How to implement zoom to specific country and zoom in and out when using mouse scroll wheel together in datamap?

191 Views Asked by At

I implemented the zoom when mouse scroll using datamaps inside done function as follows, successfully:

 done: function (datamap) {
        /* zoom on mouse scroll */
        datamap.svg.call(d3.behavior.zoom().on("zoom", redraw));
        function redraw() {
          datamap.svg
            .selectAll("g")
            .attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
        }

And also implemented the zoom to specific country successfully as well:

const canvas = document.getElementById("choropleth_map");
    const { width, height } = canvas.getBoundingClientRect();
    const canvasFactor = width / height;
    selectedCountry = isoCodeConverter[Country[0].code];
    const countryFeature = map.current.svg.selectAll(`.datamaps-subunit.${selectedCountry}`)["0"]["0"].__data__;
    if (countryFeature !== undefined) {
      const bounds = path.bounds(countryFeature); // get bounds of selected country
      bounds.s = bounds[0][1];
      bounds.n = bounds[1][1];
      bounds.w = bounds[0][0];
      bounds.e = bounds[1][0];
      bounds.height = Math.abs(bounds.n - bounds.s);
      bounds.width = Math.abs(bounds.e - bounds.w);
      newScale = 0.95 / Math.max(bounds.width / width, bounds.height / height);
      const factor = bounds.width / bounds.height;
      /* for maintaining width and height relative to the canvas size to keep the country in the middle */
      if (factor < 1.8) {
        bounds.w = bounds.w - Math.abs(bounds.height * canvasFactor - bounds.width) / 2;
      }
      if (factor > 1.8) {
        bounds.s = bounds.s - Math.abs(bounds.width / canvasFactor - bounds.height) / 2;
      }
      /* update the current map*/
      map.current.svg
        .selectAll("g")
        .transition()
        .duration(750)
        .attr("transform", `scale(${newScale})translate(${-bounds.w},${-bounds.s})`);
    }

But there is a problem when i click on specific country(suppose the map gets zoomed to a zoom level about 6) and on using mouse scroll at that level, the map zooms out to the original scale i.e. 1 and not from the current scale i.e. 6. My approach to the problem is to save the current zoom and transform when the specific country is clicked and assign it to d3.event.scale if it's possible. Is there a better way? How do i get the current zoom level of the map when a specific country is clicked and how do i assign it to d3.event? when console logging d3.event inside the specific country function, it gives me null. I am new to datamaps as well so, i dont have a better understanding to solve it myself.

1

There are 1 best solutions below

0
AudioBubble On

I made it working though with guidance by Andrew Reid.Here is the code:

const canvas = document.getElementById("choropleth_map");
    const { width, height } = canvas.getBoundingClientRect();
    const canvasFactor = width / height;
    selectedCountry = isoCodeConverter[Country[0].code];
    const countryFeature = map.current.svg.selectAll(`.datamaps-subunit.${selectedCountry}`)["0"]["0"].__data__;
    if (countryFeature !== undefined) {
      const bounds = path.bounds(countryFeature); // get bounds of selected country
      bounds.s = bounds[0][1];
      bounds.n = bounds[1][1];
      bounds.w = bounds[0][0];
      bounds.e = bounds[1][0];
      bounds.height = Math.abs(bounds.n - bounds.s);
      bounds.width = Math.abs(bounds.e - bounds.w);
      newScale = 0.95 / Math.max(bounds.width / width, bounds.height / height);
      const x = (bounds.w + bounds.e) / 2;
      const y = (bounds.s + bounds.n) / 2;

      /* specify the current zoom and translation vector */
      zoom.scale(newScale);
      zoom.translate([width / 2 - newScale * x, height / 2 - newScale * y]);

      /* dispatches a zoom gesture to registered listeners */
      zoom.event(map.current.svg.selectAll("g").transition().duration(2000));
      map.current.svg.selectAll("g").call(zoom);
    }