Add zoom to d3js map using d3fc-label-layout

Viewed 151

I am trying to add zoom to UK map with d3fc-label-layout. But when I zoom in the labels are shifted. As I understand I have to recalculate the positions with d3fc-label-layout every time the zoom is called, but not sure how to do this Here is a fiddle https://jsfiddle.net/benderlio/cyvqase5/11/

 var zoom = d3.zoom()
      .scaleExtent([1, 28])
      .on('zoom', function () {

        svg.selectAll('path')
          .attr('transform', d3.event.transform);
        svg.selectAll("circle")
          .attr('transform', d3.event.transform);

        svg.selectAll("text")
          .attr('transform', d3.event.transform);

      });

    svg.call(zoom);
1 Answers

I was able to sync the zoom of the points and text by applying a transform on the labels themselves instead of the circles and text items.

I recalculate the position from the projection and adjust according to the zoom transformation:

 const t=d3.event.transform;

 svg.selectAll('path')
   .attr('transform', t);

 svg.selectAll(".label")
   .attr('transform',  d => {
      const p=projection(d.geometry.coordinates)
      return `translate(${ p[0] * t.k + t.x }, ${ p[1] * t.k + t.y }) scale(${ t.k })`
   })

you can see it working here: https://jsfiddle.net/p94xhorv/8/

Edit: adding code to handle layout while zooming

I changed the code to recalculate the layout as the user zooms to keep cities from becoming "hidden" as per the OP's comment to my original answer.

    .on('zoom', function () {
      const t=d3.event.transform;
      svg.selectAll('path')
        .attr('transform', t);

      labels.position(function (d) { 
        const p=projection(d.geometry.coordinates)
        return [p[0]*t.k+t.x, p[1]*t.k+t.y]
      });

      svg.datum(places.features)
        .call(labels);
    });

and here's the updated jsfiddle https://jsfiddle.net/rpv9743n/

Related