I'm new to D3js, using v7, and very confused about the behavior of the d3.brush(). I have a map on which I have some stations (stored in stations.json, a geojson file), and I've added the stations and labels to a group within an svg, like so:
d3.json('json/stations.json').then(function (stations){
mapGroup.selectAll("rect")
.data(stations.features)
.enter()
.append("rect")
.attr("x", function (d) { return projection(d.geometry.coordinates)[0]; }) // stn x coordinate
.attr("y", function (d) { return projection(d.geometry.coordinates)[1]; }) // stn y coordinate
.attr("width", 2)
.attr("height", 2)
.attr("stroke", "black")
.attr("id", function (d) { return d.properties.link; }) // returns station name
.attr('fill', '#69a3b2'); //black square fill
mapGroup.selectAll("text.label") // displays station labels
.data(stations.features)
.enter()
.append("text")
.attr("class", "label")
.attr("x", function (d) { return projection(d.geometry.coordinates)[0]; }) // coordinate to display label
.attr("y", function (d) { return projection(d.geometry.coordinates)[1]; })
.attr("dx", "0.5em")
.attr("id", "station")
.attr("dy", "-0.5em")
.html(function (d) { return d.properties.link; }) //displays the label at the station location
});
This, along with other code in the script, produces a world map with squares on it and names of stations next to those squares. Now, I want to be able to zoom in and draw rectangular selection boxes to pick stations to perform more operations with. For this I'm using d3.zoom() and d3.brush() (open to other ideas). My zoom function is defined like so:
var zoom = d3.zoom()
.scaleExtent([1, Infinity])
.translateExtent([[0,0], [width, height]])
.on('zoom', function(event) {
var zoomState = event.transform;
tx = zoomState.x; // x translation position of zoomState
ty = zoomState.y; // y translation position of zoomState
s = zoomState.k; // scale factor at the current zoomState
projection.translate([tx+s*width/2-5,ty+s*height/2]) // subtracting 5 from width centers this better
.scale(s*projectionScaleFactor);
mapGroup.selectAll("path") // plot the map
.attr("d", path);
mapGroup.selectAll("rect") // plot all stations
.attr("x", function (d) { return projection(d.geometry.coordinates)[0]; })
.attr("y", function (d) { return projection(d.geometry.coordinates)[1]; });
mapGroup.selectAll("text.label") // plot all station labels
.attr("x", function (d) { return projection(d.geometry.coordinates)[0]; })
.attr("y", function (d) { return projection(d.geometry.coordinates)[1]; })
});
The projection is d3.geoEquirectangular() and my brush function doesn't have anything in it yet, I'm just trying it out:
var brush = d3.brush()
.extent([[0,0],[width,height]])
.on('brush',function(event){
});
The confusing behavior I'm seeing is that when I call zoom and brush on the svg of the map like this, all the station icons appear but the labels disappear:
svg.call(brush);
svg.call(zoom)// call the zoom behavior
.on("mousedown.zoom", null)
.on("touchstart.zoom", null)
.on("touchmove.zoom", null)
.on("touchend.zoom", null);
Whereas if I append a new group containing everything in the brush, everything appears fine (stations and labels show up):
const brushSvg = svg
.append("g")
.call(brush);
svg.call(zoom)// call the zoom behavior
.on("mousedown.zoom", null)
.on("touchstart.zoom", null)
.on("touchmove.zoom", null)
.on("touchend.zoom", null);
Could someone explain why I'm seeing this behavior?
Thanks!
from D3js v7 brush behavior - text labels disappear
No comments:
Post a Comment