Подход, который вы используете, не сработает, например, он не учитывает масштаб (просто переведите).Это очень важно, так как d3-мозаика использует геометрическое масштабирование - она применяет преобразование масштабирования (масштабирование и преобразование) ко всем векторным элементам (не плиткам), поэтому проекция проецирует все в квадратную область размером в один пиксель и никогда не изменяется сzoom.
Чтобы решить эту проблему, поместите ваши круги так же, как в примере, размещает (и размеры) полигонов:
vector
.attr("d", path(topojson.mesh(us, us.objects.counties)));
circle
.attr("cx", projection(coord)[0])
.attr("cy", projection(coord)[1])
.attr("r", 5/(1<<12));
Обе эти позиции имеют одинаковый способ: только с проекцией, проецируя на квадрат в один пиксель.Увеличение применяет преобразование, чтобы покрыть весь SVG. Кроме того, поскольку мы масштабируем один пиксель, чтобы он соответствовал svg, мы хотим, чтобы радиус тоже масштабировался соответствующим образом .
Теперь мы можем применить преобразование к окружностям, аналогичным полигонам.:
circle
.attr("transform", transform);
Конечно, мы могли бы уменьшать радиус и при каждом увеличении, используя увеличение k для изменения размера круга:
var pi = Math.PI,
tau = 2 * pi;
var width = Math.max(960, window.innerWidth),
height = Math.max(500, window.innerHeight);
// Initialize the projection to fit the world in a 1×1 square centered at the origin.
var projection = d3.geoMercator()
.scale(1 / tau)
.translate([0, 0]);
var path = d3.geoPath()
.projection(projection);
var tile = d3.tile()
.size([width, height]);
var zoom = d3.zoom()
.scaleExtent([1 << 11, 1 << 14])
.on("zoom", zoomed);
var svg = d3.select("svg")
.attr("width", width)
.attr("height", height);
var raster = svg.append("g");
var vector = svg.append("circle");
// Compute the projected initial center.
var center = projection([-98.5, 39.5]);
// Apply a zoom transform equivalent to projection.{scale,translate,center}.
svg
.call(zoom)
.call(zoom.transform, d3.zoomIdentity
.translate(width / 2, height / 2)
.scale(1 << 12)
.translate(-center[0], -center[1]));
var coord = [-100,40]
vector
.attr("cx", projection(coord)[0])
.attr("cy", projection(coord)[1])
.attr("r", 5/(1<<12));
function zoomed() {
var transform = d3.event.transform;
var tiles = tile
.scale(transform.k)
.translate([transform.x, transform.y])
();
vector
.attr("transform", transform)
.attr("r", 5/transform.k);
var image = raster
.attr("transform", stringify(tiles.scale, tiles.translate))
.selectAll("image")
.data(tiles, function(d) { return d; });
image.exit().remove();
image.enter().append("image")
.attr("xlink:href", function(d) { return "http://" + "abc"[d[1] % 3] + ".tile.openstreetmap.org/" + d[2] + "/" + d[0] + "/" + d[1] + ".png"; })
.attr("x", function(d) { return d[0] * 256; })
.attr("y", function(d) { return d[1] * 256; })
.attr("width", 256)
.attr("height", 256);
}
function stringify(scale, translate) {
var k = scale / 256, r = scale % 1 ? Number : Math.round;
return "translate(" + r(translate[0] * scale) + "," + r(translate[1] * scale) + ") scale(" + k + ")";
}
<svg></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://d3js.org/d3-tile.v0.0.min.js"></script>
<script src="https://d3js.org/topojson.v1.min.js"></script>
В конечном итоге d3-плитка может показаться немного запутанной, поскольку вы используете довольно много систем координат (мозаика, масштабирование, пиксель, проекция, географическая).и, как правило, не проецирует всю карту в квадрат 1 пикселя.