SVG的渲染是否可以推迟到我完成对它的操作

Can the rendering of an SVG be postponed until I finished manipulating it?

本文关键字:操作 迟到 推迟 是否 SVG      更新时间:2023-09-26

我正在构建一个使用SVG在浏览器中运行的复杂GUI。SVG有许多可以操作的对象。

只要我同时操作一个或几个对象,一切都会顺利进行,但当我开始移动一大群对象时,事情就会变得非常缓慢。

我通过更改SVG元素的每个属性来移动它们。我认为这很慢,因为浏览器每次更改DOM时都会渲染SVG,所以为了移动一组元素,SVG的渲染次数与要移动的元素的渲染次数一样多。这是正确的吗?

我做了一个实验,我认为这证明了我的观点。如果我将要移动的所有元素分组到SVG组中,然后通过更改其转换属性来移动该组。动作非常流畅。在这种情况下,我只更改SVG DOM一次,SVG只重新渲染一次。

问题是我不能使用这种技术,因为元素不是一直以相同的方式分组的。每次重新组合元素似乎增加了许多不必要的复杂性。

我想知道是否有一种方法可以推迟SVG的渲染,直到我移动了所有对象?

也许您可以尝试简单地将其从dom树中删除,然后在更改后将其添加回来,例如:

    <!DOCTYPE html>
<html>
    <script type="text/javascript">
        function change () {
            var mySVG = document.getElementById('mySVG'),
                circle = document.getElementById('myCircle'),
                body = document.body;
            body.removeChild(mySVG);
            circle.setAttribute('cx', '150');
            circle.setAttribute('cy', '100');
            circle.setAttribute('r', '80');
            body.appendChild(mySVG);
        }
    </script>
    <body>
        <button onclick="change();">change</button>
        <svg id="mySVG" xmlns="http://www.w3.org/2000/svg" version="1.1">
            <circle id="myCircle" cx="100" cy="50" r="40" stroke="black" stroke-width="2" fill="red" />
        </svg>
    </body>
</html>

问候,

Ben

浏览器确实检测到DOM的更改,但它们不会在每次更改时重新渲染整个svg一次,而是对渲染操作进行排队(批处理)(通常在执行修改的脚本片段完成一段时间后进行渲染)。如果每一次更改都触发了某种布局/回流操作(基本上是树遍历),以找出绘制内容和位置,我不会感到惊讶。

从问题的描述来看,这听起来像是一个拖放界面,您可以在其中选择多个元素并移动它们。这可能不是一拖再拖,但原则也是一样的。你有三个事件,开始,移动和结束,在拖放中,它看起来像这样:

start = function(e) {
  //capture the initial position
}
move = function(e) {
  //change the x and y attributes or transform attr
}
end = function(e) {
  //finish up
}
svg.addEventListener("mousedown", start)
svg.addEventListener("mousemove", move)
svg.addEventListener("mouseup", end)

现在,如果你只想在行动结束时更改属性,你可以这样做:

start = function(e) {
  //capture the initial position
}
end = function(e) {
  //change the x and y attributes or transform attr
  //finish up
}
svg.addEventListener("mousedown", start)
svg.addEventListener("mouseup", end)

因此,在这种情况下,事件只会在两次时触发,一次是在按下鼠标按钮时,第二次是在释放鼠标按钮时。