简体   繁体   English

用映像填充数百个SVG路径会导致严重的性能问题

[英]Filling hundreds SVG paths with an image causes serious performance issues

I'm creating hexagonal tiles using SVG like that: 我正在使用SVG创建六角形瓷砖,如下所示:

<style>
    .tile:hover {
        fill: red;
    }
</style>

<svg width="1000" height="1000">
    <g>
        <path
            d="M-17.32050807568877,-10L0,-20L17.32050807568877,-10L17.32050807568877,10.000000000000002L0,20.000000000000004L-17.32050807568877,10.000000000000002"
            class="tile"></path>

            ...
    </g>
</svg>

I have about 400 tiles on the screen. 我的屏幕上有大约400个磁贴。 You can check how it looks here: https://337706.playcode.io/ Try to hover over some tiles. 您可以在此处查看外观: https : //337706.playcode.io/尝试将鼠标悬停在某些图块上。 Hovered tiles should become red, and there is no performance issues. 悬停的图块应变为红色,并且没有性能问题。 There is also no issue if I fill all of the tiles with color: 如果我用颜色填充所有图块,也没有问题:

<style>
    .tile {
        fill: green;
    }
</style>

I'd like to fill the tiles with an image, so I have created a pattern: 我想用图像填充图块,所以我创建了一个模式:

<defs>
    <pattern patternUnits="objectBoundingBox" id="grass" width="70" height="80">
        <image href="https://i.ibb.co/9ZZgDhy/tiles.png"></image>
    </pattern>
</defs>

And then, fill tiles with it: 然后,用它填充瓷砖:

<style>
    .tile {
        fill: url(#grass);
    }

    .tile:hover {
        fill: red;
    }
</style>

After that, the performance drops dramatically. 之后,性能会急剧下降。 (you can check it here, but bear in mind it may even crash your browser: https://337697.playcode.io/ ) (您可以在此处进行检查,但请记住,它甚至可能使您的浏览器崩溃: https : //337697.playcode.io/

I have checked the profiler on Chrome, it says 98% of the time is spent on "Composite Layers". 我已经在Chrome上检查了探查器,它说98%的时间都花在了“复合层”上。

在此处输入图片说明

I have noticed that the problem is not about the image itself but about the <pattern> because even if I remove the image and place just green rectangle instead, the performance is the same bad. 我注意到问题不在于图像本身,而是与<pattern>有关,因为即使我删除图像并仅放置绿色矩形,其性能也一样差。 If I remove the pattern and just fill the tile with color, there is no issue... 如果我删除图案并仅用颜色填充瓷砖,则没有问题...

How can I fill the tiles with image and fix this performance issue? 如何用图像填充图块并解决此性能问题? Is there a better way of setting the background image? 有设置背景图片的更好方法吗?

It should be quicker using clipped images. 使用裁剪的图像应该更快。

I've created the map using a nested loop to create a bunch of <use> elements. 我使用嵌套循环创建了地图,以创建一堆<use>元素。 The downside to this method is that you can't do a simple CSS colour change on hover. 这种方法的缺点是您无法在悬停时进行简单的CSS颜色更改。

 var map = document.getElementById("map"); var SVG_NS = map.namespaceURI; var XLINK_NS = "http://www.w3.org/1999/xlink"; var H_STEP = 34.64; var V_STEP = 30; var y = 0; for (let j=0; j<20; j++) { var xStart = (j % 2) ? (H_STEP / 2) : 0; for (let i=0; i<20; i++) { addUse("grass", xStart + i * H_STEP, j * V_STEP); } } function addUse(defId, x, y) { var use = document.createElementNS(map.namespaceURI, "use"); use.setAttributeNS(XLINK_NS, "xlink:href", "#"+defId); use.setAttribute("x", x); use.setAttribute("y", y); map.appendChild(use); } 
 <svg width="1000" height="1000"> <defs> <clipPath id="hexagon"> <path d="M0,10 L17.32,0 L34.64,10 L34.64,30 L17.32,40 L0,30 Z"/> </clipPath> <image id="grass" href="https://i.ibb.co/9ZZgDhy/tiles.png" width="105" height="80" clip-path="url(#hexagon)"/> </defs> <g id="map"> </g> </svg> 

I think the composite process with that many SVG's filled with a pattern is just asking too much. 我认为,包含许多SVG且填充有模式的复合过程的要求太多。 I'm basing that thought on this write-up . 我在此基础上这个想法写了 I'm not sure if there is a good way to improve that, but there are other ways to accomplish what you want. 我不确定是否有改善它的好方法,但是还有其他方法可以实现您想要的。


Here's an example using css clip-path in place of an SVG. 这是一个使用css clip-path代替SVG的示例。

Note you need to do a bit more work in CSS to correctly position everything. 请注意,您需要在CSS中做更多的工作才能正确放置所有内容。

Each hexagon is a square and all corners land on a quarter or half. 每个六边形都是一个正方形,所有角点占四分之一或一半。 That makes the math a bit easier. 这使数学变得容易一些。 I'm absolutely positioning each tile and then providing height , width , X ( left:offset ) and Y ( top:offset ) via the Javascript when they're appended. 我绝对定位每个图块,然后在附加它们时通过Javascript提供heightwidth ,X( left:offset )和Y( top:offset )。

Here's a Codepen if you want to play with it. 如果您想使用Codepen ,可以使用它。

It seems quite performant even with 2500 elements... 即使有2500个元素,它的表现似乎不错

 var container = document.getElementById("wrapper"); var totalCols = 10; var totalRows = 15; var stepX = (1/totalCols) * 100; var stepY = stepX * 0.75; for (let r=0; r<totalRows; r++ ){ for(let c=0; c<totalCols; c++){ var offset = (r % 2) ? (stepX * 0.5) : 0; addHexagon(offset + c * stepX, r * stepY); } } function addHexagon (x,y) { var newPos = 'top: ' + y + '%;' + 'left: ' + x + '%;' + 'width: ' + stepX +'%;' + 'height: ' + stepX + '%;' var el = document.createElement('div') el.setAttribute('class', 'el') el.setAttribute('style', newPos); container.appendChild(el); } 
 #wrapper { width:1000px; height: 1000px; background: #333; position: relative; overflow:hidden; } .el { position: absolute; /* set height & width using js */ /* make the hexagon and mask the content */ clip-path: polygon(50% 0%, 100% 25%, 100% 75%, 50% 100%, 0% 75%, 0% 25%); /* asethetic only */ background-image: url(https://images.unsplash.com/photo-1560146491-308b0f69a52a?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=200&q=80); background-size: cover; background-position: center center; background-repeat: no-repeat; } .el:hover { background-color: blue; background-image: none; } 
 <div id="wrapper"></div> 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM