Reputation: 33
I have D3 code to make a U.S. map based off arcs in a JSON file. The code I am using is based off this example (http://bl.ocks.org/mbostock/4108203) where this is the json file (http://bl.ocks.org/mbostock/raw/4090846/us.json)
<!DOCTYPE html>
<meta charset="utf-8">
<style>
path {
fill: none;
stroke: #000;
stroke-width: .5px;
}
.land-boundary {
stroke-width: 1px;
}
.county-boundary {
stroke: #aaa;
}
</style>
<body>
<script src="//d3js.org/d3.v3.min.js"></script>
<script src="//d3js.org/topojson.v1.min.js"></script>
<script>
var width = 960,
height = 500;
var path = d3.geo.path();
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
d3.json("js/us.json", function(error, topology) {
if (error) throw error;
svg.append("path")
.datum(topojson.feature(topology, topology.objects.land))
.attr("d", path)
.attr("class", "land-boundary");
svg.append("path")
.datum(topojson.mesh(topology, topology.objects.states, function(a, b) { return a !== b; }))
.attr("d", path)
.attr("class", "state-boundary");
});
</script>
How would I click on the map and return the ID of the state that was clicked on?
The first console.log right now gives me the pixel coordinates of where I'm clicking, the second gives back an svg object and select gives back a parent node..?
d3.select("svg").on("mousedown.log", function() {
console.log(d3.mouse(this));
console.log(this);
console.log(d3.select("id")[0]);
});
The json looks like it has an object "states" with a dictionary including the arcs to make the map and the id of the state which corresponds to a state in this list (https://gist.github.com/mbostock/4090846#file-us-state-names-tsv). I just can't figure out the right function to use to isolate the ID corresponding to the object.
Upvotes: 3
Views: 3018
Reputation: 28638
First off, you're creating a mesh of your features, which will turn all of the features into a multilinestring which doesn't hold any data. If you want to have events on the individual states and retain the data, you'll need to use .feature
instead of .mesh
topojson.mesh:
Returns the GeoJSON MultiLineString geometry object representing the mesh for the specified object in the given topology. This is useful for rendering strokes in complicated objects efficiently, as edges that are shared by multiple features are only stroked once.
https://github.com/mbostock/topojson/wiki/API-Reference#mesh
topojson.feature:
Returns the GeoJSON Feature or FeatureCollection for the specified object in the given topology. If the specified object is a GeometryCollection, a FeatureCollection is returned, and each geometry in the collection is mapped to a Feature. Otherwise, a Feature is returned.
https://github.com/mbostock/topojson/wiki/API-Reference#feature
Next you're binding your eventlistener to the SVG. If you bind it to the actual paths you're creating you have got direct access to the data object like Lars mentioned in his comment on your question:
svg.append("g")
.selectAll("path")
.data(topojson.feature(us, us.objects.states).features)
.enter().append("path")
.attr("class", "state-boundary")
.attr("d", path)
.style("fill", "red")
.on('mousedown.log', function (d) {
console.log(d.id);
});
If you want to bind to the SVG and access the data you can do this but i wouldn't recommend it, but just to show it is possible:
d3.select("svg").on("mousedown.log", function() {
console.log(d3.event.srcElement.__data__.id);
});
Upvotes: 1