I'm using topojson to draw a world map with D3js. I believe this is working fine. However, when I try and project latitude/longitude points onto the map, the projection function is returning "NaN" for points with negative values, and the projection for points that are working is way off the country's position on the world map.
This is the data I'm reading in: assets/data/gcf.csv
Coords,Country,Frequency
"[38.9597594, 34.9249653]",Turkey,1
"[61.0666922, -107.9917071]",Canada,3
"[52.5001698, 5.7480821]",Netherlands,1
"[42.6384261, 12.674297]",Italy,1
"[39.7837304, -100.4458825]",United States,69
"[59.6749712, 14.5208584]",Sweden,1
"[35.000074, 104.999927]",China,5
"[64.6863136, 97.7453061]",Russian Federation,2
"[36.5748441, 139.2394179]",Japan,1
Index.html
<div id="worldmap"></div>
<script src="../assets/js/graphs/map.js"></script>
assets/js/graphs/map.js
var width = 960;
var height = 500;
// set projection
var projection = d3.geo.mercator();
// create path variable
var path = d3.geo.path()
.projection(projection);
// Define the div for the tooltip
var div = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
d3.json("https://unpkg.com/world-atlas@1/world/110m.json", function(error1, topo) {
if(error1) console.log("Error: topo json not loaded.");
d3.csv("../assets/data/gcf.csv", function(error2, data) {
if(error2) console.log("Error: Coord/frequency data not loaded.");
countries = topojson.feature(topo, topo.objects.countries).features;
projection
.scale(width / 2 / Math.PI)
.translate([(width / 2)-30, (height / 2)+50]);
data.forEach(function(d) {
// + symbol convert from string representation of a number to an actual number
d.Frequency = +d.Frequency;
d.Coords = d.Coords.replace(/[\[\]"]+/g, '');
d.Coords = d.Coords.split(',');
d.Coords = d.Coords.map(x => parseFloat(x));
d.Country = d.Country;
console.log("Country:", d.Country, ". Projection: ", projection(d.Coords)[0], projection(d.Coords)[1]);
});
// create svg variable
var svg = d3.select("#worldmap").append("svg")
.attr("width", width)
.attr("height", height);
svg.append("rect")
.attr("width", "100%")
.attr("height","100%")
.attr("fill","#A2E8E8");
// add countries from topojson
svg.selectAll("path")
.data(countries).enter()
.append("path")
.attr("class", "feature")
.style("fill", "#71945A")
.attr("d", path);
// put boarder around countries
svg.append("path")
.datum(topojson.mesh(topo, topo.objects.countries, function(a, b) { return a !== b; }))
.attr("class", "mesh")
.attr("d", path);
aa = [38.9597594, 34.9249653];
// add circles to svg
svg.selectAll("circle")
.data(data).enter()
.append("circle")
.attr("r", function(d) {
return d.Frequency === 1 ? d.Frequency* 10 : d.Frequency / 2
})
.attr("transform", function(d) {
return "translate(" + projection([
(d.Coords[0]),
(d.Coords[1])
]) + ")";
})
.attr("fill", "red")
.on("mouseover", function(d) {
div.transition()
.duration(200)
.style("opacity", .9);
div .html(d.Country)
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px");
})
.on("mouseout", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);
});
});
});
Styles for world map:
.feature {
fill: none;
stroke: grey;
stroke-width: 1px;
stroke-linejoin: round;
}
.mesh {
fill: none;
stroke: black;
stroke-width: 2px;
stroke-linejoin: round;
}