Mouse position in SVG and RevealJS
Asked Answered
C

1

9

I'm creating a presentation with RevealJS and would like to incorporate some interactive SVG visualizations created with D3. I've done this without difficulty a number of times before but I'm having some difficulty this time. After a bit of debugging, I've traced the problem to the following: For some reason, the mouse position relative to an SVG is not reported correctly when the whole thing is wrapped inside RevealJS.

My original version of the code used a standard D3 technique to get the mouse position. In an effort to simplify and isolate the problem, though, I eliminated D3 and now use vanilla Javascript to get the mouse position as detailed in this StackOverflow answer. My code (implemented as a stack-snippet) looks like so:

var info =  document.getElementById("info");
var svg =  document.getElementById("svg");
pt = svg.createSVGPoint();
var cursorPoint = function(evt){
  pt.x = evt.clientX; pt.y = evt.clientY;
  return pt.matrixTransform(svg.getScreenCTM().inverse());
}
svg.addEventListener('mousemove',function(evt){
  var loc = cursorPoint(evt);
  info.textContent = "(" + loc.x + ", " + loc.y +   ")";
},false);
svg {
  border: solid black 1px;
  border-radius: 8px;
}
<div id="info">pos</div>
<svg id="svg" width="300" height="200"></svg>

When I run it inside RevealJS in Firefox on my Mac, though, I get very different numbers - as if the coordinates have been shifted by (-423,-321) or some other large negative pair of numbers. I've added a screen shot below to illustrate this. The mouse doesn't appear in the screenshot but is near the upper left corner so that it should read something like (3,5) or some small values like that.

enter image description here

I assume that RevealJS is performing some extra transformation on the SVG, but I can't find it and I'm hoping there's some RevealJS recommended way to deal with this.

There is a full working (well, not actually correctly) version of the RevealJS version here. It's pretty much the exact same code as in the stack-snippet above, but wrapped inside a minimal RevealJS template.


Looking into this more closely still, the issue appears to happen with Firefox but not with Chrome. I'm running current versions of those programs on my 1 year old Macbook Pro. I'd really like some code that works in a wide range of browsers and would certainly want it to run in both Firefox and Chrome.

Centra answered 23/12, 2017 at 1:23 Comment(7)
What you mean by "very different numbers"? I'm getting almost the same thing... actually, I'd not even notice the difference if you just show me the two codes without saying that there is a problem.Quentinquercetin
@GerardoFurtado Good question - thank you. I've edited my post to hopefully be more clear. Your question made me realize that I should check to see how it works in another browser. The problem occurs in Firefox on my Mac but not in Chrome.Centra
That's funny, I'm not getting those negative values... as I said, I'm getting almost the same.Quentinquercetin
@GerardoFurtado You're not getting those negative values using Firefox? Are you on a Mac? Or PC?Centra
I'm on a PC, Windows 7 64bit, Chrome 63. Here is a screenshot, the mouse is almost at the top left corner: snag.gy/rJ0cBF.jpgQuentinquercetin
@GerardoFurtado Yep, that's how it works in Chrome for me as well. It's almost certainly a silly bug. Worse case scenario - I'll just deliver the presentation using Chrome. - thanks for the responses!Centra
Now I see in your edit that you're getting the expected results on Chrome but not on Firefox. Well, funnily enough, sometimes this is a Chrome bug! For instance, this is just a silly example, suppose you had to write "300px" instead of just "300". Chrome is much more forgiving regarding these mistakes, and it will do what we expect as the "normal" result... on the other hand Firefox is more strict, and will throw an error or do something that we think it's a bug.Quentinquercetin
H
5

Notice how elegant it is to create slides animations with CSS tranforms but it is not the most reliable approach for the display as it yields inconsistent results across browsers and I suppose that you're going to do something with those coordinates later and that you may need to have a precise location of the mouse pointer.

You were right something unexpected happened in reveal.js
Basically, with scale and translate the SVG element is shifted downward right and scaled but the coordinates of the pointer are as if your hovering its original position and size area then computed relative to the current layout, hence the negative values, please take a look at the picture.

enter image description here

So I'm removing this line from the layout() function in reveal.js :

transformSlides( { layout: 'translate(-50%, -50%) scale('+ scale +')' } );

that is used to center the element. With one set of statements for both of Firefox and Chrome (no need to check for features.zoom in the layout() function) I want to horizontally center the slide element:

dom.slides.style.left = '0';
dom.slides.style.top = 'auto';
dom.slides.style.bottom = 'auto';
dom.slides.style.right = '0';

Reveal.initialize({});
var info = document.getElementById("info");
var svg = document.getElementById("svg");
pt = svg.createSVGPoint();
var cursorPoint = function(evt) {
  pt.x = evt.clientX;
  pt.y = evt.clientY;
  return pt.matrixTransform(svg.getScreenCTM().inverse());
}
svg.addEventListener('mousemove', function(evt) {
  var loc = cursorPoint(evt);
  info.textContent = "(" + loc.x + ", " + loc.y + ")";
}, false);
svg {
  background-color: white;
  border: solid black 1px;
  border-radius: 8px;
}
<script src="https://cdn.rawgit.com/Nasdav/revealjs-for-SO-answer/b6ea3980/reveal.js"></script>

<script src="https://cdn.rawgit.com/hakimel/reveal.js/master/lib/js/head.min.js"></script>
<link rel="stylesheet" href="https://cdn.rawgit.com/hakimel/reveal.js/65bdccd5807b6dfecad6eb3ea38872436d291e81/css/reveal.css">
<link rel="stylesheet" href="https://cdn.rawgit.com/hakimel/reveal.js/65bdccd5807b6dfecad6eb3ea38872436d291e81/lib/css/zenburn.css">
<link rel="stylesheet" href="https://cdn.rawgit.com/hakimel/reveal.js/65bdccd5807b6dfecad6eb3ea38872436d291e81/css/theme/sky.css" id="theme">

<body>

  <div class="reveal">
    <div class="slides">
      <section>
        <h2 style="font-size:150%">Mouse position in RevealJS</h2>
        <p style="font-size:75%">
          Make sure to click "full page" at the right most side of "Run Code Snippet". Then hover over the SVG below to get the "position" of the mouse in the SVG. The position is obtained using a standard javascript technique and works fine in
          <a href="non_reveal_version.html">this non-reveal version</a>. For some reason though. The values are correct now in Firefox when RevealJS is present. It works well in Chrome, though.
        </p>
        <svg id="svg" width="300" height="200"></svg>
        <div id="info">pos</div>
      </section>
    </div>
  </div>

Problem solved you have a reliable way of getting the coordinates of the mouse pointer consistently accross both Chrome, Firefox and even Internet Explorer in the SVG area from (0,0) to (300,200)

Here, it will be slightly less accurate coordinates if you want the slide to have the same size as the previous one (slightly bigger ) and/or responsive to resizing : In the same place as the previous code, I would let the width and the font size having percentages (I could do so to the SVG itself which is having a fixed size here)

dom.slides.style.width = '90%';
dom.slides.style.fontSize= scale*100+'%';
Holmes answered 27/12, 2017 at 15:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.