Search code examples
javascriptpixi.jsvivagraphjs

Paint text on the mouse hover on the graphics in the position of cursor


I have a problem when I go to paint the PIXI.Text in the cursor position.

This is the simple demo to reproduce the problem, when you go over the node with the cursor I paint the text, in this case, "@author vincenzopalazzo" but I want the position on the node, so I think for resolving the problem I have got the solution I must set the position of the mouse.

But I don't have an idea got get this position, so this is an example to reproduce the problem with PIXI

//setup Pixi renderer
var renderer = PIXI.autoDetectRenderer(600, 400, {
  backgroundColor: 0x000000
});
document.body.appendChild(renderer.view);

// create new stage
var stage = new PIXI.Container();

// create helpful message
var style = {
  font: '18px Courier, monospace',
  fill: '#ffffff'
};


// create graphic object called circle then draw a circle on it
var circle = new PIXI.Graphics();
circle.lineStyle(5, 0xFFFFFF, 1);
circle.beginFill(0x0000FF, 1);
circle.drawCircle(150, 150, 100);
circle.endFill();
circle.alpha = 0.5;
stage.addChild(circle);

// designate circle as being interactive so it handles events
circle.interactive = true;

// create hit area, needed for interactivity
circle.hitArea = new PIXI.Circle(150, 150, 100);

// make circle non-transparent when mouse is over it
circle.mouseover = function(events) {
    var message = new PIXI.Text('Hover your mouse over the circle to see the effect.', style);
  message.x = events.clientX;
  message.y = events.clientY;
  circle.message = message;
  circle.addChild(message);
}

// make circle half-transparent when mouse leaves
circle.mouseout = function(mouseData) {
  this.alpha = 0.5;
  circle.removeChild(circle.message);
  delete circle.message;
}

// start animating
animate();

function animate() {
  requestAnimationFrame(animate);
  // render the root container
  renderer.render(stage);
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/5.1.4/pixi.js"></script>

This is my real code

   module.exports = function (animatedNode, ctx) {

  ctx.on('hover', function(animatedNode, ctx){
    let x = animatedNode.pos.x;
    let y = - animatedNode.pos.y / 2;
    if(animatedNode.label === undefined){
      animatedNode.label = new PIXI.Text('@author vincenzopalazzo', { fontFamily: "Arial", fontSize: "20px" ,  fill: 0x000000} );
      animatedNode.label.x = x;
      animatedNode.label.y = y + animatedNode.width/2;
      ctx.addChild(animatedNode.label);
    }else{
      animatedNode.label.x = x;
      animatedNode.label.y = y + animatedNode.width/2;
    }
  });

  ctx.on('unhover', function(animatedNode, ctx){
      ctx.removeChild(animatedNode.label);
      delete animatedNode.label;

  });

  ctx.mouseover = function() {
    console.debug('I\'call the hover events');
    this.fire('hover', animatedNode, ctx);
  }

  ctx.mouseout = function() {
    console.debug('I\'call the unhover events');
    this.fire('unhover', animatedNode, ctx);
  }

}

I'm using the ngraph.events on the ctx (it is the PIXI graphics) object, the method on and fire is the module nghraph.events


Solution

  • In your example code (first snippet) the "moseover" handler should be changed from:

    // make circle non-transparent when mouse is over it
    circle.mouseover = function(events) {
        var message = new PIXI.Text('Hover your mouse over the circle to see the effect.', style);
        message.x = events.clientX;
        message.y = events.clientY;
        circle.message = message;
        circle.addChild(message);
    }
    

    to:

        // make circle non-transparent when mouse is over it
        circle.on('mouseover', function(event) {
            // console.log('mouse is over the circle');
            // console.log(event); // see in (for example in Chrome Devtools console) what is inside this variable
    
            var message = new PIXI.Text('Hover your mouse over the circle to see the effect.', style);
            // By looking at what "console.log(event)" shows we can see that instead of:
            // message.x = events.clientX;
            // message.y = events.clientY;
            // should be:
            message.x = event.data.global.x;
            message.y = event.data.global.y;
    
            circle.message = message;
            circle.addChild(message);
        });
    

    To understand it more you can uncomment the "console.log" lines to observe it in your browser devtools console.

    Then we also need to handle 'mouseover' event like this:

        circle.on('mousemove',function (event) {
            if (!circle.message) {
                return;
            }
    
            var newPosition = event.data.getLocalPosition(this.parent);
            circle.message.x = newPosition.x;
            circle.message.y = newPosition.y;
        });
    

    so whole runnable example will be like this:

    //setup Pixi renderer
    var renderer = PIXI.autoDetectRenderer(600, 400, {
      backgroundColor: 0x000000
    });
    document.body.appendChild(renderer.view);
    
    // create new stage
    var stage = new PIXI.Container();
    
    // create helpful message
    var style = {
      font: '18px Courier, monospace',
      fill: '#ffffff'
    };
    
    
    // create graphic object called circle then draw a circle on it
    var circle = new PIXI.Graphics();
    circle.lineStyle(5, 0xFFFFFF, 1);
    circle.beginFill(0x0000FF, 1);
    circle.drawCircle(150, 150, 100);
    circle.endFill();
    circle.alpha = 0.5;
    stage.addChild(circle);
    
    // designate circle as being interactive so it handles events
    circle.interactive = true;
    
    // create hit area, needed for interactivity
    circle.hitArea = new PIXI.Circle(150, 150, 100);
    
    
        // make circle non-transparent when mouse is over it
        circle.on('mouseover', function(event) {
            // console.log('mouse is over the circle');
            // console.log(event); // see in (for example in Chrome Devtools console) what is inside this variable
    
            var message = new PIXI.Text('Hover your mouse over the circle to see the effect.', style);
            // By looking at what "console.log(event)" shows we can see that instead of:
            // message.x = events.clientX;
            // message.y = events.clientY;
            // should be:
            message.x = event.data.global.x;
            message.y = event.data.global.y;
    
            circle.message = message;
            circle.addChild(message);
        });
    
    
        circle.on('mousemove',function (event) {
            if (!circle.message) {
                return;
            }
    
            var newPosition = event.data.getLocalPosition(this.parent);
            circle.message.x = newPosition.x;
            circle.message.y = newPosition.y;
        });
    
    
    // make circle half-transparent when mouse leaves
    circle.mouseout = function(mouseData) {
      this.alpha = 0.5;
      circle.removeChild(circle.message);
      delete circle.message;
    }
    
    // start animating
    animate();
    
    function animate() {
      requestAnimationFrame(animate);
      // render the root container
      renderer.render(stage);
    };
    <script src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/5.1.4/pixi.js"></script>

    Please also see: