AngryOtter
AngryOtter

Reputation: 159

How to make map draggable in D3v6

I have a Drilldown world map(continent map + country map) where the second map(the country map) is zoomed-in onload by using fitExtent function. Since it is zoomed-in, I wanted to implement a draggable feature where I can drag the map and see other part of the map.

//My svg tag
<svg id="mapSVG" width="560"; height="350"></svg>

let zoomControl = function (event) {
    svg.selectAll("path")
        .attr("transform", event.transform);
}

function loadCountryMap(path, mapData) {
    d3.json(path).then(function (json) {
        var projection = d3.geoMercator();
        var features = json.features;

        //The reason why we have to do this is because d3.js has winding problem
        //We need to rewind for the map to display correctly
        var fixed = features.map(function (feature) {
            return turf.rewind(feature, { reverse: true });
        })
        //Projections
        var geoPath = d3.geoPath().projection(projection);

        //Zoom in
        projection.fitExtent([[mapData.XOffSet, mapData.YOffSet], [width*2, height*2]], { "type": "FeatureCollection", "features": fixed })

        //Draggable
        svg.selectAll("path")
            .data(fixed)
            .enter()
            .append("path")
            .attr("d", geoPath)
            .attr("id", function (d) { return d.properties.FIPS_10_; })
            .style("fill", "steelblue")
            .style("stroke", "transparent")
            .on("mouseover", mouseOver)
            .on("mouseleave", mouseLeave)
            .on("click", mouthClick)
            .call(d3.zoom()
                .on("zoom", zoomControl)
                .scaleExtent([1, 1])
            )
    })
}

//How I select the svg
var svg = d3.select("svg")
    .style("background-color", "white")
    .style("border", "solid 1px black");
var width = +svg.attr("width");
var height = +svg.attr("height");

There are two problems with this:

1: By selecting the "svg" tag, this will drag the entire SVG HTML element, instead of the map content of SVG. I also changed it to "path" and "d", it didn't work either.

2: When the drag event first occurred, the dragged elements are being placed at the bottom right corner of the mouse cursor and follow the mouse cursor after that.

I want the zoomed-in map to be draggable to so I can see other part of the map.

The example desired behavior bin. This is the code from Andrew Reid's answer to a question. When the map is zoomed in, it became draggable. I don't see the drag behavior been defined anywhere in the code. I am assuming it is achieved by using d3.zoom(). However, since my map are zoomed-in by default(onload), and I have a separate mouse click event, I don't think I can use the similar approach.

Upvotes: 1

Views: 618

Answers (1)

AngryOtter
AngryOtter

Reputation: 159

var svg = d3.select("#mapDiv")
    .append("svg")
    .attr("width", width)
    .attr("height", height)
    .style("background-color", "white")
    .style("border", "solid 1px black")
    .call(d3.zoom()
        .on("zoom", function (event) {
            svg.attr("transform", event.transform)
        })
        .scaleExtent([1, 1])
    )
    .append("g");

I have achieved the functionality by grouping my path with .append("g"). Instead of assigning the zoom functionality path by path, I simply assigned it to the entire SVG and now the map is working fine.

Upvotes: 1

Related Questions