Reputation: 1055
I'm trying to add points to a map using the d3.js
library.
(I've tried to adapt a script from this gist).
The problem is that the map is being rendered on top of the dots.
I've tried to use another SO answer which suggested something like this:
svg.append("g").attr("id", "map").attr("id", "points")
...but I have been unable to make it work. I'm a long time python user...JavaScript is new for me (so please excuse the naivety).
Am using the following CSS:
<style>
body {
background-color: white;
}
svg {
border: 1px solid black;
background-color: #a4bac7;
}
.land {
fill: #d7c7ad;
stroke: #8999ab;
}
.boundary {
fill: none;
stroke: #a5967f;
}
</style>
Body:
<script type="text/javascript" src="d3/d3.js"></script>
<script src="http://d3js.org/topojson.v0.min.js"></script>
<script>
var width = 960;
var height = 480;
var dataURL = "https://gist.githubusercontent.com/abenrob/787723ca91772591b47e/raw/8a7f176072d508218e120773943b595c998991be/world-50m.json";
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
In response to this SO answer answer, added this:
svg.append("g")
.attr("id", "map")
.attr("id", "points");
var projection = d3.geoEquirectangular()
.scale(153)
.translate([width/2,height/2])
var path = d3.geoPath()
.projection(projection);
d3.json(dataURL, function(error, world) {
svg.append("g")
.select("#map").selectAll(".map")
.attr("class", "land")
.selectAll("path")
.data([topojson.object(world, world.objects.land)])
.enter().append("path")
.attr("d", path);
svg.append("g")
.select("#map").selectAll(".map")
.attr("class", "boundary")
.selectAll("boundary")
.data([topojson.object(world, world.objects.countries)])
.enter().append("path")
.attr("d", path);
}
);
var lngLatExtract = function(d, i){
return projection([d['lng'], d['lat']])[i];
};
d3.csv("cities.csv", function(data){
svg.append("g")
.select("#points").selectAll(".points")
.data(data)
.enter()
.append('circle')
.attr("cx", function(d){
return lngLatExtract(d, 0);
})
.attr('cy', function(d){
return lngLatExtract(d, 1);
})
.style("fill", "blue")
.style("opacity", 0.75)
.attr("r", function(d){
return Math.sqrt(parseInt(d['population']) * 0.000001)
});
}
);
</script>
cities.csv
looks like this:
rank,place,population,lat,lng
1,New York city,8175133,40.71455,-74.007124
2,Los Angeles city,3792621,34.05349,-118.245323
Upvotes: 1
Views: 942
Reputation: 108567
Both d3.json
and d3.csv
are async functions. The order in which their callbacks fire is not a given and in fact since your csv file is smaller, it's callback is probably firing first. That means that your svg.append("g")
in your csv callback is happening before the svg.append("g")
in the json callback. You can confirm this by inspecting the DOM and to see which was appended first.
That said, I would switch to using d3.queue. This allows you to fire off both the d3.json
and d3.csv
async requests and then fire a single callback with both are complete.
Another less streamlined option is to place your d3.csv
code in the callback of the d3.json
call.
Upvotes: 2