D3.js:限制可以在地图/投影上拖动对象的区域?

时间:2017-04-28 11:43:16

标签: javascript d3.js

有没有办法限制可以在D3.js地图上拖动对象的区域?在this example中,用户可以将对象拖动到投影边界之外,这是我想要避免的。

有什么想法吗?谢谢!

var drag = d3.behavior.drag()
    .on("drag", function(d) {
    var x = d3.select(this).attr("x");
    var y = d3.select(this).attr("y");
    var dx = d3.event.x - x;
    var dy = d3.event.y - y;
    d3.select(this).attr("transform", "translate(" + dx + "," + dy + ")");
    });

function putCircle(x, y) {
    d3.select('svg')
        .append('path')
        .attr("class", "projected")
        .attr("x", x).attr("y", y)
        .datum(d3.geo.circle().origin(projection.invert([x, y])).angle(5))
        .attr('d', d3.geo.path().projection(projection))
        .call(drag);
}

1 个答案:

答案 0 :(得分:0)

可能有更简单的方法,但我已经使用此方法根据投影重新调整栅格。

首先,对于诸如正交投影之类的投影,projection.invert将返回任何svg点的有效地理点,无论它是否在明显的投影区域内。

其次,对于像Aitoff这样的投影,projection.invert将返回未定义的svg点,这些点位于投影区域之外。

这些类别中有许多预测。

因此,您需要进行两次检查以确定点是在投影区域内部还是外部。这两项检查都依赖于projection.invert

第一个很简单,除非定义projection.invert([d3.event.x,d3.event.y]),否则不要拖动点。

第二个涉及正投影等预测。由于projection.invert总是为这些投影返回有效的地理点,我们可以应用前向投影来查看返回的svg点是否等于我们开始的svg点。基本上我们想在以下时间拖动点:projection(projection.invert([x,y]) == [x,y]。由于projection.invert对于这些预测并非一对一,因此并非总是如此。

为了避免潜在的舍入误差,我扩展了上面的比较(不幸的是,需要打破坐标的x和y分量):

if ( 
   Math.abs(projection(projection.invert([d3.event.x,d3.event.y]))[0] - d3.event.x) < 0.5 
   && 
   Math.abs(projection(projection.invert([d3.event.x,d3.event.y]))[1] - d3.event.y) < 0.5) {     
      d3.select(this).attr("transform", "translate(" + dx + "," + dy + ")");
}

然后我们一起进行两项检查,从要求不高的第一次检查开始,然后仅在第一次检查时进行第二次检查。

更新后的fiddle is here