我正在制作一张加拿大选举投票区的可视化地图。我设法在这里获得了一个有效的 SVG 版本。
然而,性能很差,所以我想我会改为在 Canvas 上绘图。我把我认为是直接转换的东西放在一起:
class VectorMap {
constructor(map_file, element_id) {
this.map_file = map_file;
this.root = $(`#${element_id}`)[0];
this.init_map();
}
init_map() {
var root_rect = this.root.getBoundingClientRect();
this.width = root_rect.width;
this.height = 720;
this.zoom = d3.zoom()
.on('zoom', _ => this.onZoom(d3.event.transform));
var canvas = d3.select(this.root).append('canvas')
.attr('width', this.width)
.attr('height', this.height)
.call(this.zoom);
this.context = canvas.node().getContext('2d');
this.projection = d3.geoMercator()
.scale(1 / 2 / Math.PI)
.translate([0, 0]);
this.path = d3.geoPath()
.projection(this.projection)
.context(this.context);
this.onZoom(d3.zoomIdentity);
}
onZoom(transform) {
var tiler = d3.tile()
.size([this.width, this.height])
.scale(transform.k)
.translate([transform.x, transform.y])
//init drawing parameters
this.context.save();
this.context.fillStyle = 'gray';
this.context.strokeStyle = 'red';
//this.context.lineWidth = 1 / transform.k;
this.context.setTransform(1, 0, 0, 1, 0, 0);
this.context.clearRect(0, 0, this.width, this.height);
this.context.scale(transform.k, transform.k);
this.context.translate(transform.x, transform.y);
var tiles = tiler();
tiles.forEach(tile => {
console.log(tile);
var zoom = tile[2];
var x = tile[0];
var y = tile[1];
if (zoom > 10) {
// since these are vector tiles we can just overzoom the z10 ones
x = Math.floor(x / Math.pow(2, zoom - 10));
y = Math.floor(y / Math.pow(2, zoom - 10));
zoom = 10;
}
d3.json(`/maps/${zoom}/${x}/${y}/`)
.then(function(json) {
json.features.forEach(feature => {
this.context.beginPath();
path(feature);
this.context.closePath();
this.context.stroke();
this.context.fill();
});
});
});
this.context.restore();
}
但它什么也没画。显然 SVG 和 Canvas 之间发生了一些变化,但我不确定是什么。只是绘制矩形似乎有效,所以我假设这是画布路径生成器的问题。