将document.elementsFromPoint(x,y)限制为仅SVG id,并按id打印元素列表



如何制作document.elementsFromPoint(x,y(只返回SVG中的元素
如何仅获取SVG元素的列表,并仅将悬停更改应用于这些SVG元素?

最后,它将被覆盖在一个有数千个点的非常大的SVG上。有没有一种更有效的方法可以只在悬停时应用颜色变化,而在鼠标移动时只删除这些元素的颜色变化?(目前的方法将其应用于所有SVG元素,这意味着在一个包含更多元素的文档上,每移动一次鼠标,就会发生数千次更改(

在这段代码中,我尝试了svg.elementsFromPoint(x,y(。我读到了关于ShadowRoots的文章,并试图在SVG上创建ShadowRoot((,但没有成功;我甚至不确定这是否是正确的方法。

https://jsfiddle.net/g8p60vy7/

(function() {
const svg = document.querySelector('#Shapes'),
output = document.querySelector('#test');
function printElement(elm) {
var id = elm.id ? ' id="' + elm.id + '"' : "";
return "<" + elm.tagName.toLowerCase() + id + ">";
}
var shapes = svg.querySelectorAll('ellipse,rect,polygon');
shapes.forEach( (el) => {
el.dataset.default_fill = "rgba(0,0,0,0)";
el.style.fill = el.dataset.default_fill;
} );
function hitTest(e) {
const x = e.clientX,
y = e.clientY,
current_hovereds = document.elementsFromPoint( x, y );
shapes.forEach( (el) => el.style.fill = el.dataset.default_fill );

var orderedcolors = ["rgba(255, 0 , 0, 0.7)", "rgba(255, 127, 0, 0.2)", "rgba(255, 255, 0, 0.2)", " rgba(0, 255, 0, 0.2)", " rgba(75, 0, 130, 0.2)", " rgba(148, 0, 211, 0.2)", "rgba(0,0,0,0.2)", "rgba(0,0,0,0.1)", "rgba(0,0,0,0.01)"];

current_hovereds.forEach( (el, i) => el.style.fill =  orderedcolors[ i ]);
//not working to print element
output.textContext = current_hovereds.map(printElement).join(' ');
}

svg.addEventListener('mousemove', hitTest);
svg.addEventListener('touchmove', hitTest);
})();

根据我从你的fiddle中可以看出,你的目标不是<svg>元素的子元素,而是可以用fill属性着色的元素。它们有共同的基类SVGGeometryElement。你可以测试一下:

const current_hovereds =document.elementsFromPoint( x, y ).filter(el => {
return el instanceof SVGGeometryElement;
});

并不是说Internet Explorer没有实现这个类。如果你需要兼容性,你需要列出所有相关的元素:

return el instanceof SVGPathElement ||
el instanceof SVGRectElement ||
el instanceof SVGCircleElement ||
el instanceof SVGEllipseElement ||
el instanceof SVGLineElement ||
el instanceof SVGPolylineElement ||
el instanceof SVGPolygonElement ||
el instanceof SVGTextContentElement;

对于文本输出,这是一个简单的打字错误:output.textContent,而不是output.textContext

您已经有了目标shapes的列表,只需将document.elementsFromPoint的结果过滤到此shapes列表中的结果即可。

(function() {
const svg = document.querySelector('#Shapes');
const output = document.querySelector('#test');
function printElement(elm) {
var id = elm.id ? ' id="' + elm.id + '"' : "";
return "<" + elm.tagName.toLowerCase() + id + ">";
}
// convert to Array for easy filtering
const shapes = [...svg.querySelectorAll('ellipse,rect,polygon')];
shapes.forEach((el) => {
el.dataset.default_fill = "rgba(0,0,0,0)";
el.style.fill = el.dataset.default_fill;
});
function hitTest(e) {
const orderedcolors = ["rgba(255, 0 , 0, 0.7)", "rgba(255, 127, 0, 0.2)", "rgba(255, 255, 0, 0.2)", " rgba(0, 255, 0, 0.2)", " rgba(75, 0, 130, 0.2)", " rgba(148, 0, 211, 0.2)", "rgba(0,0,0,0.2)", "rgba(0,0,0,0.1)", "rgba(0,0,0,0.01)"];
const x = e.clientX;
const y = e.clientY;
const current_hovereds = document.elementsFromPoint(x, y)
// keep only our shapes
.filter(el => shapes.includes(el));
shapes.forEach((el) => el.style.fill = el.dataset.default_fill);
current_hovereds.forEach((el, i) => el.style.fill = orderedcolors[i]);
// had a typo
output.textContent = current_hovereds.map(printElement).join(' ');
}
svg.addEventListener('mousemove', hitTest);
svg.addEventListener('touchmove', hitTest);
})();

https://jsfiddle.net/85dv69k3/

最新更新