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