-1

I try to use tippy in an object SVG tag text, but when I hover the text tag I receive this error:
Uncaught TypeError: Cannot read properties of null (reading 'body')

I try also to append on a document.body but doesn't solve a problem.

how can i display the tooltip in an object svg text?

// error message
    getScrollParent.js:8 Uncaught TypeError: Cannot read properties of null (reading 'body')
        at getScrollParent (getScrollParent.js:8:1)
        at getScrollParent (getScrollParent.js:15:1)
        at getScrollParent (getScrollParent.js:15:1)
        at listScrollParents (listScrollParents.js:19:37)
        at Object.setOptions (createPopper.js:69:120)
        at createPopper (createPopper.js:215:1)
        at createPopperInstance (tippy.esm.js:1167:43)
        at mount (tippy.esm.js:1204:1)
        at Object.show (tippy.esm.js:1450:1)
        at scheduleShow (tippy.esm.js:1240:1)
<!DOCTYPE html>
<html lang="en-us">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width">
    <link
rel="stylesheet"
href="https://unpkg.com/tippy.js@6/animations/scale.css"
/>
<script src="https://unpkg.com/@popperjs/core@2"></script>
<script src="https://unpkg.com/tippy.js@6"></script>
  </head>
  <body>
    <div class="container">
     <object id="svgObject" class="atac-svg-tranlator" data="./src/assets/images/test.svg" type="image/svg+xml" width="800" height="1100"></object>
    </div>
     
    <script>
      document.addEventListener('DOMContentLoaded', function() {
      const svgObject = document.getElementById('svgObject'); // Select the <object> element
    
      svgObject.addEventListener('load', function() {
        const svgDoc = svgObject.contentDocument; // Get the SVG document from the object element
        
        if (svgDoc) {
          // Find and initialize tooltips for text elements within the SVG
          const textElements = svgDoc.querySelectorAll('text');
          textElements.forEach(function(textElement) {
            // Create Tippy tooltip for each text element
            tippy(textElement, {
              content: textElement.textContent,
              appendTo: svgDoc.documentElement,
              placement: 'top', 
              
            });
          });
        } else {
          console.log('SVG document not loaded');
        }
      });
    
      // Optionally, you can add further code here
    });
    </script>
  </body>
</html>

The svg inside file it is simple like this:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>

<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="500" height="1100">
            <text x="50" y="50">ciao come</text>
            <text x="70" y="80">test test testo 3</text>
            <text x="30" y="130">origin pixels size off jira</text>
            <text x="90" y="160">svg body testo 4</text>
            <text x="50" y="180">lorem ipsum testo 5</text>
            <text x="80" y="210">silente testo 3</text>
          </svg>
corsaro
  • 731
  • 1
  • 9
  • 24

1 Answers1

0

After I tried a few things, it seemed impossible to do that with the tippy.js.

I think tippy.js may not support this usage.

But there are still many ways to realize a custom tooltip.

solution 1

Outside the SVG create an absolute position div as a tooltip container, and add the mouse event listener on SVG texts dynamic set its content to the tooltip.

<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">

<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
  <text x="0" y="15" fill="red" id="red1">I love SVG</text>
  <text x="10" y="25" fill="green" id="green2">I love SVG 2</text>
</svg>

PS: The ./texts.svg file must be run on a server without CORS issues.

<!DOCTYPE html>
<html lang="zh-Hans">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <meta name="author" content="xgqfrms">
    <meta name="generator" content="VS code">
    <script src="https://unpkg.com/@popperjs/core@2"></script>
    <script src="https://unpkg.com/tippy.js@6"></script>
    <style lang="css">
      #tip {
        position: absolute;
        top: 0;
        left: 0;
        background: #000;
        color: #0f0;
      }
      #svgObject {
        margin-top: 100px;
        margin-left: 100px;
      }
    </style>
  </head>
  <body>
    <div class="container">
      <div id="tip">
        <span id="hack"></span>
      </div>
      <object id="svgObject" class="atac-svg-tranlator" data="./texts.svg" type="image/svg+xml" width="400" height="300"></object>
    </div>
    <footer>
      <p>copyright&copy; xgqfrms 2023</p>
    </footer>
    <script>
      window.addEventListener("load", (event) => {
        const body = document.body;
        const tip = document.getElementById('tip');
        const svgObject = document.getElementById('svgObject');
        const svgDoc = svgObject.contentDocument.querySelector("svg")
        if (svgDoc) {
          const textElements = svgDoc.querySelectorAll('text');
          textElements.forEach(function(textElement) {
            const text = textElement.textContent
            textElement.addEventListener('mouseleave', (event) => {
              tip.innerHTML = `<span id="hack"></span>`
              tip.setAttribute(`style`, `top: 0px; left: 0px;`)
            })
            textElement.addEventListener('mouseenter', (event) => {
              const y = event.screenY - event.clientY - 80
              const x = event.screenX - event.clientX + 18
              tip.innerHTML = `<span id="hack">${text}</span>`
              tip.setAttribute(`style`, `top: ${y}px; left: ${x}px;`)
              // title property not work ❌
              textElement.setAttribute('title', text);
              textElement.setAttribute('style', `cursor: pointer;`);
            })
            textElement.addEventListener('click', (event) => {
              console.log(`click`, event)
            })
            // tippy(textElement, {
            //   content: text,
            //   placement: 'top',
            // });
            // Bug reproduction steps, the mouse hovers over the svg text
            // ❌ core@2:5 Uncaught TypeError: Cannot read properties of null (reading 'body')
            // https://atomiks.github.io/tippyjs/
            // https://github.com/atomiks/tippyjs/issues/1137
          });
        } else {
          console.log('SVG document not loaded');
        }
      });
    </script>
  </body>
</html>

enter image description here

solution 2

Add the mouse event listener on SVG texts, then dynamic create an SVG <Title> tag, and insert it into SVG with text content.

Text in a <title> element is not rendered as part of the graphic, but browsers usually display it as a tooltip.

<!DOCTYPE html>
<html lang="zh-Hans">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <meta name="author" content="xgqfrms">
  <meta name="generator" content="VS code">
  <script src="https://unpkg.com/@popperjs/core@2"></script>
  <script src="https://unpkg.com/tippy.js@6"></script>
  <style lang="css">
    #svgObject {
      margin-top: 100px;
      margin-left: 100px;
    }
  </style>
</head>
<body>
  <div class="container">
    <object id="svgObject" class="atac-svg-tranlator" data="./texts.svg" type="image/svg+xml" width="400" height="300"></object>
  </div>
  <footer>
    <p>copyright&copy; xgqfrms 2023</p>
  </footer>
  <script>
    window.addEventListener("load", (event) => {
      const body = document.body;
      const svgObject = document.getElementById('svgObject');
      const svgDoc = svgObject.contentDocument.querySelector("svg")
      if (svgDoc) {
        const textElements = svgDoc.querySelectorAll('text');
        textElements.forEach(function(textElement) {
          const text = textElement.textContent
          textElement.setAttribute('style', `cursor: pointer;`);
          textElement.addEventListener('mouseenter', (event) => {
            if(!textElement.children.length) {
              textElement.insertAdjacentHTML(`beforeend`, `<title>${text}</title>`)
            }
          })
          // tippy(textElement, {
          //   content: text,
          //   placement: 'top',
          // });
          // Bug reproduction steps, the mouse hovers over the svg text
          // ❌ core@2:5 Uncaught TypeError: Cannot read properties of null (reading 'body')
          // https://atomiks.github.io/tippyjs/
          // https://github.com/atomiks/tippyjs/issues/1137
        });
      } else {
        console.log('SVG document not loaded');
      }
    });
  </script>
</body>
</html>

enter image description here

refs

https://developer.mozilla.org/en-US/docs/Web/SVG/Element/title

xgqfrms
  • 10,077
  • 1
  • 69
  • 68