私は、カナダの選挙の投票部門の地図を視覚化することに取り組んでいます。ここで、動作する 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 の間で何かが変更されていますが、何が変わったのかはわかりません。長方形を描くだけでうまくいくように見えるので、キャンバスパスジェネレーターの問題だと思います。