如何在 SVG 上模拟文本选择行为

How to simulate text selection behavior on SVG

我有以下 svg 元素,我想允许用户 select 通过鼠标单击和拖动路径,就好像他们在与普通文本交互一样。

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 238.9 39.28" height="75" width="190">

<rect class="opacity-0" x="231.47" width="15.74" height="26"/>
   
   <path d="M119.42,162.67h3.91v27.05h13V193H119.42Z" transform="translate(-119.42 -162.63)"/>
    <path d="M159.6,181.93c0,8.06-5.58,11.57-10.84,11.57-5.9,0-10.44-4.32-10.44-11.21,0-7.29,4.77-11.56,10.8-11.56C155.37,170.73,159.6,175.27,159.6,181.93Zm-17.28.23c0,4.77,2.75,8.36,6.62,8.36s6.61-3.55,6.61-8.45c0-3.69-1.84-8.37-6.52-8.37S142.32,178,142.32,182.16Z" transform="translate(-119.42 -162.63)"/>
    <path d="M164.6,178c0-2.57,0-4.77-.18-6.8h3.46l.14,4.28h.18a6.52,6.52,0,0,1,6-4.77,4.25,4.25,0,0,1,1.12.13v3.74a5.9,5.9,0,0,0-1.35-.14c-2.79,0-4.77,2.12-5.31,5.09a11.14,11.14,0,0,0-.18,1.84V193H164.6Z" transform="translate(-119.42 -162.63)"/>
    <path d="M181.07,182.83c.09,5.36,3.51,7.56,7.47,7.56a14.37,14.37,0,0,0,6-1.12l.67,2.83a17.61,17.61,0,0,1-7.24,1.35c-6.71,0-10.71-4.41-10.71-11s3.87-11.74,10.21-11.74c7.11,0,9,6.25,9,10.26a16,16,0,0,1-.13,1.84ZM192.68,180c0-2.52-1-6.44-5.49-6.44-4,0-5.76,3.69-6.08,6.44Z" transform="translate(-119.42 -162.63)"/>
    <path d="M201.41,177.12c0-2.25,0-4.1-.18-5.9h3.46l.18,3.51H205a7.5,7.5,0,0,1,6.84-4,6.43,6.43,0,0,1,6.16,4.36h.09a9,9,0,0,1,2.43-2.83,7.46,7.46,0,0,1,4.82-1.53c2.88,0,7.15,1.89,7.15,9.45V193h-3.87V180.67c0-4.18-1.53-6.7-4.72-6.7a5.12,5.12,0,0,0-4.68,3.6,6.52,6.52,0,0,0-.32,2V193H215V180c0-3.46-1.53-6-4.54-6a5.41,5.41,0,0,0-4.91,4,5.54,5.54,0,0,0-.31,1.93V193h-3.87Z" transform="translate(-119.42 -162.63)"/>
    <path d="M252.89,165.1a2.46,2.46,0,0,1-4.91,0,2.42,2.42,0,0,1,2.48-2.47A2.35,2.35,0,0,1,252.89,165.1ZM248.48,193V171.22h4V193Z" transform="translate(-119.42 -162.63)"/>
    <path d="M259,178.33c0-2.79-.09-5-.18-7.11h3.55l.18,3.74h.09a8.56,8.56,0,0,1,7.74-4.23c5.27,0,9.23,4.45,9.23,11.07,0,7.82-4.77,11.7-9.9,11.7a7.67,7.67,0,0,1-6.71-3.42h-.09v11.83H259Zm3.91,5.81a9,9,0,0,0,.18,1.62,6.12,6.12,0,0,0,5.94,4.63c4.19,0,6.62-3.42,6.62-8.41,0-4.37-2.3-8.1-6.48-8.1a6.32,6.32,0,0,0-6,4.9,6.69,6.69,0,0,0-.27,1.62Z" transform="translate(-119.42 -162.63)"/>
    <path d="M284.07,189a10.33,10.33,0,0,0,5.22,1.57c2.88,0,4.23-1.44,4.23-3.23s-1.12-2.93-4-4c-3.91-1.39-5.76-3.55-5.76-6.16,0-3.51,2.84-6.39,7.52-6.39a10.85,10.85,0,0,1,5.35,1.35l-1,2.88a8.46,8.46,0,0,0-4.45-1.26c-2.34,0-3.65,1.35-3.65,3,0,1.8,1.31,2.61,4.14,3.69,3.78,1.44,5.72,3.33,5.72,6.57,0,3.82-3,6.52-8.15,6.52a12.33,12.33,0,0,1-6.12-1.49Z" transform="translate(-119.42 -162.63)"/>
    <path d="M320.66,187.06c0,2.25,0,4.23.18,5.94h-3.51l-.23-3.55H317a8.2,8.2,0,0,1-7.2,4.05c-3.42,0-7.51-1.9-7.51-9.54V171.22h4v12.06c0,4.14,1.26,6.93,4.86,6.93a5.72,5.72,0,0,0,5.22-3.6,5.86,5.86,0,0,0,.36-2V171.22h4Z" transform="translate(-119.42 -162.63)"/>
    <path d="M327.23,177.12c0-2.25-.05-4.1-.18-5.9h3.46l.18,3.51h.14a7.5,7.5,0,0,1,6.84-4,6.43,6.43,0,0,1,6.16,4.36h.09a9,9,0,0,1,2.43-2.83,7.46,7.46,0,0,1,4.82-1.53c2.88,0,7.15,1.89,7.15,9.45V193h-3.87V180.67c0-4.18-1.53-6.7-4.72-6.7a5.12,5.12,0,0,0-4.68,3.6,6.52,6.52,0,0,0-.32,2V193h-3.87V180c0-3.46-1.53-6-4.54-6a5.41,5.41,0,0,0-4.91,4,5.54,5.54,0,0,0-.31,1.93V193h-3.87Z" transform="translate(-119.42 -162.63)"/>
</svg>

在下图中,第一行是我select其中一部分的真实文本,第二行是上面svg代码的渲染。

阅读 W3 SVG 1.1 / 16 Interactivity 后,我尝试了一些 JavaScript 方法,但我只能更改 类 和 svg 元素的几个属性。


更新

我正在寻找的行为很简单,一旦用户单击并拖动 svg 的鼠标,我需要显示某种背景。为了实现这个目标,我修改了我的 svg 以添加一个隐藏的矩形,该矩形在 mousedown 事件中显示一次:

<rect class="opacity-0" x="231.47" width="15.74" height="26"/>
window.addEventListener('load', function(e) {
  var verse = document.getElementById('2-6');
  verse.addEventListener('click', (e) => {
    let elements = document.elementsFromPoint(e.clientX, e.clientY);
    for (var i = 0; i < elements.length; i++) {
      if (elements[i].localName === 'rect') {
        elements[i].style.opacity = "0.5"
      }
    }
  });
});

我快到了,但还没有。

在试用 <canvas><rect> 和 javascript 之后,我决定再次尝试 Robert 的 ,效果惊人。

想法是:

  • 为 svg 创建一个同伴 div。
  • svg 放在它上面。
  • 为伴随 div 提供最接近原始字体的属性(即 font-sizetext-alignline-heightfont-family),这样当有人复制文本,你在那里得到一些准确性。
  • 使随播 div 文本颜色 transparent(不透明度不起作用)以显示选择背景而不是所选文本。
  • 最后,SVG 需要其 positionabsolutepointer-eventsnone

这里和那里可能需要几个星期,但只是想分享我要走的路,以防你遇到同样的问题。

.container {
  position: relative;
}

.companion {
  font-size: 2rem;
  text-align: left;
  line-height: 4.2rem;
  padding-right: 1rem;
  color: transparent;
  font-family: sans-serif;
}
  
svg {
  position: absolute;
  pointer-events: none;
}
<div class="container">
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 238.9 39.28" height="75" width=190>
      <path d="M119.42,162.67h3.91v27.05h13V193H119.42Z" transform="translate(-119.42 -162.63)" />
      <path d="M159.6,181.93c0,8.06-5.58,11.57-10.84,11.57-5.9,0-10.44-4.32-10.44-11.21,0-7.29,4.77-11.56,10.8-11.56C155.37,170.73,159.6,175.27,159.6,181.93Zm-17.28.23c0,4.77,2.75,8.36,6.62,8.36s6.61-3.55,6.61-8.45c0-3.69-1.84-8.37-6.52-8.37S142.32,178,142.32,182.16Z" transform="translate(-119.42 -162.63)" />
      <path d="M164.6,178c0-2.57,0-4.77-.18-6.8h3.46l.14,4.28h.18a6.52,6.52,0,0,1,6-4.77,4.25,4.25,0,0,1,1.12.13v3.74a5.9,5.9,0,0,0-1.35-.14c-2.79,0-4.77,2.12-5.31,5.09a11.14,11.14,0,0,0-.18,1.84V193H164.6Z" transform="translate(-119.42 -162.63)" />
      <path d="M181.07,182.83c.09,5.36,3.51,7.56,7.47,7.56a14.37,14.37,0,0,0,6-1.12l.67,2.83a17.61,17.61,0,0,1-7.24,1.35c-6.71,0-10.71-4.41-10.71-11s3.87-11.74,10.21-11.74c7.11,0,9,6.25,9,10.26a16,16,0,0,1-.13,1.84ZM192.68,180c0-2.52-1-6.44-5.49-6.44-4,0-5.76,3.69-6.08,6.44Z" transform="translate(-119.42 -162.63)" />
      <path d="M201.41,177.12c0-2.25,0-4.1-.18-5.9h3.46l.18,3.51H205a7.5,7.5,0,0,1,6.84-4,6.43,6.43,0,0,1,6.16,4.36h.09a9,9,0,0,1,2.43-2.83,7.46,7.46,0,0,1,4.82-1.53c2.88,0,7.15,1.89,7.15,9.45V193h-3.87V180.67c0-4.18-1.53-6.7-4.72-6.7a5.12,5.12,0,0,0-4.68,3.6,6.52,6.52,0,0,0-.32,2V193H215V180c0-3.46-1.53-6-4.54-6a5.41,5.41,0,0,0-4.91,4,5.54,5.54,0,0,0-.31,1.93V193h-3.87Z" transform="translate(-119.42 -162.63)" />
      <path d="M252.89,165.1a2.46,2.46,0,0,1-4.91,0,2.42,2.42,0,0,1,2.48-2.47A2.35,2.35,0,0,1,252.89,165.1ZM248.48,193V171.22h4V193Z" transform="translate(-119.42 -162.63)" />
      <path d="M259,178.33c0-2.79-.09-5-.18-7.11h3.55l.18,3.74h.09a8.56,8.56,0,0,1,7.74-4.23c5.27,0,9.23,4.45,9.23,11.07,0,7.82-4.77,11.7-9.9,11.7a7.67,7.67,0,0,1-6.71-3.42h-.09v11.83H259Zm3.91,5.81a9,9,0,0,0,.18,1.62,6.12,6.12,0,0,0,5.94,4.63c4.19,0,6.62-3.42,6.62-8.41,0-4.37-2.3-8.1-6.48-8.1a6.32,6.32,0,0,0-6,4.9,6.69,6.69,0,0,0-.27,1.62Z" transform="translate(-119.42 -162.63)" />
      <path d="M284.07,189a10.33,10.33,0,0,0,5.22,1.57c2.88,0,4.23-1.44,4.23-3.23s-1.12-2.93-4-4c-3.91-1.39-5.76-3.55-5.76-6.16,0-3.51,2.84-6.39,7.52-6.39a10.85,10.85,0,0,1,5.35,1.35l-1,2.88a8.46,8.46,0,0,0-4.45-1.26c-2.34,0-3.65,1.35-3.65,3,0,1.8,1.31,2.61,4.14,3.69,3.78,1.44,5.72,3.33,5.72,6.57,0,3.82-3,6.52-8.15,6.52a12.33,12.33,0,0,1-6.12-1.49Z" transform="translate(-119.42 -162.63)" />
      <path d="M320.66,187.06c0,2.25,0,4.23.18,5.94h-3.51l-.23-3.55H317a8.2,8.2,0,0,1-7.2,4.05c-3.42,0-7.51-1.9-7.51-9.54V171.22h4v12.06c0,4.14,1.26,6.93,4.86,6.93a5.72,5.72,0,0,0,5.22-3.6,5.86,5.86,0,0,0,.36-2V171.22h4Z" transform="translate(-119.42 -162.63)" />
      <path d="M327.23,177.12c0-2.25-.05-4.1-.18-5.9h3.46l.18,3.51h.14a7.5,7.5,0,0,1,6.84-4,6.43,6.43,0,0,1,6.16,4.36h.09a9,9,0,0,1,2.43-2.83,7.46,7.46,0,0,1,4.82-1.53c2.88,0,7.15,1.89,7.15,9.45V193h-3.87V180.67c0-4.18-1.53-6.7-4.72-6.7a5.12,5.12,0,0,0-4.68,3.6,6.52,6.52,0,0,0-.32,2V193h-3.87V180c0-3.46-1.53-6-4.54-6a5.41,5.41,0,0,0-4.91,4,5.54,5.54,0,0,0-.31,1.93V193h-3.87Z" transform="translate(-119.42 -162.63)" />
    </svg>
  <div class="companion">Lorem ipsum</div>
</div>