首页 > 解决方案 > d3.js 过渡的问题 - 使用 GeoJson 的多边形变形不正确

问题描述

我正在尝试使用 D3 叠加创建传单地图。在叠加层中,我想展示一些能够在它们之间动态切换的形状——从一个平滑转换到另一个(变形)。我设法设置了一些基本的工作代码,它们或多或少可以满足我的需要,但有一个问题。

当我按下按钮改变形状时,最终的形状“展开”而不是平滑过渡,而不是前一个形状。我究竟做错了什么?我在网络上的某些地方看到 .transition() 应该完成这项工作,但在我的情况下不是。我需要使用某种插值吗?或者也许准备数据?我会很感激任何帮助!

这是我的代码,我还包括一个演示链接:(有一个地图和两个按钮来改变形状)

https://jsfiddle.net/xiaoss/dLk65pyu/

JS:

var figure1 = {
  "features": [{
    "type": "Feature",
    "properties": {},
    "geometry": {
      "coordinates": [
        [
          [
            -72.256697,
            1.150426
          ],
          [
            -74.579093,
            -7.698964
          ],
          [
            -67.075969,
            -21.93404
          ],
          [
            -68.088295,
            -34.291664
          ],
          [
            -55.285345,
            -31.492019
          ],
          [
            -44.923888,
            -19.0337
          ],
          [
            -46.591249,
            -5.569695
          ],
          [
            -59.394199,
            1.983787
          ],
          [
            -65.051316,
            2.578799
          ],
          [
            -72.256697,
            1.150426
          ]
        ]
      ],
      "type": "Polygon"
    },
    "id": "c9cd572980c7663fc538a70f2092af60"
  }],
  "type": "FeatureCollection"
}

var figure2 = {
  "features": [{
    "type": "Feature",
    "properties": {},
    "geometry": {
      "coordinates": [
        [
          [
            -62.921997,
            -10.077123
          ],
          [
            -62.160825,
            -24.409954
          ],
          [
            -51.208418,
            -18.349548
          ],
          [
            -54.379964,
            -7.653952
          ],
          [
            -62.921997,
            -10.077123
          ]
        ]
      ],
      "type": "Polygon"
    },
    "id": "9db95177c15f320f2293f918b58ff94b"
  }],
  "type": "FeatureCollection"
}


var map = L.map('mapid').setView([-13.294, -60.624], 4);

L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
  attribution: 'Map data &copy; <a href="https://www.openstreetmap.org/">OpenStreetMap</a> contributors, <a href="https://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, Imagery © <a href="https://www.mapbox.com/">Mapbox</a>',
  maxZoom: 18,
  id: 'mapbox.streets',
}).addTo(map);

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

draw(figure1, figure2)

function draw(collection1, collection2) {

  collection = collection1

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

  var feature = g.selectAll("path")
    .data(collection.features)
    .enter().append("path")
    .attr("class", "green");

  map.on("viewreset", reset);
  reset();

  $("#btn1").click(function() {
    update(collection1, "green")
  });

  $("#btn2").click(function() {
    update(collection2, "red")
  });

  function update(data, color) {
    var t = d3.transition()
      .duration(750);

    var sel = g.selectAll("path")
      .data(data.features)
      .attr("class", color)

    sel.enter()
      .append("path")

    sel
      .transition().duration(1000)
      .attr("d", geoGenerator)
  }

  function reset() {

    var bounds = geoGenerator.bounds(collection),
      topLeft = bounds[0],
      bottomRight = bounds[1];

    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] + ")");

    feature.attr("d", geoGenerator);
  }

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

HTML:

<!doctype html>

<html lang="en">

  <head>
    <meta charset="utf-8">

    <link rel="stylesheet" href="css/styles.css?v=1.0">
    <link rel="stylesheet" href="https://unpkg.com/leaflet@1.5.1/dist/leaflet.css" integrity="sha512-xwE/Az9zrjBIphAcBb3F6JVqxf46+CDLwfLMHloNu6KEQCAWi6HcDUbeOfBIptF7tcCzusKFjFw2yuvEpDL9wQ==" crossorigin="" />
  </head>

  <body>
    <div>
      <button type="button" id="btn1">One</button>
      <button type=" button" id="btn2">Two</button>
    </div>

    <div id="mapid"></div>

    <script src="//d3js.org/d3.v3.min.js" charset="utf-8"></script>
    <script src="https://d3js.org/queue.v1.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.5/leaflet.js"></script>

    <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
  </body>

</html>

CSS:

#mapid {
  height: 500px;
}

svg {
  position: relative;
}

path {
  fill-opacity: .7;
  stroke: rgb(90, 89, 89);
  stroke-width: 3.5px;
}

.red {
  fill: rgb(255, 82, 14);
}

.green {
  fill: rgb(16, 236, 64);
}

标签: javascriptd3.jsleaflettransitiongeojson

解决方案


我想通了,问题出在数据上——默认情况下,d3 似乎无法处理这样的形状。当我将两个数字对齐以使其更相似并订购点时,它可以正常工作。我想我需要使用更高级的变形功能,比如flubber https://bestofjs.org/projects/flubber

它适用于这两个数字:

{
  "features": [
    {
      "type": "Feature",
      "properties": {},
      "geometry": {
        "coordinates": [
          [
            [
              -63.334278,
              -8.430061
            ],
            [
              -64.029526,
              -16.512253
            ],
            [
              -44.272875,
              -19.923701
            ],
            [
              -48.038806,
              -7.05227
            ],
            [
              -63.334278,
              -8.430061
            ]
          ]
        ],
        "type": "Polygon"
      },
      "id": "5142b4060fc932fe302b7ae7258dc916"
    }
  ],
  "type": "FeatureCollection"
}


{
  "features": [
    {
      "type": "Feature",
      "properties": {},
      "geometry": {
        "coordinates": [
          [
            [
              -62.921997,
              -10.077123
            ],
            [
              -62.160825,
              -24.409954
            ],
            [
              -51.208418,
              -18.349548
            ],
            [
              -54.379964,
              -7.653952
            ],
            [
              -62.921997,
              -10.077123
            ]
          ]
        ],
        "type": "Polygon"
      },
      "id": "9db95177c15f320f2293f918b58ff94b"
    }
  ],
  "type": "FeatureCollection"
}


推荐阅读