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

Javascript 将document.elementsFromPoint(x,y)仅限制为SVG id,并按id打印元素列表,javascript,html,css,svg,Javascript,Html,Css,Svg,如何使document.elementsFromPoint(x,y)仅返回SVG中的元素? 如何仅获取SVG元素列表,并仅对这些SVG元素应用悬停更改 最后,这将覆盖在一个具有数千个点的非常大的SVG上。有没有更有效的方法只在鼠标悬停时应用颜色更改,并在鼠标移动时删除这些元素的颜色更改?(fiddle中的方法将其应用于所有SVG元素,这意味着在包含更多元素的文档上每移动一次鼠标,就会发生数千次更改) 在这段代码中,我在这段代码中尝试了svg.elementsFromPoint(x,y)。 我正在

如何使document.elementsFromPoint(x,y)仅返回SVG中的元素?
如何仅获取SVG元素列表,并仅对这些SVG元素应用悬停更改

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

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

(函数(){
const svg=document.querySelector(“#Shapes”),
输出=document.querySelector(“#test”);
函数printElement(elm){
var id=elm.id?'id=“”+elm.id+”:“”;
返回“”;
}
var shapes=svg.querySelectorAll(“椭圆、矩形、多边形”);
形状。forEach((el)=>{
el.dataset.default_fill=“rgba(0,0,0,0)”;
el.style.fill=el.dataset.default\u fill;
} );
功能测试(e){
常数x=e.clientX,
y=e.clientY,
当前\u hovereds=document.elementsFromPoint(x,y);
shapes.forEach((el)=>el.style.fill=el.dataset.default\u fill);
var OrderedColor=[“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.01)”;
当前_hovereds.forEach((el,i)=>el.style.fill=OrderedColor[i]);
//无法打印元素
output.textContext=current_hovereds.map(printElement).join(“”);
}
addEventListener('mousemove',hitTest);
svg.addEventListener('touchmove',hitTest);
})();

从你的小提琴上我可以看出,你的目标不是
元素的子元素,而是可以用
填充
属性着色的元素。它们有共同的基类,
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

您已经有了所有要定位的
形状的列表,只需过滤掉
文档的结果。元素从
指向此
形状
列表中的那些

(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);
})();
(函数(){
const svg=document.querySelector(“#Shapes”);
const output=document.querySelector(“#test”);
函数printElement(elm){
var id=elm.id?'id=“”+elm.id+”:“”;
返回“”;
}
//转换为数组以便于过滤
constshapes=[…svg.querySelectorAll('eliple,rect,polygon');
形状。forEach((el)=>{
el.dataset.default_fill=“rgba(0,0,0,0)”;
el.style.fill=el.dataset.default\u fill;
});
功能测试(e){
常量有序颜色=[“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.2)”,“rgba(0,0,0.1)”,“rgba(0,0,0.01)”;
常数x=e.clientX;
常数y=e.clientY;
const current\u hovereds=document.elementsFromPoint(x,y)
//只保留我们的形状
.filter(el=>shapes.includes(el));
shapes.forEach((el)=>el.style.fill=el.dataset.default\u fill);
当前_hovereds.forEach((el,i)=>el.style.fill=OrderedColor[i]);
//有个打字错误
output.textContent=current_hovereds.map(printElement).join(“”);
}
addEventListener('mousemove',hitTest);
svg.addEventListener('touchmove',hitTest);
})();

非常感谢!这两种回答都非常有用。这似乎仍然适用于所有形状的填充。。不仅仅是当前的_悬停,当有数千个点时可能会导致性能问题?在函数末尾将当前的悬停项存储为最后一个悬停项有意义吗?下次函数运行时,请检查上次悬停是否包含数据并清除上次悬停上的填充?这样,每次鼠标移动都不会改变数千个元素……非常感谢!这两种回答都非常有用。这似乎仍然适用于所有形状的填充。。不仅仅是当前的_悬停,当有数千个点时可能会导致性能问题?在函数末尾将当前的悬停项存储为最后一个悬停项有意义吗?下次函数运行时,请检查上次悬停是否包含数据并清除上次悬停上的填充?这样,每次鼠标移动都不会改变数千个元素……更改为相同的值不会有任何效果,所以您应该很好,唯一的事情就是在所有这些元素上循环(但数千个应该仍然可以)。如果您面临性能问题,那么是的,您可以存储以前悬停的问题,并且只在这些问题上循环。谢谢您--我必须这样做吗?将数据存储在控制台中并不断更新控制台?这在移动设备上仍然有效吗?是的,只是将其保持在一个变量中,是的。
(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);
})();