【问题标题】:SVG element bounding box covering elementsSVG元素边界框覆盖元素
【发布时间】:2018-02-09 04:24:51
【问题描述】:

我遇到了 SVG 的透明部分仍然覆盖其下方对象的鼠标事件的问题。 jsFiddle here 显示了一个非常简化的示例。起初我认为这是所有项目都是单独的 SVG 元素的问题,这些元素嵌入了 object 标记,但即使使用内联元素,这个问题似乎也会弹出,例如页面中的示例。

如果您将鼠标悬停在任一圆圈上,指针会根据需要更改,但如果您将鼠标悬停在红色圆圈的边界框重叠的蓝色圆圈上,您将失去指针交互。

我正在尝试找到一种简单的方法来让这些通过。我听说使用 css pointer-events 属性可以解决这个问题,但如果我将它放在任何更高的元素上,如 'none' 它似乎也会删除所有子事件。

这里是代码 sn-p,以防你不想检查 jsFiddle。

// Get all svgs
var svgElems = document.getElementsByTagName("svg");

// loop the list
for (let svgElem of svgElems) {
  // grab the first group element inside
  var gElem = svgElem.getElementsByTagName("g")[0];

  // set the style for the cursor to a pointer
  gElem.style.cursor = 'pointer';
}
svg {
  outline: 1px solid black;
}
<div class="interaction-spot" style="position: absolute; width: 50%; top: 5%; left:10%; z-index:5">
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 164 164">
    <defs>
      <style>.cls-1{fill:#030093;}</style>
    </defs>
    <title>blue</title>
    <g id="Layer_2" data-name="Layer 2">
      <g id="Layer_1-2" data-name="Layer 1">
        <circle class="cls-1" cx="82" cy="82" r="82"/>
      </g>
    </g>
  </svg>
</div>

<div class="interaction-spot" style="position: absolute; width: 50%; top: 5%; left:25%; z-index:5">
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 164 164">
    <defs>
      <style>.cls-2{fill:#af0000;}</style>
    </defs>
    <title>red</title>
    <g id="Layer_2" data-name="Layer 2">
      <g id="Layer_1-2" data-name="Layer 1">
        <circle class="cls-2" cx="82" cy="82" r="82"/>
      </g>
    </g>
  </svg>
</div>

【问题讨论】:

    标签: javascript html css svg


    【解决方案1】:

    您可以在容器上设置指针事件:无,并在内部元素中重置它

    // Get all svgs
    var svgElems = document.getElementsByTagName("svg");
    
    // loop the list
    for (let svgElem of svgElems) {
      // grab the first group element inside
      var gElem = svgElem.getElementsByTagName("g")[0];
    
      // set the style for the cursor to a pointer
      gElem.style.cursor = 'pointer';
    }
    svg {
      outline: 1px solid black;
    }
    
    .interaction-spot {
        pointer-events: none;
    }
    
    
    #Layer_1-2 {
        pointer-events: auto;
    }
    <div class="interaction-spot" style="position: absolute; width: 50%; top: 5%; left:10%; z-index:5">
      <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 164 164">
        <defs>
          <style>.cls-1{fill:#030093;}</style>
        </defs>
        <title>blue</title>
        <g id="Layer_2" data-name="Layer 2">
          <g id="Layer_1-2" data-name="Layer 1">
            <circle class="cls-1" cx="82" cy="82" r="82"/>
          </g>
        </g>
      </svg>
    </div>
    
    <div id="red" class="interaction-spot" style="position: absolute; width: 50%; top: 5%; left:25%; z-index:5">
      <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 164 164">
        <defs>
          <style>.cls-2{fill:#af0000;}</style>
        </defs>
        <title>red</title>
        <g id="Layer_2" data-name="Layer 2">
          <g id="Layer_1-2" data-name="Layer 1">
            <circle class="cls-2" cx="82" cy="82" r="82"/>
          </g>
        </g>
      </svg>
    </div>

    【讨论】:

    • 我认为这实际上是更好的选择,因为我不必为我需要的项目的最终仓库中的每个对象生成和保存剪辑路径掩码。我想我没有意识到您需要重置顶部下方的交互。
    • @BeauSeverson 你是对的。我已将选择器更改为类,现在我们有了想要的确切行为。 (以及更清洁的解决方案)
    • 我想在这里添加一个注释。如果您使用使用 SVG 的 Object embed 方法放置的 SVG,则此功能不适用。我可以将pointer-events 应用于 SVG 内的任何元素,但是如果我从包含文档和所有 SVG 元素的对象标签中删除事件,它似乎不会让任何悬停事件再通过它产生涟漪。
    • 使用 Object 创建一种影子 dom ......你不能用 CSS(通常)达到它,但你可以用内联样式。见这里css-tricks.com/using-svg
    【解决方案2】:

    你可以使用clip-path:

    .interaction-spot {
      clip-path: circle(50%);
    }
    

    jsFiddle

    【讨论】:

    • 我看了你的 jsFiddle,我很惊讶剪辑路径的圆圈比 svg 的圆圈大 20px。我将背景设置为黑色,它使它更明显。 circle(50%) 匹配得更好......奇怪
    • @TheCrzyMan 我没有太在意尺寸,因为 svg 的宽度和高度可能与 viewBox 的值不同。感谢您指出这一点,现已更新。
    【解决方案3】:

    您实际上可以为 SVG 中的各个元素分配一个 ID —— 只需在编辑器中打开 SVG 以访问 SVG DOM 并将 id="someelement" 添加到您想要通过的任何元素,然后重新保存 SVG。然后,您可以将 pointer-events:none 应用到您希望通过点击传递的特定元素,只需定位 ID。

    svg#someelement, svg#sometherelement, svg#yetanotherelement{
        pointer-events:none;
    }
    

    【讨论】:

    • 问题是我需要通过的是SVG元素的边界框。出于某种原因,即使我只在 SVG 内的特定元素上放置了一个事件,所以指针只有在悬停在该元素上时才会触发,SVG 标签本身的边界框似乎仍然覆盖它下面的任何 HTML 元素。
    猜你喜欢
    • 2012-04-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多