gpt4 book ai didi

javascript - 保持内容居中并允许在 d3 中平移/缩放

转载 作者:塔克拉玛干 更新时间:2023-11-02 21:25:15 26 4
gpt4 key购买 nike

在我基于 d3.js 的项目中,即使 View 的宽度或高度发生变化,我也想让当前 View 居中的内容保持居中。同时我希望允许用户通过平移和缩放进行交互。

我的想法是使用嵌套组,外部组用于居中,内部组作为 d3.zoom 目标:

<g transform="translate(WIDTH/2, HEIGHT/2)">
<g transform="translate(ZOOM_X, ZOOM_Y) scale(ZOOM_K)">

...

</g>
</g>

请参阅以下尝试:

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);
html,
body,
#svgWrapper,
svg {
width: 100%;
height: 100%;
overflow: hidden;
}
<div id="svgWrapper">
<svg></svg>
</div>
<script src="https://d3js.org/d3.v4.min.js"></script>

红色十字代表视口(viewport)中心,圆圈代表可以拖动的内容。单击“整页”并调整窗口大小以查看调整大小的效果。

遗憾的是,第一个平移以及向某个点缩放似乎坏了。将两个 translates() 放入单个 transform 中也不起作用。

这是为什么?有什么办法可以解决吗?

目前的想法和失败的尝试

单一变换

将它变成一个单一的转换,即在每次调整大小时调用 zoom.transform,出于各种原因对我来说不是一个好的解决方案:

  • 这会导致 start/zoom/end 事件在调整窗口大小甚至检查 event.sourceEvent 没什么用

  • 平移限制 (​​.translateExtent()) 将与显示相关。

内部转换内部转换

与单一转换方法相比,这几乎没有任何优势,而且从我有限的测试来看,这似乎也存在问题。

zoom.extent()

我不明白这对我有什么帮助。

最佳答案

添加 <rect>它捕获所有输入,如 https://bl.ocks.org/mbostock/4e3925cdc804db257a86fdef3a032a45似乎可行,但我必须将矩形添加到外部组并将其转换回来(否则缩放中心将关闭):

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);
html,
body,
#svgWrapper,
svg {
width: 100%;
height: 100%;
overflow: hidden;
}
<div id="svgWrapper">
<svg></svg>
</div>
<script src="https://d3js.org/d3.v4.min.js"></script>

这对于示例来说效果很好,但遗憾的是,叠加层捕获了所有事件,因此显然您无法拥有可点击/可悬停的元素。欢迎提出替代解决方案。

由于这些原因,我对我的项目最终采用了单一转换方法。

关于javascript - 保持内容居中并允许在 d3 中平移/缩放,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46533546/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com