iamjazzar
iamjazzar

Reputation: 201

How to simulate text selection behavior on SVG

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

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

I'm almost there, but not yet.

Upvotes: 2

Views: 763

Answers (1)

iamjazzar
iamjazzar

Reputation: 201

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

Upvotes: 1

Related Questions