0

I want to display a moving cross hairs with coordinates when the cursor is moved over a particular DIV containing an SVG.

On mouseenter I can successfully create a rect displaying the coordinates (and remove it on mouseout), however, moving the cursor over the newly created rect or text itself fires a mouseout mouseenter event cycle.

I've tried d3.event.stopPropagation() in several places, but none seem to work.

The picture shows if you carefully move the mouse onto the grey "screen" - the rect & text is created and stays in one place.

But if you move the cursor to touch "bobo" or the green rectangle, it starts moving.

enter image description here

var infoBox = null;

var theSVG = d3.select("#theScreen")
  .append("svg")
  .attr("width", 250)
  .attr("height", 250);

// Register mouse events
theSVG
  .on("mouseenter", mouseEnter)
  .on("mouseout",   mouseExit);

function mouseEnter()
{
    if (infoBox !== null)
      return;

  var coord = d3.mouse(d3.event.currentTarget);
  x1 = parseInt(coord[0]);
  y1 = parseInt(coord[1]);

  console.log("mouseEnter", x1, y1, infoBox);

  infoBox = theSVG.append("g")
    .attr('class', 'ssInfoBox');

  var rectItem = infoBox.append("rect")
  .attr('x', x1)
  .attr('y', y1)
  .attr('width',  30)
  .attr('height', 20);

  var textItem = infoBox.append("text")
  .attr('x', x1)
  .attr('y', y1)
  .text("bobo");
}

function mouseExit()
{
    if (infoBox === null)
    return;

    console.log("mouseExit", infoBox);
  infoBox.remove()
  infoBox = null;
}

The code doesn't implement the moving yet. To start, I just want the rect/text created and destroyed on mouseenter and mouseout.

How do I do that?

Link to Fiddle.

Gerardo Furtado
  • 100,839
  • 9
  • 121
  • 171
Danny
  • 2,482
  • 3
  • 34
  • 48

2 Answers2

0

You may create transparent div or any other tag on top of your svg with same size. Than handle mouse events of this overlay. This way you will not going be interrupted by internal components events. Downside - you will have to handle interaction with internals manually.

Like so:

<svg style="z-index:1;position:absolute;left:0;width:200px;top:0;height:200px">...</svg>

<div id="overlay" style="background:rgba(0,0,0,0);z-index:2;position:absolute;left:0;width:200px;top:0;height:200px"></div>
Oleg Imanilov
  • 2,591
  • 1
  • 13
  • 26
0

Instead of mouseout, use mouseleave.

The MDN has a good explanation about the differences between them: https://developer.mozilla.org/en-US/docs/Web/API/Element/mouseleave_event

And here is your code with that change only:

var infoBox = null;

var theSVG = d3.select("#theScreen")
  .append("svg")
  .attr("width", 250)
  .attr("height", 250);

// Register mouse events
theSVG
  .on("mouseenter", mouseEnter)
  .on("mouseleave", mouseExit);

function mouseEnter() {
  if (infoBox !== null)
    return;

  var coord = d3.mouse(d3.event.currentTarget);
  x1 = parseInt(coord[0]);
  y1 = parseInt(coord[1]);

  console.log("mouseEnter", x1, y1, infoBox);

  infoBox = theSVG.append("g")
    .attr('class', 'ssInfoBox');

  var rectItem = infoBox.append("rect")
    .attr('x', x1)
    .attr('y', y1)
    .attr('width', 30)
    .attr('height', 20);

  var textItem = infoBox.append("text")
    .attr('x', x1)
    .attr('y', y1)
    .text("bobo");
}

function mouseExit() {
  if (infoBox === null)
    return;

  console.log("mouseExit", infoBox);
  infoBox.remove()
  infoBox = null;
}
#container {
  width: 400px;
  height: 400px;
  background-color: #0BB;
}

#theScreen {
  position: absolute;
  top: 50px;
  left: 50px;
  width: 250px;
  height: 250px;
  background-color: #333;
  cursor: crosshair;
}

.ssInfoBox rect {
  fill: #383;
}

.ssInfoBox text {
  fill: white;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script>
<div id='container'>
  <div id='theScreen'>
  </div>
</div>
Gerardo Furtado
  • 100,839
  • 9
  • 121
  • 171