Home > front end >  How to simulate text selection behavior on SVG
How to simulate text selection behavior on SVG

Time:04-17

I have the following svg element, and I'd like to allow the user to select paths on mouse click and drag just as if they're interacting with a normal text.

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

<rect  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>

In the following image, the first line is real text I'm selecting part of it, the second line is the rendering of the svg code above.

enter image description here

I've tried few JavaScripts approaches after reading W3 SVG 1.1 / 16 Interactivity, but I was only able to change classes and few attributes of the svg element.


Update

The behavior I'm looking for is simple, once the use clicks and drags the mouse of the svg, I need to show a background of some kind. To achieve this goal, I modified my svg to a add a hidden rectangle that gets displayed once on mousedown event:

<rect  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"
      }
    }
  });
});

I'm almost there, but not yet.

CodePudding user response:

After playing around with <canvas>, <rect> and javascript, I've decided to give Robert's suggestion another try which amazingly worked.

The idea is to:

  • Create a companion div to the svg.
  • Position the svg on top of it.
  • Give that companion div the closest attributes to the original font (i.e. font-size, text-align, line-height, and font-family) so that when someone copies the text, you get some accuracy there.
  • Make the companion div text color transparent (Opacity won't work) to show the selection background but not the selected text.
  • Finally, the SVG needs its position to be absolute and pointer-events to be none.

Few weeks here and there might be needed, but just wanted to share the path that I'm going with in case you face the same problem.

.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 >
  <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 >Lorem ipsum</div>
</div>

  • Related