Search code examples
d3.jssvglimitdragmercator

How to limit the d3.js drag behavior on a mercator map


I have implemented a map in a svg-Element with the mercator-function of d3.js. The Map represented only a specific city - everything outside the city-map is not relevant for my project.

Now I want to implement some function like zoom() and drag() on this map.

But I can not find any solution, to handle the drag()-function with my mercator-map - I can not limit the area of the transformation. (the user should not be able to drag the map outside the map of the city)

For normal svg-elements this works:

var drag = d3.behavior.drag()
                 .on("drag", dragmove);

function dragmove(d) {
    var x = Math.max(0, Math.min('width-of-svg-element', d3.event.x));
    var y = Math.max(0, Math.min('height-of-svg-element', d3.event.y));
    d3.select(this)
    .attr("transform", "translate(" + x + "," + y + ")");
    }

But it doesn't work for my mercator-map.

please help me :(

Thanks in advance!

Here is a small example: https://jsfiddle.net/c55w7u9e/

My intention is, that there should be no possibility for the user to drag the red circle (in this example, but in my project the map) outside the svg element...


Solution

  • Updated fiddle : https://jsfiddle.net/thatoneguy/c55w7u9e/4/

    You werent taking your radius into account. It was working, but you can't see it. Update drag to this :

    function dragmove(d) {
        var x = Math.max(0, Math.min(width - radius, d3.event.x));
        var y = Math.max(0, Math.min(height - radius, d3.event.y));
        d3.select(this)
        .attr("transform", "translate(" + x + "," + y + ")");
        }
    

    Help from this question : Explaining Mike Bostock's d3.js dragmove function

    And this example : http://bl.ocks.org/mbostock/1557377 //think its offline ...

    I would use this function to limit, it works better :

    function dragmove(d) {
      d3.select(this)
          .attr("cx", d.x = Math.max(radius, Math.min(width - radius, d3.event.x)))
          .attr("cy", d.y = Math.max(radius, Math.min(height - radius, d3.event.y)));
            }
    

    Updated fiddle from examples : https://jsfiddle.net/thatoneguy/c55w7u9e/5/