worldMap = {
var waterCol = '#deebf7'
var noDataCol = '#9DC2B3'
var unselectedCol = '#4E997B'
var selectedCol = "#3C755E"
var maxCol = 'rgb(218,218,235)'
var minCol = 'rgb(106,81,163)'
var myColor = d3.scaleLinear()
.domain([0,Math.sqrt(max_distance)])
.range([minCol,maxCol])
var width = 900
var height = 600
const svg = d3.create('svg')
.attr('width', width)
.attr('height',height)
const g = svg.append('g')
g.append('rect')
.attr('class', 'background')
.attr('x', 0)
.attr('y', 0)
.attr('width', width)
.attr('height', height)
.attr('fill', waterCol)
.on("click", clicked)
const projection = geo.geoMercator()
.scale(140)
.translate([width/2, height/1.4])
// generate an SVG path data string
const path = geo.geoPath(projection)
// initialize tooltip
const tooltip = d3.select("body").append("div")
.attr("class", "tooltip")
.style("position", "absolute")
.style("visibility", "hidden")
// get the countries and draw them
const countriesTemp = topojson.feature(topoData, topoData.objects.countries)
// exclude the Antarctica
const countriesSelected = countriesTemp.features
.filter((feature) => feature.properties.name != 'Antarctica')
// draw the countries
g.selectAll('path')
.data(countriesSelected)
.enter().append('path')
.attr('class', function(d) {return d.properties.name.replace(/ +/g, "")})
.attr('d', path)
.attr("fill", function(d) {
if (selection_mode=="Compare" && selectedCountry) {
return colorCountriesByDistance(d.properties.name.replace(/ +/g, ""))
} else {
if (selectedCountry) {
return colorCountriesByDistance(d.properties.name.replace(/ +/g, ""))
} else {
if (countriesMap2.includes(d.properties.name.replace(/ +/g, ""))) {return unselectedCol}
else {return noDataCol}
}
}
})
.attr("stroke", function(d) {
if (selectedCountries.has(d.properties.name.replace(/ +/g, ""))){return '#4a1486'}
else {
if (countriesMap2.includes(d.properties.name.replace(/ +/g, ""))) {return selectedCol}
else {return unselectedCol}
}
})
.attr("stroke-width", (d) => selectedCountries.has(d.properties.name.replace(/ +/g, "")) ? 2.5 : 0.7)
// mouse events
.on("click", clicked)
.on("mouseover", function(event, d) {
let text = d.properties.name
showToolTip(text, [event.pageX, event.pageY]).on("mousemove", function(event) {
d3.select(".tooltip")
.style("top", event.pageY - 10 + "px")
.style("left", event.pageX + 10 + "px")
})
})
.on("mousemove", function(event) {
d3.select(".tooltip")
.style("top", event.pageY - 10 + "px")
.style("left", event.pageX + 10 + "px")
})
.on("mouseout", function() {
d3.select(".tooltip").style("visibility", "hidden")
})
// mouse event handling
function clicked(event, d) {
if (event.target.className.baseVal == "background") {
// unselect everything when user clicks on background
if (selection_mode == 'Compare') {
// selection mode is on compare
// -> set selectedCountry to undefined
mutable selectedCountry = ''
} else {
// selection mode is on selection
// -> clear the selection
mutable selectedCountries = new Set()
}
} else if (countriesMap2.includes(d.properties.name.replace(/ +/g, ""))) {
// click on country with data
var countryName = d.properties.name.replace(/ +/g, "")
if (selection_mode == 'Compare') {
// selection mode is on compare
// -> set selected Country to the country name
mutable selectedCountry = d.properties.name.replace(/ +/g, "")
} else {
// selection mode is on selection
if (!selectedCountries.has(countryName)) {
// selected country is not in the selection -> select
let tempSelectedCountries = structuredClone(selectedCountries)
tempSelectedCountries.add(countryName)
mutable selectedCountries = tempSelectedCountries
} else {
// selected country is not in the selection -> unselect
let tempSelectedCountries = structuredClone(selectedCountries)
tempSelectedCountries.delete(countryName)
mutable selectedCountries = tempSelectedCountries
}
}
}
if (selection_mode == 'Compare') {
// update coloring
if (selectedCountry == '') {
// no country is selected -> color all green
for (let i = 0; i < countryCodes.length; i++) {
let unselCountry = countryCodes[i].mapName.replace(/ +/g, "")
d3.select("." + unselCountry).attr("fill", unselectedCol)
}
} else {
// one country is selected -> color according to similarity
colorCountriesByDistance(selectedCountry)
}
} else {
// update stroke for all countries
for (let i = 0; i < countryCodes.length; i++) {
let unselCountry = countryCodes[i].mapName.replace(/ +/g, "")
d3.select("." + unselCountry).attr("stroke-width", 0.7).attr("stroke", selectedCol)
}
// and selected countries
selectedCountries.forEach(function (selCountry) {
var path = d3.select("." + selCountry)._groups[0][0]
d3.select(path.parentNode.appendChild(path))
.attr("stroke-width", 2.5).attr("stroke", "#4a1486")})
}
}
// color all countries by the relationship to one selected country
function colorCountriesByDistance(countryName) {
if (!countryCodes.map((x) => x.noWhitespace).includes(countryName)) return noDataCol
var firstID = parseInt(countryCodes.filter((country) => country.noWhitespace == selectedCountry)[0].index)
let secondID = parseInt(countryCodes.filter((country) => country.noWhitespace == countryName)[0].index)
let secondCountry = countryCodes.filter((country) => country.noWhitespace == countryName)[0].noWhitespace
let distance = distance_mat_clone[firstID][secondID]
let distanceTrans = Math.sqrt(distance)
return myColor(distanceTrans)
}
// zoom
svg.call(d3.zoom()
.extent([[0, 0], [width, height]])
.translateExtent([[0, 0], [width, height]])
.scaleExtent([1, 8])
.on("zoom", zoomed))
function zoomed({transform}) {
g.attr("transform", transform);
}
// legend
svg.append('g')
.attr("transform", "translate(565,550)")
.append(() => legend)
return svg.node();
}