首页 > 解决方案 > 带 Lat/Lng 输入的拖动点

问题描述

我一直在使用这个例子来启用点的拖动。成功的 JS在这里提琴。

我的问题是,如何将其转换为使用基于纬度/经度的坐标系的输入数据?

我可以很好地显示/投影这些点,但是当我拖动它时,它会固定在左上角。DevTools 控制台返回错误“错误:属性 cx:预期长度,“NaN”。” 同样返回属性 cy。

我认为这与拖动功能有关,但我尝试过的所有排列都失败了。

var width = Math.max(960, window.innerWidth),
    height = Math.max(500, window.innerHeight) - 90;

var tile = d3.geo.tile()
    .size([width, height]);

var projection = d3.geo.mercator()
    .scale((1 << 23) / 2 / Math.PI)
    .translate([-width / 2, -height / 2]);

var drag = d3.behavior.drag()
    .origin(function (d) { return d; })
    .on("dragstart", dragstarted)
    .on("drag", dragged)
    .on("dragend", dragended);

var container = d3.select("body").append("div")
    .attr("id", "container")
    .style("width", width + "px")
    .style("height", height + "px");

var points = container.append("svg")
    .attr("id", "points");

var nodes_data_latlng = [{ "lat1": -0.01, "lng1": 0.025 }];

drawnodeslatlng();

function drawnodeslatlng() {
    d3.select("#points").selectAll("circle")
        .data(nodes_data_latlng)
        .enter()
        .append("circle")
        .attr("cx", function (d) { return projection([d.lng1, d.lat1])[0] })
        .attr("cy", function (d) { return projection([d.lng1, d.lat1])[1] })
        .attr("r", "10")
        .call(drag)
}

function dragstarted(d) {
    d3.event.sourceEvent.stopPropagation();
    d3.select(this).classed("dragging", true);
}
function dragged(d) {
    d3.select(this)
        .attr("cx", d.lng1 = d3.event.x)
        .attr("cy", d.lat1 = d3.event.y);
} 
function dragended(d) {
    d3.select(this).classed("dragging", false);
}
<html>
<body>
    <script src="https://d3js.org/d3.v3.min.js"></script>
    <script src="https://d3js.org/d3.geo.tile.v0.min.js"></script>
</body>
</html>

标签: javascriptd3.js

解决方案


在 D3 v3 中,.origin您在此处使用的方法...

var drag = d3.behavior.drag()
    .origin(function (d) { return d; })

...需要一个具有xy属性的对象。那个非常旧和过时的版本的API说:

源访问器经常被指定为身份函数:function(d) { return d; }. 这适用于绑定到被拖动元素的基准已经是一个对象,xy属性表示其当前位置。

因此,最简单的解决方案是简单地删除它:

var width = Math.max(960, window.innerWidth),
    height = Math.max(500, window.innerHeight) - 90;

var tile = d3.geo.tile()
    .size([width, height]);

var projection = d3.geo.mercator()
    .scale((1 << 23) / 2 / Math.PI)
    .translate([-width / 2, -height / 2]);

var drag = d3.behavior.drag()
    .on("dragstart", dragstarted)
    .on("drag", dragged)
    .on("dragend", dragended);

var container = d3.select("body").append("div")
    .attr("id", "container")
    .style("width", width + "px")
    .style("height", height + "px");

var points = container.append("svg")
    .attr("id", "points");

var nodes_data_latlng = [{ "lat1": -0.01, "lng1": 0.025 }];

drawnodeslatlng();

function drawnodeslatlng() {
    d3.select("#points").selectAll("circle")
        .data(nodes_data_latlng)
        .enter()
        .append("circle")
        .attr("cx", function (d) { return projection([d.lng1, d.lat1])[0] })
        .attr("cy", function (d) { return projection([d.lng1, d.lat1])[1] })
        .attr("r", "10")
        .call(drag)
}

function dragstarted(d) {
    d3.event.sourceEvent.stopPropagation();
    d3.select(this).classed("dragging", true);
}
function dragged(d) {
    d3.select(this)
        .attr("cx", d.lng1 = d3.event.x)
        .attr("cy", d.lat1 = d3.event.y);
} 
function dragended(d) {
    d3.select(this).classed("dragging", false);
}
<html>
<body>
    <script src="https://d3js.org/d3.v3.min.js"></script>
    <script src="https://d3js.org/d3.geo.tile.v0.min.js"></script>
</body>
</html>


推荐阅读