0

我正在尝试使用 d3-geo-voronoi 来使用 d3-tile 显示矢量平铺数据。我最初尝试显示数据,填充设置为“无”,这非常令人兴奋! 没有颜色填充的 Voronoi 平铺贴图

然而,当我尝试填充多边形时,一些图块被扭曲了。 带有颜色填充的 Voronoi 平铺图

我一直无法弄清楚为什么会这样。我检查了 dom 中的 svg,一切看起来都正确。svg 在没有多边形的情况下是正确的,它们只是没有被正确渲染,可能它们被掩盖了。下面是我使用的代码:

const d3 = require('d3');
const d3tile = require('d3-tile');
const d3geovoronoi = require('d3-geo-voronoi');
const vt2geojson = require('@mapbox/vt2geojson');

const pi = Math.PI,
      tau = 2 * pi;

const width = Math.max(960, window.innerWidth),
      height = Math.max(500, window.innerHeight);

const map = d3.select("body").append("div")
  .attr("class", "map")
  .style("width", width + "px")
  .style("height", height + "px")
  .on("mousemove", mousemoved);

let projection = d3.geoMercator()
  .scale(1 / tau)
  .translate([0, 0]);

let center = projection([-76.3, 38.794745]);

const tile = d3tile.tile()
  .size([width, height]);

const zoom = d3.zoom()
  .scaleExtent([1 << 15, 1 << 24])
  .on("zoom", zoomed);

const svg = map.append("g")
  .attr("pointer-events", "none")
  .attr("class", "svg");

const info = map.append("g")
  .attr("class", "info");

const ramp = d3.scaleLinear().domain([0.05,0.07]).interpolate(d3.interpolateHcl).range(['#34d8eb','#3a34eb']).unknown("#5c5752")

map.call(zoom)
  .call(zoom.transform, d3.zoomIdentity
    .translate(width / 2, height / 2)
    .scale(1 << 21)
    .translate(-center[0], -center[1]));

function zoomed() {
  let transform = d3.event.transform;

  let tiles = tile(transform);

  let image = svg 
    .style("transform", stringify(tiles.scale, tiles.translate))
    .selectAll(".tile")
    .data(tiles, function(d) { return d; })
    .enter().append("svg")
    .attr("class", "tile")
    .attr("fill", "none")
    .attr("stroke", "#000")
    .attr("stroke-width", "0.5")
    .attr("stroke-linejoin", "round")
    .attr("stroke-linecap", "round")
    .style("left", function(d) { return d[0] * 256 + "px"; })
    .style("top", function(d) { return d[1] * 256 + "px"; })
    .each(function(d) { this._xhr = render(d, this); });

  projection
    .scale(transform.k / tau)
    .translate([transform.x, transform.y]);

}

function render(d, xnode) {
  let k = Math.pow(2, d[2]) * 256;
  vt2geojson({
    uri: 'http://localhost:7800/public.r3sim_fort_temp/'+d[2]+'/'+d[0]+'/'+d[1]+'.pbf?properties=node,zeta,mask,bathymetry'
  }, function (err, json) {
    if (err) throw err;
    d3.select(xnode)
      .selectAll("path")
      .data(d3geovoronoi.geoVoronoi().polygons(json).features)
      .enter().append("path")
    //.attr('fill', 'none')
        .attr("fill", function(d) {return ramp(d.properties.site.properties.zeta)})
        .attr("stroke", "#fff")
        .attr("stroke-width", "0.5")
        .attr("stroke-linejoin", "round")
        .attr("stroke-linecap", "round")
        .attr("d", d3.geoPath()
            .projection(d3.geoMercator()
                .scale(k / tau)
                .translate([k / 2 - d[0] * 256, k / 2 - d[1] * 256])
                .precision(0)));
  })
}

function stringify(scale, translate) {
  const k = scale / 256, r = scale % 1 ? Number : Math.round;
  return "matrix3d(" + [k, 0, 0, 0, 0, k, 0, 0, 0, 0, k, 0, r(translate[0] * scale), r(translate[1] * scale), 0, 1 ] + ")";
}

function mousemoved() {
  info.text(formatLocation(projection.invert(d3.mouse(this)), d3.zoomTransform(this).k));
}

function formatLocation(p, k) {
  const format = d3.format("." + Math.floor(Math.log(k) / 2 - 2) + "f");
  return (p[1] < 0 ? format(-p[1]) + "°S" : format(p[1]) + "°N") + " "
       + (p[0] < 0 ? format(-p[0]) + "°W" : format(p[0]) + "°E");
}

<!doctype html>
<head>
  <meta charset="utf-8">
  <title>D3 V5 Vector Tile Example</title>
  <style>
    body {
      margin: 0;
    }
    .map {
      background: #5c5752;
      position: relative;
      overflow: hidden;
    }
    .svg {
      position: absolute;
      will-change: transform;
    }
    .tile {
      position: absolute;
      width: 256px;
      height: 256px;
    }
    .info {
      position: absolute;
      bottom: 10px;
      left: 10px;
    }
  </style>
</head>
<body>
  <script src="bundle.js"></script>
</body>

在这个例子中,我用不同的颜色值填充了多边形。但是,如果我使用单一颜色值,则会出现完全相同的失真。如果我重新加载所有数据,失真也总是在同一个地方。

4

1 回答 1

0

我对数据进行了更深入的研究,发现了错误的 svg 路径,然后找到了与之相关的数据。看起来 d3.geo.voronoi 正在生成一些错误的坐标,但输入数据看起来还不错。下面是节点 1192 的两个打印输出。第一个是输入的 geojson 数据,显示坐标,第二个是 voronoi 几何。voronoi 几何包含东半球 (103.86...) 的经度值,这超出了数据范围。我仍在尝试确定为什么会产生这些不良值。同样,输入坐标看起来是正确的,但可能是其他数据进入了 voronoi 计算?

1192 
{…}
  geometry: {…}
    coordinates: (2) […]
      0: -76.12801194190979
      1: 38.78622954627738
      length: 2
      <prototype>: Array []
    type: "Point"
    <prototype>: Object { … }
  properties: Object { node: 180407, zeta: "NaN", mask: "True", … }
  type: "Feature"
  <prototype>: Object { … }

1192 (11) […]
  0: Array [ 103.86695733932268, -44.964779133003304 ]
  1: Array [ -76.13308210176842, 38.75793814039401 ]
  2: Array [ -76.13020999558496, 38.782688154120585 ]
  3: Array [ -76.12890669699081, 38.78647064351637 ]
  4: Array [ -76.12807302385534, 38.786723650244355 ]
  5: Array [ -76.12754554182737, 38.78651000385868 ]
  6: Array [ -76.12640847594942, 38.78408839960177 ]
  7: Array [ -76.11435851540921, 38.636536130021334 ]
  8: Array [ 103.858096036925, -39.00570100251519 ]
  9: Array [ 103.860092112702, -39.367933188411186 ]
  10: Array [ 103.86695733932268, -44.964779133003304 ]
  length: 11
  <prototype>: []
于 2020-03-26T22:11:51.923 回答