我正在绘制大量元素,并且在许多情况下,大多数元素都在视点之外。
我想避免对隐藏元素进行昂贵的旋转变换。
这里是一个示例:
https://blockchaingraph.org/#ipfs-QmfXtMeUdjWBPQHUNKvF3nkYR57aZz7qarW5qikEUYWJvw
此图中的许多元素都是隐藏的(尝试缩小以查看)。但是目前,我必须在每个刻度上渲染每个元素,并且它变得越来越慢。
这是我的代码:
function transformLinks(svgLinks, nodeRadius, arrowSize) {
if (svgLinks) {
var link = svgLinks.selectAll('.link').filter(needRedraw);
//console.log("total:", svgLinks.selectAll('.link').size(), ',needRedraw:', link.size());
transformLinksLines(link);
transformLinksTexts(link.selectAll('.text'));
transformLinksOutlines(link, nodeRadius, arrowSize);
transformLinksOverlays(link.selectAll('.overlay'));
link.each(function (n) {
n.source.lx = n.source.x;
n.source.ly = n.source.y;
n.target.lx = n.target.x;
n.target.ly = n.target.y;
});
}
}
function needRedraw(link) {
if (!link.source) {
link = link.parentNode;
}
return nodeMoved(link.source) || nodeMoved(link.target);
}
var minDistToRedraw = 0.8;
function nodeMoved(n) {
return utils.isNumber(n.x) && utils.isNumber(n.y)
&& !(utils.isNumber(n.lx) && Math.abs(n.x - n.lx) <= minDistToRedraw && Math.abs(n.y - n.ly) <= minDistToRedraw);
}
我想扩展needRedraw()函数以检查可见性。目前,该功能仅检查两个链接的节点是否移动足够大。
答案 0 :(得分:0)
由于我没有找到任何开箱即用的解决方案,所以我不得不进入那些坐标转换方面。
首先,我创建了将外部容器坐标转换为SVG内部客户端坐标系统的函数-containerToSVG()
然后将其应用于.getBoundingClientRect();以获得SVG坐标空间中的可见区域。
然后在过滤器中检查两个节点的大小是否均超出可见区域-不要重绘链接。
在某些情况下,两个节点都超出了该区域的大小,但是链接仍然可以越过该区域。但这并不是大问题,只要用户看不到链接分离。
代码如下:
function transformLinks(svgLinks, nodeRadius, arrowSize) {
if (svgLinks) {
var containerRect = container.node().getBoundingClientRect();
var p = containerToSVG(-nodeRadius, -nodeRadius);
var r = containerToSVG(containerRect.width + nodeRadius, containerRect.height + nodeRadius);
svgVisibleRect = {left: p.x, top: p.y, right: r.x, bottom: r.y};
minDistToRedraw = (svgVisibleRect.right - svgVisibleRect.left) / (containerRect.width + nodeRadius * 2);
var link = svgLinks.selectAll('.link').filter(needRedraw);
transformLinksLines(link);
transformLinksTexts(link.selectAll('.text'));
transformLinksOutlines(link, nodeRadius, arrowSize);
transformLinksOverlays(link.selectAll('.overlay'));
link.each(function (n) {
updateLastCoord(n.source);
updateLastCoord(n.target);
});
}
}
function needRedraw(link) {
if (!nodeMoved(link.source) && !nodeMoved(link.target)) {
return false;
}
return isVisible(link.source) || isVisible(link.target);
}
function nodeMoved(n) {
return utils.isNumber(n.x) && utils.isNumber(n.y) &&
!(utils.isNumber(n.lx) && Math.abs(n.x - n.lx) <= minDistToRedraw && Math.abs(n.y - n.ly) <= minDistToRedraw);
}
function isVisible(n) {
var result = n.x > svgVisibleRect.left && n.x < svgVisibleRect.right &&
n.y > svgVisibleRect.top && n.y < svgVisibleRect.bottom;
return result;
}
function updateLastCoord(n) {
n.lx = n.x;
n.ly = n.y;
}
function containerToSVG(containerX, containerY) {
var svgPount = svgNode.createSVGPoint();
svgPount.x = containerX;
svgPount.y = containerY;
return svgPount.matrixTransform(document.getElementById("links-svg").getScreenCTM().inverse());
}
function transformLinksLines(link) {
link.attr('transform', function (d) {
var angle = rotation(d.source, d.target);
return 'translate(' + d.source.x + ', ' + d.source.y + ') rotate(' + angle + ')';
});
}