Фон
Вы управляете преобразованием, примененным к вашим элементам, в функции щелчка, но не обновляете состояние масштабирования, чтобы отразить это.d3.zoom не отслеживает преобразование элемента вообще.Таким образом, когда вы изменяете атрибут transform элемента независимо от d3.zoom, d3.zoom больше не «знает», каково преобразование этого элемента - оно остается неизменным.D3.zoom отслеживает состояние масштабирования - внутренне и независимо от атрибута преобразования любого элемента.
Может показаться странным, что d3.zoom не отслеживает преобразование элемента, но для этого есть веская причина.d3.zoom не всегда используется для управления преобразованием элемента, он может изменять что-то вроде ширины элемента или масштаба, в то время как преобразование этого элемента остается неизменным.Вот мой bl.ock , где d3.zoom управляет только радиусом кругов на холсте.
Задача
Как вы не делаетеt обновляя состояние масштабирования в событии щелчка, d3.zoom определяет, где оно было в последний раз, при применении нового события масштабирования, что объясняет ваш симптом: «Кажется, мой уровень масштабирования восстанавливается, как это было до щелчка мыши».
Решение
Итак, что вам нужно сделать?Вам нужно передать преобразование масштаба в d3.zoom и вызвать событие масштабирования.Таким образом, d3.zoom получает информацию о текущем состоянии масштабирования.К счастью, есть способ для этого.Мы берем d3.zoomIdentity (k = 1, x = 0, y = 0) и переводим и масштабируем по мере необходимости, мы можем переводить, масштабировать, а затем снова переводить, как вы это сделали:
// Create a zoom transform from d3.zoomIdentity
var transform = d3.zoomIdentity
.translate(250,150)
.scale(k)
.translate(-x,-y);
А затем мы применяем масштабирование, вызывая zoom.transform, который в соответствии с документами:
устанавливает текущее преобразование масштабирования выбранных элементов в указанное преобразование, мгновенно генерируя события начала, масштабирования и окончания.Если выделение является переходом, определяет анимацию «увеличения» для указанного преобразования с использованием d3.interpolateZoom, отправляя событие start, когда начинается переход, события масштабирования для каждого тика перехода, а затем событие end, когда переход завершается (илипрерывается).( ссылка )
Мы можем вызвать zoom.transform с помощью:
// Apply the zoom and trigger a zoom event with a provided zoom transform:
svg.call(zoom.transform, transform);
Так что если это аналогично тому, что у вас есть:
var zoom = d3.zoom()
.scaleExtent([1,8])
.translateExtent([[0,0],[500,300]])
.on("zoom",zoomed);
var svg = d3.select("div")
.append("svg")
.attr("width",500)
.attr("height",300)
.call(zoom);
var g = svg.append("g");
var rects = g.selectAll(null)
.data(d3.range(750))
.enter()
.append("rect")
.attr("width",17)
.attr("height",17)
.attr("fill","#eee")
.attr("y", function(d) { return Math.floor(d/50) * 20; })
.attr("x", function(d) { return d%50 * 20; })
.on("click", click);
function zoomed() {
g.attr("transform", d3.event.transform);
}
function click(d) {
rects.attr("fill","#eee");
var clicked = d3.select(this);
clicked.attr("fill","orange");
var x = +clicked.attr("x")+10;
var y = +clicked.attr("y")+10;
var k = 5;
var transform = "translate(" + 250 + "," + 150 + ")scale(" + k + ")translate(" + -x + "," + -y + ")";
g.transition()
.attr("transform",transform)
.duration(1000);
}
rect {
stroke-width: 1px;
stroke: #ccc;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<div>
Это может быть аналогично вашему решению:
var zoom = d3.zoom()
.scaleExtent([1,8])
.translateExtent([[0,0],[500,300]])
.on("zoom",zoomed);
var svg = d3.select("div")
.append("svg")
.attr("width",500)
.attr("height",300)
.call(zoom);
var g = svg.append("g");
var rects = g.selectAll(null)
.data(d3.range(750))
.enter()
.append("rect")
.attr("width",17)
.attr("height",17)
.attr("fill","#eee")
.attr("y", function(d) { return Math.floor(d/50) * 20; })
.attr("x", function(d) { return d%50 * 20; })
.on("click", click);
function zoomed() {
g.attr("transform", d3.event.transform);
}
function click(d) {
rects.attr("fill","#eee");
var clicked = d3.select(this);
clicked.attr("fill","orange");
var x = +clicked.attr("x")+10;
var y = +clicked.attr("y")+10;
var k = 5;
// Create a zoom transform from d3.zoomIdentity
var transform = d3.zoomIdentity
.translate(250,150)
.scale(k)
.translate(-x,-y);
// Apply the zoom and trigger a zoom event:
svg.call(zoom.transform, transform);
}
rect {
stroke-width: 1px;
stroke: #ccc;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<div>