我正在使用交互式细粒度美国地图,在d3中有大约35K多边形。一旦我开始想要回应单个多边形的点击,我就遇到了这个问题。我使用SVG路径元素来渲染多边形。
问题是我无法让Chrome响应SVG上的点击事件,我称之为交互式费率(〜亚秒级响应时间),而Firefox处理方案没有问题。希望有一些伏都教我不知道或者可能是我忽略了一些简单的东西?
我将下面的问题简化为仅包含基本要素的纯JavaScript。我使用SVG路径元素(模拟我的地图)生成一堆方形单元格,然后附加单击处理程序。尝试不同版本的 numberOfPathCellsPerSide 并鼠标单击SVG地图,以查看Chrome中的渐进性能下降与Firefox中的即时性能。
///////////////////////////////////////////////////////////////////////////////////////////
// numberOfPathCellsPerSide * numberOfPathCellsPerSide = total number of SVG path "polygons".
// Click handler response time seems to be tied to total number of paths rather than the
// size of each path. Also, as you will see down below, several different variations
// of click event listening were tried to no avail.
// Try uncommenting each in succession to experience the performance variations
// between Chrome and Firefox:
///////////////////////////////////////////////////////////////////////////////////////////
var numberOfPathCellsPerSide = 100; // 100 x 100 = 10,000 total paths => ~instant in Chrome, ~instant in Firefox
//var numberOfPathCellsPerSide = 200; // 200 x 200 = 40,000 total paths => ~7 sec in Chrome, ~instant in Firefox
//var numberOfPathCellsPerSide = 300; // 300 x 300 = 90,000 total paths => ~48 sec in Chrome, ~instant in Firefox
var lengthOfPathCell = 5;
var xmlns = "http://www.w3.org/2000/svg";
var description = document.createElement("div");
description.innerHTML =
"Total number of svg paths: " + numberOfPathCellsPerSide * numberOfPathCellsPerSide + "<br><br>";
document.body.appendChild(description);
var lengthOfSVGContainer = numberOfPathCellsPerSide * lengthOfPathCell;
var svg = document.createElementNS (xmlns, "svg");
document.body.appendChild(svg);
svg.setAttributeNS (null, "width", lengthOfSVGContainer);
svg.setAttributeNS(null, "height", lengthOfSVGContainer);
var g = document.createElementNS(xmlns, "g");
svg.appendChild(g);
for(var i=0; i<(numberOfPathCellsPerSide * numberOfPathCellsPerSide); i++)
{
var path = document.createElementNS (xmlns, "path");
var x = (i % numberOfPathCellsPerSide) * lengthOfPathCell
var y = Math.floor(i / numberOfPathCellsPerSide) * lengthOfPathCell;
var drawCellCommands =
"M " + x + " " + y + " " +
"L " + (x + lengthOfPathCell) + " " + y + " " +
"L " + (x + lengthOfPathCell) + " " + (y + lengthOfPathCell) + " " +
"L " + x + " " + (y + lengthOfPathCell) + " " +
"L " + x + " " + y + " ";
path.setAttributeNS(null, "d", drawCellCommands);
path.style.fill = "hsl(" + Math.random() * 360 + ",100%,50%)";
///////////////////////////////////////////////////////////////////////////////////////////
// Several different variants of listening for click events.
// Leave one of them uncommented to see it doesn't seem to matter!
///////////////////////////////////////////////////////////////////////////////////////////
// listener attempt 1: create an anonymous handler function for each path cell
path.addEventListener("click", function(e)
{
console.log("finally handled the click...");
alert("finally handled the click...");
});
// listener attempt 2: use the same named handler function for each path cell
//path.addEventListener("click", namedClickHandler);
g.appendChild(path);
}
// listener attempt 3: leverage delegation by using a single named handler once on enclosing SVG parent element
// Should be the most responsive yet still seems to make no difference in Chrome
//svg.addEventListener("click", namedClickHandler);
function namedClickHandler(e)
{
console.log("finally handled the click...");
alert("finally handled the click...");
}