web-dev-qa-db-fra.com

Afficher une info-bulle dans un graphique

J'utilise l'élément canvas html5 pour dessiner un graphique avec des points indiquant différents points dansici.

Je souhaite afficher différentes info-bulles sur différents points du survol de la souris. Le texte à afficher en tant qu'info-bulle sera fourni par l'utilisateur.

J'ai essayé, mais je ne savais pas comment ajouter une info-bulle à différents points du graphique. Le code que j'utilise pour afficher les points est ..

// Draw the dots
c.fillStyle = '#333';

for (var i = 0; i < data.values.length; i++) {
  c.beginPath();
  c.arc(getXPixel(data.values[i].X), getYPixel(data.values[i].Y), 4, 0, Math.PI * 2, true);
  c.fill();
}

Que dois-je ajouter dans ce code pour pouvoir afficher les entrées de l'utilisateur sous forme d'info-bulle?

11
Lucy

Vous pouvez afficher des info-bulles lorsque votre utilisateur passe au-dessus du point de données de votre graphique

Cette info-bulle est simplement un deuxième canevas qui tire le texte de la zone de texte liée et se positionne au-dessus du point de données.

Tout d'abord, vous créez un tableau contenant les informations de l'info-bulle pour chacun de vos points de données. 

    var dots = [];

Pour chaque info-bulle, vous aurez besoin de:

  • La coordonnée x/y du point de données,
  • Le rayon du point de données,
  • L'identifiant de la zone de texte à partir de laquelle vous souhaitez obtenir le conseil.
  • Vous avez également besoin de rXr qui a toujours == rayon sur carré (nécessaire lors du test de frappe)

Voici le code pour la création d'informations d'info-bulle à stocker dans des points []

    // define tooltips for each data point

    for(var i = 0; i < data.values.length; i ++) {
        dots.Push({
            x: getXPixel(data.values[i].X),
            y: getYPixel(data.values[i].Y),
            r: 4,
            rXr: 16,
            tip: "#text"+(i+1)
        });
    }

Ensuite, vous configurez un gestionnaire de déplacement de souris qui examine le tableau de points. L'info-bulle est affichée si l'utilisateur se déplace dans une donnée = point:

    // request mousemove events

    $("#graph").mousemove(function(e){handleMouseMove(e);});

    // show tooltip when mouse hovers over dot
    function handleMouseMove(e){
      mouseX=parseInt(e.clientX-offsetX);
      mouseY=parseInt(e.clientY-offsetY);

      // Put your mousemove stuff here
      var hit = false;
      for (var i = 0; i < dots.length; i++) {
          var dot = dots[i];
          var dx = mouseX - dot.x;
          var dy = mouseY - dot.y;
          if (dx * dx + dy * dy < dot.rXr) {
              tipCanvas.style.left = (dot.x) + "px";
              tipCanvas.style.top = (dot.y - 40) + "px";
              tipCtx.clearRect(0, 0, tipCanvas.width, tipCanvas.height);
              tipCtx.fillText($(dot.tip).val(), 5, 15);
              hit = true;
          }
      }
      if (!hit) { tipCanvas.style.left = "-200px"; }
    }

[Edité pour correspondre à votre code]

Voici le code et un violon: http://jsfiddle.net/m1erickson/yLBjM/

<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>

<style>
    body{ background-color: ivory; margin-top:35px; }
    #wrapper{position:relative; width:300px; height:150px;}
    canvas{border:1px solid red;}
    #tip{background-color:white; border:1px solid blue; position:absolute; left:-200px; top:100px;}
</style>

<script>
$(function(){

    var graph = document.getElementById("graph");
    var ctx = graph.getContext("2d");
    var tipCanvas = document.getElementById("tip");
    var tipCtx = tipCanvas.getContext("2d");

    var canvasOffset = $("#graph").offset();
    var offsetX = canvasOffset.left;
    var offsetY = canvasOffset.top;

    var graph;
    var xPadding = 30;
    var yPadding = 30;

    // Notice I changed The X values
    var data = { values:[
        { X: 0, Y: 12 },
        { X: 2, Y: 28 },
        { X: 3, Y: 18 },
        { X: 4, Y: 34 },
        { X: 5, Y: 40 },
        { X: 6, Y: 80 },
        { X: 7, Y: 80 }
    ]};

    // define tooltips for each data point
    var dots = [];
    for(var i = 0; i < data.values.length; i ++) {
        dots.Push({
            x: getXPixel(data.values[i].X),
            y: getYPixel(data.values[i].Y),
            r: 4,
            rXr: 16,
            color: "red",
            tip: "#text"+(i+1)
        });
    }

    // request mousemove events
    $("#graph").mousemove(function(e){handleMouseMove(e);});

    // show tooltip when mouse hovers over dot
    function handleMouseMove(e){
      mouseX=parseInt(e.clientX-offsetX);
      mouseY=parseInt(e.clientY-offsetY);

      // Put your mousemove stuff here
      var hit = false;
      for (var i = 0; i < dots.length; i++) {
          var dot = dots[i];
          var dx = mouseX - dot.x;
          var dy = mouseY - dot.y;
          if (dx * dx + dy * dy < dot.rXr) {
              tipCanvas.style.left = (dot.x) + "px";
              tipCanvas.style.top = (dot.y - 40) + "px";
              tipCtx.clearRect(0, 0, tipCanvas.width, tipCanvas.height);
              tipCtx.fillText($(dot.tip).val(), 5, 15);
              hit = true;
          }
      }
      if (!hit) { tipCanvas.style.left = "-200px"; }
    }

// le code non modifié suit

    // Returns the max Y value in our data list
    function getMaxY() {
        var max = 0;

        for(var i = 0; i < data.values.length; i ++) {
            if(data.values[i].Y > max) {
                max = data.values[i].Y;
            }
        }

        max += 10 - max % 10;
        return max;
    }

    // Returns the max X value in our data list
    function getMaxX() {
        var max = 0;

        for(var i = 0; i < data.values.length; i ++) {
            if(data.values[i].X > max) {
                max = data.values[i].X;
            }
        }

        // omited
      //max += 10 - max % 10;
        return max;
    }

    // Return the x pixel for a graph point
    function getXPixel(val) {
        // uses the getMaxX() function
        return ((graph.width - xPadding) / (getMaxX() + 1)) * val + (xPadding * 1.5);
        // was
      //return ((graph.width - xPadding) / getMaxX()) * val + (xPadding * 1.5);
    }

    // Return the y pixel for a graph point
    function getYPixel(val) {
        return graph.height - (((graph.height - yPadding) / getMaxY()) * val) - yPadding;
    }

        graph = document.getElementById("graph");
        var c = graph.getContext('2d');            

        c.lineWidth = 2;
        c.strokeStyle = '#333';
        c.font = 'italic 8pt sans-serif';
        c.textAlign = "center";

        // Draw the axises
        c.beginPath();
        c.moveTo(xPadding, 0);
        c.lineTo(xPadding, graph.height - yPadding);
        c.lineTo(graph.width, graph.height - yPadding);
        c.stroke();

        // Draw the X value texts
        var myMaxX = getMaxX();
        for(var i = 0; i <= myMaxX; i ++) {
            // uses data.values[i].X
            c.fillText(i, getXPixel(i), graph.height - yPadding + 20);
        }
        /* was
        for(var i = 0; i < data.values.length; i ++) {
            // uses data.values[i].X
            c.fillText(data.values[i].X, getXPixel(data.values[i].X), graph.height - yPadding + 20);
        }
        */

        // Draw the Y value texts
        c.textAlign = "right"
        c.textBaseline = "middle";

        for(var i = 0; i < getMaxY(); i += 10) {
            c.fillText(i, xPadding - 10, getYPixel(i));
        }

        c.strokeStyle = '#f00';

        // Draw the line graph
        c.beginPath();
        c.moveTo(getXPixel(data.values[0].X), getYPixel(data.values[0].Y));
        for(var i = 1; i < data.values.length; i ++) {
            c.lineTo(getXPixel(data.values[i].X), getYPixel(data.values[i].Y));
        }
        c.stroke();

        // Draw the dots
        c.fillStyle = '#333';

        for(var i = 0; i < data.values.length; i ++) {  
            c.beginPath();
            c.arc(getXPixel(data.values[i].X), getYPixel(data.values[i].Y), 4, 0, Math.PI * 2, true);
            c.fill();
        }


}); // end $(function(){});
</script>

</head>

<body>
    <div id="wrapper">
        <canvas id="graph" width=300 height=150></canvas>
        <canvas id="tip" width=100 height=25></canvas>
    </div>
    <br><br>
    <input type="text" id="text1" value="text 1"/><br><br>
    <input type="text" id="text2" value="text 2"/><br><br>
    <input type="text" id="text3" value="text 3"/><br><br>
    <input type="text" id="text4" value="text 4"/><br><br>
    <input type="text" id="text5" value="text 5"/><br><br>
    <input type="text" id="text6" value="text 6"/><br><br>
    <input type="text" id="text7" value="text 7"/><br><br>
</body>
</html>
21
markE

J'ai essayé la solution de markE et cela a fonctionné parfaitement, SAUF que lorsque vous faites défiler un peu (par exemple, lorsque vous avez votre toile un peu en bas du site).

Ensuite, les positions dans lesquelles votre survol est reconnu se déplacent vers le bas de la même longueur et il peut arriver qu’elles se retrouvent en dehors de la toile et ne soient pas reconnues du tout ...

Lorsque vous utilisez mouseEvent.pageX et mouseEvent.pageY au lieu de .clientX et .clientY, tout va bien. Pour plus de contexte, voici mon code:

// Filling the dots
var dots = [];
// [...]
dots.Push({
    x: xCoord,
    y: yCoord,
    v: value,
    r: 5,
    tooltipRadius2: 7*7 // a little increased radius for making it easier to hit
});
// [...]

var tooltipCanvas = $('#tooltipCanvas')[0];
var tooltipCtx = tooltipCanvas.getContext('2d');
var canvasOffset = canvas.offset();
canvas.mousemove(function (e) {

    // getting the mouse position relative to the page - not the client
    var mouseX = parseInt(e.pageX - canvasOffset.left);
    var mouseY = parseInt(e.pageY - canvasOffset.top);

    var hit = false;
    for (var i = 0; i < dots.length; i++) {
        var dot = dots[i];
        var dx = mouseX - dot.x;
        var dy = mouseY - dot.y;
        if (dx * dx + dy * dy < dot.tooltipRadius2) {
            // show tooltip to the right and below the cursor
            // and moving with it
            tooltipCanvas.style.left = (e.pageX + 10) + "px";
            tooltipCanvas.style.top = (e.pageY + 10) + "px";
            tooltipCtx.clearRect(0, 0, tooltipCanvas.width, tooltipCanvas.height);
            tooltipCtx.textAlign = "center";
            tooltipCtx.fillText(dot.v, 20, 15);
            hit = true;
            // when a dot is found, don't keep on searching
            break;
        }
    }
    if (!hit) {
        tooltipCanvas.style.left = "-200px";
    }
});
1
Neomedes

Vous pourriez peut-être jouer avec l'attribut "title" du graphe et adapter son contenu en fonction de la position de la souris. Essayez d’ajouter ce gestionnaire à votre code de violon:

    graph.addEventListener("mousemove", (function(evt) {
            var rect = evt.target.getBoundingClientRect();
            var x = evt.clientX - rect.left;
            var y = evt.clientY - rect.top;
            var xd, yd;

            graph.title = "";
            for(var i = 0; i < data.values.length; i ++) {
                xd = getXPixel(data.values[i].X);
                yd = getYPixel(data.values[i].Y);
                if ((x > xd-5) && (x < xd+5) &&(y > yd-5) && (y < yd+5) ) {
                    graph.title = document.getElementById("text"+(i+1)).value;
                    break;
                }
            }
    }), false);

Voir ici: Violon mis à jour

Éditer: dans le code ci-dessus, je choisis d'afficher l'info-bulle si la souris est dans un carré de 10x10 autour du point. Bien sûr, cela peut être adapté. De plus, il y a probablement plus de tests à faire, notamment avant d'appeler la valeur sur getElementById, ce qui pourrait éventuellement renvoyer null.

0
Bili

Réponse courte: comme vous l'avez fait maintenant, vous ne pouvez pas.

Réponse longue: vous pouvez, mais vous devez connaître la position exacte de la souris tous les 30 millisecondes environ. Pour chaque milliseconde, vous devez vérifier si la souris survole le point, dessiner à nouveau l'écran et afficher l'info-bulle s'il le fait. Faire cela par vous-même peut être fastidieux, c'est pourquoi j'utilise gee.js .

Regardez cet exemple: http://jsfiddle.net/Saturnix/Aexw4/

C'est l'expression qui contrôle le survol de la souris:

g.mouseX < x + r && g.mouseX > x -r && g.mouseY > y -r && g.mouseY < y+r
0
Saturnix