phk*_*phk 5 javascript svg d3.js
在我基于 d3.js 的项目中,即使视图的宽度或高度发生变化,我也希望保留当前视图中居中的内容以保持居中。同时我希望允许用户通过平移和缩放进行交互。
我的想法是使用嵌套组,外部组作为居中,内部组作为目标d3.zoom:
<g transform="translate(WIDTH/2, HEIGHT/2)">
<g transform="translate(ZOOM_X, ZOOM_Y) scale(ZOOM_K)">
...
</g>
</g>
Run Code Online (Sandbox Code Playgroud)
请参阅以下尝试:
var svgWrapper = d3.select("#svgWrapper").node(),
svg = d3.select("svg"),
width = svgWrapper.offsetWidth,
height = svgWrapper.offsetHeight;
var outerG = svg.append("g");
var g = outerG.append("g");
outerG.append("line")
.attr("stroke", "red")
.attr("stroke-width", 2)
.attr("x1", -10)
.attr("x2", 10)
.attr("y1", -10)
.attr("y2", 10);
outerG.append("line")
.attr("stroke", "red")
.attr("stroke-width", 2)
.attr("x1", -10)
.attr("x2", 10)
.attr("y1", 10)
.attr("y2", -10);
for (var i = 1; i <= 3; ++i) {
g.append("circle")
.attr("fill", "none")
.attr("stroke", "black")
.attr("stroke-width", 1.5)
.attr("r", i * 5);
}
var zoom = d3.zoom();
svg.call(zoom
.scaleExtent([1 / 2, 4])
.on("zoom", zoomed));
g.call(zoom.transform, d3.zoomIdentity.translate(-width / 2, -height / 2));
function zoomed() {
g.attr("transform", d3.event.transform);
}
// https://developer.mozilla.org/en-US/docs/Web/Events/resize#requestAnimationFrame_customEvent
function throttle(type, name, obj) {
obj = obj || window;
var running = false;
var func = function() {
if (running) {
return;
}
running = true;
requestAnimationFrame(function() {
obj.dispatchEvent(new CustomEvent(name));
running = false;
});
};
obj.addEventListener(type, func);
}
function resize() {
width = svgWrapper.offsetWidth;
height = svgWrapper.offsetHeight;
zoom.extent([
[0, 0],
[width, height]
]);
outerG.attr("transform", "translate(" + (width / 2) + ", " + (height / 2) + ")");
}
resize();
throttle("resize", "optimizedResize");
window.addEventListener("optimizedResize", resize);Run Code Online (Sandbox Code Playgroud)
html,
body,
#svgWrapper,
svg {
width: 100%;
height: 100%;
overflow: hidden;
}Run Code Online (Sandbox Code Playgroud)
<div id="svgWrapper">
<svg></svg>
</div>
<script src="https://d3js.org/d3.v4.min.js"></script>Run Code Online (Sandbox Code Playgroud)
红十字代表视口中心,圆圈代表可以拖动的内容。单击“整页”并调整窗口大小以查看调整大小的实际效果。
遗憾的是,第一个平移以及向某个点的缩放似乎已损坏。将两者合并translates()为一个transform也不起作用。
这是为什么?有什么可以做的吗?
由于各种原因,将其变成单个转换(即调用zoom.transform每次调整大小)在我的情况下并不是一个好的解决方案:
start//当窗口大小调整时,这会导致zoom事件被发出,甚至检查那里也没有多大帮助endevent.sourceEvent
平移限制 (.translateExtent() ) 与显示器相关。
与单一转换方法相比,这几乎没有任何优势,而且从我有限的测试来看,这似乎也存在问题。
zoom.extent()我不明白这对我有什么帮助。
添加像https://bl.ocks.org/mbostock/4e3925cdc804db257a86fdef3a032a45<rect>中那样捕获所有输入的a似乎可行,但我必须将矩形添加到外部组并将其转换回来(否则缩放中心将关闭):
var svgWrapper = d3.select("#svgWrapper").node(),
svg = d3.select("svg"),
width = svgWrapper.offsetWidth,
height = svgWrapper.offsetHeight;
var outerG = svg.append("g");
var g = outerG.append("g");
outerG.append("line")
.attr("stroke", "red")
.attr("stroke-width", 2)
.attr("x1", -10)
.attr("x2", 10)
.attr("y1", -10)
.attr("y2", 10);
outerG.append("line")
.attr("stroke", "red")
.attr("stroke-width", 2)
.attr("x1", -10)
.attr("x2", 10)
.attr("y1", 10)
.attr("y2", -10);
for (var i = 1; i <= 3; ++i) {
g.append("circle")
.attr("fill", "none")
.attr("stroke", "black")
.attr("stroke-width", 1.5)
.attr("r", i * 5);
}
var zoom = d3.zoom();
var rect = outerG.append("rect")
.attr("x", "-50%")
.attr("y", "-50%")
.attr("width", "100%")
.attr("height", "100%")
.style("fill", "yellow")
.style("opacity", ".1")
.style("pointer-events", "all")
.call(zoom
.scaleExtent([1 / 2, 4])
.on("zoom", zoomed));
function zoomed() {
g.attr("transform", d3.event.transform);
}
// https://developer.mozilla.org/en-US/docs/Web/Events/resize#requestAnimationFrame_customEvent
function throttle(type, name, obj) {
obj = obj || window;
var running = false;
var func = function() {
if (running) {
return;
}
running = true;
requestAnimationFrame(function() {
obj.dispatchEvent(new CustomEvent(name));
running = false;
});
};
obj.addEventListener(type, func);
}
function resize() {
width = svgWrapper.offsetWidth;
height = svgWrapper.offsetHeight;
zoom.extent([
[0, 0],
[width, height]
]);
outerG.attr("transform", "translate(" + (width / 2) + ", " + (height / 2) + ")");
}
resize();
throttle("resize", "optimizedResize");
window.addEventListener("optimizedResize", resize);Run Code Online (Sandbox Code Playgroud)
html,
body,
#svgWrapper,
svg {
width: 100%;
height: 100%;
overflow: hidden;
}Run Code Online (Sandbox Code Playgroud)
<div id="svgWrapper">
<svg></svg>
</div>
<script src="https://d3js.org/d3.v4.min.js"></script>Run Code Online (Sandbox Code Playgroud)
这对于示例来说效果很好,但遗憾的是覆盖层捕获了所有事件,因此显然您不能拥有可点击/可悬停的元素。请随意提出替代解决方案。
由于这些原因,我最终在我的项目中采用了单一转换方法。