RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 1404049
Accepted
Alexandr_TT
Alexandr_TT
Asked:2022-06-27 00:08:07 +0000 UTC2022-06-27 00:08:07 +0000 UTC 2022-06-27 00:08:07 +0000 UTC

检测距离 <= 3 像素的 SVG 行的点击

  • 772

这就是我检测 SVG 行点击的方式:

window.onmousedown = (e) => {
    if (e.target.tagName == 'line') {
        alert();  // do something with e.target
    }
}
svg line:hover { cursor: pointer; }
<svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" id="svg">
<line x1="320" y1="160" x2="140" y2="00" stroke="black" stroke-width="2"></line>
<line x1="140" y1="00" x2="180" y2="360" stroke="black" stroke-width="2"></line>
<line x1="180" y1="360" x2="400" y2="260" stroke="black" stroke-width="2"></line>
<line x1="00" y1="140" x2="280" y2="60" stroke="black" stroke-width="2"></line>
</svg>

这仅在鼠标光标正好在线时才有效,这并不容易,所以它是糟糕的用户体验。

如何从 Javascript 中检测对 SVG 线的点击,即使不是完全在线,但距离 <= 3 像素?

问题的免费翻译Detect a click on a SVG line even at 3 pixel by @Basj。

javascript css
  • 2 2 个回答
  • 27 Views

2 个回答

  • Voted
  1. Alexandr_TT
    2022-06-27T00:08:07Z2022-06-27T00:08:07Z

    有点复杂的解决方案,但有效:

    window.onmousedown = (e) => {
        if (e.target.classList.contains('line')) {
            console.log(e.target.href);
        }
    }
    svg .line:hover {
      cursor: pointer;
    }
    .line {
      stroke: black;
      stroke-width: 2px;
    }
    .line.stroke {
      stroke: transparent;
      stroke-width: 6px;
    }
    <svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" id="svg">
        <defs>
          <line id="line1" x1="320" y1="160" x2="140" y2="00"></line>
          <line id="line2" x1="140" y1="00" x2="180" y2="360"></line>
          <line id="line3" x1="180" y1="360" x2="400" y2="260"></line>
          <line id="line4" x1="00" y1="140" x2="280" y2="60"></line>
        </defs>
        <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#line1" class="line stroke"></use>
        <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#line1" class="line"></use>
        <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#line2" class="line stroke"></use>
        <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#line2" class="line"></use>
        <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#line3" class="line stroke"></use>
        <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#line3" class="line"></use>
        <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#line4" class="line stroke"></use>
        <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#line4" class="line"></use>
    </svg>

    来自 @syduki的答案的松散翻译 。

    • 1
  2. Best Answer
    Alexandr_TT
    2022-06-27T00:27:52Z2022-06-27T00:27:52Z

    一个包含一个<line>和几个 JavaScript 的解决方案会很有趣。

    我们可以使用现有的 Web API document.elementFromPoint(x, y)。它返回给定点的最顶层元素。一旦形成用户的点击点,我们就可以导航每个轴并<line>使用该方法找到第一个元素。当我们得到一个字符串或达到最大搜索距离时,我们停止搜索。

    在下面的演示中,没有创建其他元素。可变接近控制与要考虑选择的线的最大距离。额外功能:突出显示最靠近鼠标指针的行。因此,用户可以轻松地单击所需的行而没有任何麻烦。

    const proximity = 8;
    
    const directions = [
      [0, 0],
      [0, 1], [0, -1],
      [1, 1], [-1, -1],
      [1, 0], [-1, 0],
      [-1, 1], [1, -1]
    ];
    
    // tracks nearest line
    let currentLine = null;
    
    // highlight nearest line to mouse pointer
    container.onmousemove = (e) => {
      let line = getNearestLine(e.clientX, e.clientY);
      if (line) {
        if (currentLine !== line)
          currentLine?.classList.remove('highlight');
    
        currentLine = line;
        currentLine.classList.add('highlight');
        container.classList.add('pointer');
      } else {
        currentLine?.classList.remove('highlight');
        currentLine = null;
        container.classList.remove('pointer')
      }
    }
    
    container.onclick = (e) => {
      // we already know in 'onmousemove' which line is the nearest
      // so no need to figure it out again.
      log.textContent = currentLine ? currentLine.textContent : '';
    }
    
    // find a nearest line within 'proximity'
    function getNearestLine(x, y) {
      // move along each axis and see if we land on a line
      for (let i = 1; i <= proximity; i++) {
        for (let j = 0; j < directions.length; j++) {
          const xx = x + directions[j][0] * i;
          const yy = y + directions[j][1] * i;
          const element = document.elementFromPoint(xx, yy);
          if (element?.tagName == 'line')
            return element;
        };
      }
      return null;
    }
    svg {
      background-color: wheat;
    }
    
    .pointer {
      cursor: pointer;
    }
    
    .highlight {
      filter: drop-shadow(0 0 4px black);
    }
    
    #log {
      user-select: none;
    }
    <p>Clicked on: <span id="log"></span></p>
    <svg id='container' width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" id="svg">
        <line x1="320" y1="160" x2="140" y2="00" stroke="red" stroke-width="2">1</line>
        <line x1="140" y1="00" x2="180" y2="360" stroke="green" stroke-width="2">2</line>
        <line x1="18" y1="60" x2="400" y2="60" stroke="orange" stroke-width="2">3</line>
        <line x1="00" y1="140" x2="280" y2="60" stroke="blue" stroke-width="2">4</line>
      </svg>

    这只是一个您可以摆脱的演示代码。如果您不希望手形光标靠近显示,请删除onmousemove并将逻辑移动到onclick. 只能filter: drop-shadow(...)突出显示非方形。否则,您可以更改线条的宽度或颜色等。

    来自 @the Hutt的答案的松散翻译 。

    • 1

相关问题

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    我看不懂措辞

    • 1 个回答
  • Marko Smith

    请求的模块“del”不提供名为“default”的导出

    • 3 个回答
  • Marko Smith

    "!+tab" 在 HTML 的 vs 代码中不起作用

    • 5 个回答
  • Marko Smith

    我正在尝试解决“猜词”的问题。Python

    • 2 个回答
  • Marko Smith

    可以使用哪些命令将当前指针移动到指定的提交而不更改工作目录中的文件?

    • 1 个回答
  • Marko Smith

    Python解析野莓

    • 1 个回答
  • Marko Smith

    问题:“警告:检查最新版本的 pip 时出错。”

    • 2 个回答
  • Marko Smith

    帮助编写一个用值填充变量的循环。解决这个问题

    • 2 个回答
  • Marko Smith

    尽管依赖数组为空,但在渲染上调用了 2 次 useEffect

    • 2 个回答
  • Marko Smith

    数据不通过 Telegram.WebApp.sendData 发送

    • 1 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5