【问题标题】:How to enable dragging for D3 elements overlaid on a leaflet map如何为覆盖在传单地图上的 D3 元素启用拖动
【发布时间】:2016-01-18 22:01:07
【问题描述】:

我已经关注 Mike Bostock's tutorial 在 Leaflet 地图上使用 D3 渲染 svg 元素,但除了他示例中的功能之外,我希望用户能够在地图上重新定位 D3 渲染的元素通过拖动它们。也就是说,我希望用户能够通过拖动这些元素在传单覆盖窗格中的 D3 渲染 SVG 元素中重新定位对象,并在用户拖动或缩放传单地图时保留更新的地理位置。

通过在 D3 拖动事件中进行一些非常 hacky 的 html 编辑,我设法做到了这一点(see jsFiddle - 拖动蓝色圆圈以确认功能)但我希望找到更好的方法。有什么建议?这是我目前所拥有的:

var svg, g, map, collection, transform, path, json, d_string;
json = get_json();
setup_map();

function setup_map(){
    map = L.map('map').fitBounds([[-3.82,-73.24],[-3.69,-73.35]]);
    L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',{
        maxZoom: 18,
        attribution: 'OpenStreetMap, D3'
    }).addTo(map);  
    map.on("viewreset", reset);
    setup_d3();
}

function setup_d3(){
    svg = d3.select(map.getPanes().overlayPane).append("svg");
    g = svg.append("g").attr("class", "leaflet-zoom-hide");

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

    transform = d3.geo.transform({point: projectPoint});
    path = d3.geo.path().projection(transform);

    g.selectAll("path")
    .data(json.features)
    .enter().append("path");

    g.selectAll("path")
    .attr('fill','blue')
    .attr("r", 10)
    .style("cursor", "pointer")
    .call(drag);
    reset();
}

function reset() {
    var buffer_space = 200; //so point markers are fully drawn, and to give you space to move markers around
    bounds = path.bounds(json);
    var topLeft = bounds[0], bottomRight = bounds[1];
    topLeft[0] -= buffer_space;
    topLeft[1] -= buffer_space;
    bottomRight[0] += buffer_space;
    bottomRight[1] += buffer_space;

    svg.attr("width", bottomRight[0] - topLeft[0])
      .attr("height", bottomRight[1] - topLeft[1])
      .style("left", topLeft[0] + "px")
      .style("top", topLeft[1] + "px");

    g.attr("transform", "translate(" + -topLeft[0] + "," + -topLeft[1] + ")");
    g.selectAll("path").attr("d", path);
}

function projectPoint(x, y) {
    var point = map.latLngToLayerPoint(new L.LatLng(y, x));
    this.stream.point(point.x, point.y);
}

function dragstarted(d) {
    d3.event.sourceEvent.stopPropagation();
    d3.select(this).classed("dragging", true);
    d_string = d3.select(this).attr("d");
    d_string = d_string.substring(d_string.indexOf("m"));
}

function dragged(d) {
    var offset = get_leaflet_offset();
    var size = d3.select(this).attr("r")/2;
    var pt = [d3.event.sourceEvent.clientX - size - offset[0], d3.event.sourceEvent.clientY - size - offset[1]];
    var hackpath = "M" + pt[0] + "," + pt[1] + d_string;
    d3.select(this).attr("d", hackpath);
}

function dragended(d) {
    var offset = get_leaflet_offset();
    var size = d3.select(this).attr("r")/2;
    var pt = layer_to_LL(d3.event.sourceEvent.clientX - size - offset[0], d3.event.sourceEvent.clientY - size - offset[1]);
    d.geometry.coordinates = [pt.lng, pt.lat];
    d3.select(this).classed("dragging", false);
    reset();
}

function get_leaflet_offset(){
    var trfm = $(".leaflet-map-pane").css('transform');
    trfm = trfm.split(", ");
    return [parseInt(trfm[4]), parseInt(trfm[5])];
}

function layer_to_LL(x,y){return map.layerPointToLatLng(new L.Point(x,y));}

function projectPoint(x, y) {
  var point = map.latLngToLayerPoint(new L.LatLng(y, x));
  this.stream.point(point.x, point.y);
}

function projectSinglePoint(x, y) {
  var point = map.latLngToLayerPoint(new L.LatLng(y, x));
  console.log(point);
  return point;
}

function get_json(){
    return {
    "type": "FeatureCollection",
    "crs": {
        "type": "name",
        "properties": {"name": "urn:ogc:def:crs:EPSG::4269"}
    },
    "features": [{
        "type": "Feature",
        "properties": {"id": "pt0"},
        "geometry": {
            "type": "Point",
            "coordinates": [-73.25, -3.72]
        }
    }, {
        "type": "Feature",
        "properties": {"id": "pt1"},
        "geometry": {
            "type": "Point",
            "coordinates": [-73.37, -3.82]
        }
    }, {
        "type": "Feature",
        "properties": {"id": "pt2"},
        "geometry": {
            "type": "Point",
            "coordinates": [-73.32, -3.67]
        }
    }]
    }
}

谢谢, 克里斯

【问题讨论】:

    标签: d3.js leaflet


    【解决方案1】:

    在我看来,我会使用默认传单选项来制作 markers 并将其设置为 draggable

    类似这样的:

      json.features.forEach(function(d) {
        var marker = L.marker(new L.LatLng(d.geometry.coordinates[1], d.geometry.coordinates[0]), {
            draggable: true
        });
        marker.addTo(map);
      })
    

    这将减轻您在 D3 上执行拖动逻辑的工作,您可以看到减少了多少代码 :)

    工作代码here

    标记文档here

    希望这会有所帮助!

    【讨论】:

    • 谢谢西里尔。这没有回答所提出的问题,但它是一个非常有用的替代方案!
    猜你喜欢
    • 1970-01-01
    • 2013-11-24
    • 2020-09-15
    • 2011-06-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-27
    • 1970-01-01
    相关资源
    最近更新 更多