Search code examples
htmlsvgd3.jsmercator

D3 Map zoom event to keep LineString width constant


Building on top of http://bl.ocks.org/d3noob/5193723, I tried to add Line String on the map.

I made some modifications in the code as :

var g1 = svg.append("g");

// load and display the World
d3.json("js/data/world-110m2.json", function(error, topology) {

    var data = {type: "LineString", coordinates: [[102.0, 0.0], [3.0, 50.0]], count: 1};

    g1.selectAll(".route")
            .data([data])
            .enter()
            .append("path")
            .attr("class", "route")
            .attr("d", path);

    g.selectAll("path")
            .data(topojson.object(topology, topology.objects.countries)
                    .geometries)
            .enter()
            .append("path")
            .attr("d", path)
});

// zoom and pan
var zoom = d3.behavior.zoom()
        .on("zoom",function() {
            g.attr("transform","translate("+ d3.event.translate.join(",")+")scale("+d3.event.scale+")");
            g.selectAll("circle").attr("d", path.projection(projection));
            g.selectAll("path").attr("d", path.projection(projection));

            g1.selectAll(".route")
                    .attr("transform","translate("+ d3.event.translate.join(",")+")scale("+d3.event.scale+")")
                    .attr("d", path.projection(projection));

        });

Output

On zoom-in, the line's thickness grows accordingly. Zoomed-in

Since my application has a lot of lines, I want the line width to remain constant. Any ideas? If I use d3's simple 'line' object and draw on svg, I am able to control the behavior of of line thickness on zoom in/out. Projecting the line using mercator transformation creates a path object, which is quite tricky to control and I am not able to handle it. One way could be to re-render all the line paths on zoom actions, but not able to figure out how to do it efficiently.


Solution

  • You can put vector-effect="non-scaling-stroke" on the line but beware, it won't work on IE.