Intro.js: Bug: Doesn't work with SVG

Created on 21 Mar 2013  Â·  17Comments  Â·  Source: usablica/intro.js

I'm developing a site where the navigation is entirely drawn in SVG.

I have tried including the intro.js elements in my a tags, in my tags, and surrounding them with divs, to no avail. Each time, the intro text loads in the upper left corner.

I have pushed an example of this to http://gendale.net

More Info Edit: I made gendale call intro.js onload. The script is still aware the location of the SVG element -- it scrolls down to the bottom of the page. The tooltip, however, still loads in the top left of the page. Perhaps the ability to set the origin of the tooltip would be a simple fix for this?

bug

Most helpful comment

Why is this closed? This is not fixed in 2.3.0

All 17 comments

I can't see your example, could you please send me a correct link?

You can type introJs().start(); in developer console to fire up intro, I think.

Ok, let me see

Yeah, correct. This problem occurred when you want to use IntroJs with SVG elements. I just marked this issue as bug so I think we'll fix it for next version.

Thanks for report.

I noticed this problem too -- it's possible to use d3 to inject the tags as follows:

    d3.select("#my-svg-element-id")
        .attr("data-intro", "text")
        .attr("data-step", "1")
        .attr("data-position", "top");

but there are a couple of problems with this:

  1. The box that is drawn occludes the element I'm annotating.
  2. The box position doesn't take into account any svg transforms that may be present.

any news about it ? Using introJS with SVG (d3.js) would be awesome !

@dsalvanha I've forked this and added tentative SVG support. I just threw this up now, so I haven't had a chance to really test it, though it works fine for me in Chrome. https://github.com/bearoplane/intro.js

Bear in mind, my solution is less than ideal. It just creates a placeholder div with the contents of the SVG. It was the quickest, easiest solution for what I needed.

Hi,
I tried making the patch to this problem just for myself.

--- intro.js.v0.8.0 2014-03-26 21:26:55 +0900
+++ intro.js    2014-03-26 21:25:26 +0900
@@ -346,14 +346,14 @@
     //remove `introjs-showElement` class from the element
     var showElement = document.querySelector('.introjs-showElement');
     if (showElement) {
-      showElement.className = showElement.className.replace(/introjs-[a-zA-Z]+/g, '').replace(/^\s+|\s+$/g, ''); // This is a manual trim.
+      removeClass( showElement, new RegExp('introjs-[a-zA-Z]+', 'g') );
     }

     //remove `introjs-fixParent` class from the elements
     var fixParents = document.querySelectorAll('.introjs-fixParent');
     if (fixParents && fixParents.length > 0) {
       for (var i = fixParents.length - 1; i >= 0; i--) {
-        fixParents[i].className = fixParents[i].className.replace(/introjs-fixParent/g, '').replace(/^\s+|\s+$/g, '');
+        removeClass( fixParents[i], new RegExp('introjs-fixParent', 'g') );
       };
     }

@@ -527,13 +527,16 @@
       var fixParents = document.querySelectorAll('.introjs-fixParent');
       if (fixParents && fixParents.length > 0) {
         for (var i = fixParents.length - 1; i >= 0; i--) {
-          fixParents[i].className = fixParents[i].className.replace(/introjs-fixParent/g, '').replace(/^\s+|\s+$/g, '');
+            removeClass(fixParents[i], RegExp('introjs-fixParent', 'g'));
         };
       }

       //remove old classes
       var oldShowElement = document.querySelector('.introjs-showElement');
-      oldShowElement.className = oldShowElement.className.replace(/introjs-[a-zA-Z]+/g, '').replace(/^\s+|\s+$/g, '');
+      if( oldShowElement )
+      {
+          removeClass(oldShowElement, new RegExp('introjs-[a-zA-Z]+', 'g'));
+      }
       //we should wait until the CSS3 transition is competed (it's 0.3 sec) to prevent incorrect `height` and `width` calculation
       if (self._lastShowElementTimer) {
         clearTimeout(self._lastShowElementTimer);
@@ -699,13 +702,13 @@
     nextTooltipButton.focus();

     //add target element position style
-    targetElement.element.className += ' introjs-showElement';
+    appendClass( targetElement.element, 'introjs-showElement' );

     var currentElementPosition = _getPropValue(targetElement.element, 'position');
     if (currentElementPosition !== 'absolute' &&
         currentElementPosition !== 'relative') {
       //change to new intro item
-      targetElement.element.className += ' introjs-relativePosition';
+      appendClass( targetElement.element, 'introjs-relativePosition' );
     }

     var parentElm = targetElement.element.parentNode;
@@ -717,7 +720,7 @@
       var zIndex = _getPropValue(parentElm, 'z-index');
       var opacity = parseFloat(_getPropValue(parentElm, 'opacity'));
       if (/[0-9]+/.test(zIndex) || opacity < 1) {
-        parentElm.className += ' introjs-fixParent';
+        appendClass( parentElm, 'introjs-fixParent' );
       }

       parentElm = parentElm.parentNode;
@@ -744,6 +747,20 @@
     }
   }

+  function appendClass(element, classname) {
+      var c = element.getAttribute('class');
+      if( !c ){ c = ''; }
+      element.setAttribute( 'class', c + ' ' + classname );
+  }
+
+  function removeClass(element, reg) {
+      var c = element.getAttribute('class');
+      if( c ){
+          c = c.replace(reg, '').replace(/^\s+|\s+$/g, '');
+          element.setAttribute( 'class', c );
+      }
+  }
+
   /**
    * Get an element CSS property on the page
    * Thanks to JavaScript Kit: http://www.javascriptkit.com/dhtmltutors/dhtmlcascade4.shtml
@@ -865,26 +882,18 @@
    */
   function _getOffset(element) {
     var elementPosition = {};
-
+    var bounds = element.getBoundingClientRect();
     //set width
-    elementPosition.width = element.offsetWidth;
+    elementPosition.width = bounds.width;

     //set height
-    elementPosition.height = element.offsetHeight;
+    elementPosition.height = bounds.height;

-    //calculate element top and left
-    var _x = 0;
-    var _y = 0;
-    while (element && !isNaN(element.offsetLeft) && !isNaN(element.offsetTop)) {
-      _x += element.offsetLeft;
-      _y += element.offsetTop;
-      element = element.offsetParent;
-    }
     //set top
-    elementPosition.top = _y;
+    elementPosition.top = bounds.top;
     //set left
-    elementPosition.left = _x;
-
+    elementPosition.left = bounds.left;
     return elementPosition;
   }

Do we have any news on this one? Is it fixed?

Why is this closed? This is not fixed in 2.3.0

I also tested 2.3.0 – this is not fixed!

Doesn't work for me too.
Any news with this issue?

Hey guys, sorry for closing this I thought we have solved this. I'm working on a workaround to fix the issue but please note that it's not possible to add z-index to elements inside an SVG but I have tested something with D3 and looks like it's working fine. Screenshot attached.
screen shot 2016-12-15 at 22 10 29

I'm hoping to finish it in next few days.

Ok guys, I have pushed a testing for SVG support here: https://github.com/usablica/intro.js/commit/66b2f1a18ba143eca593fc4f05e1b5861f0d5cce

Could you please confirm if it's working fine? Thanks.

I have tested the svg fix and everything seems to be working fine now in my project. When can we expect a release for this ?

Thanks for adding SVG support! Should SVG elements also work programmatically? (I've tried but it doesn't seem to work)

Does intro js work for svg elements now in production version ?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ghost picture ghost  Â·  7Comments

janroesner picture janroesner  Â·  6Comments

msqar picture msqar  Â·  6Comments

stephendeo picture stephendeo  Â·  5Comments

cssagogo picture cssagogo  Â·  4Comments