Search code examples
javascripthtmlsvgmouseovermouseleave

Mouseover event timeout


Here you find the csv file https://www.dropbox.com/s/0ekwalkwqahl806/PeriodicTable.csv?dl=0

<!DOCTYPE html>
<meta charset="utf-8">
<html>
  <head>

    <style>
    rect.bordered {
      stroke: grey;
      stroke-width:2px;
    }
    text.mono {
      font-size: 9pt;
      font-family: Consolas;
      fill: blue;
    }
    </style>

    <script src="http://d3js.org/d3.v3.js"></script>

  </head>
  <body>

    <div id="chart" ></div>

    <script type="text/javascript" >
//cree les variables
      var margin = { top: 50, right: 0, bottom: 0, left: 30 },
          width = 960 - 30 ,
          height = 430 - 50 ,
          espacecases = 3
          gridSize = Math.floor(width / 18),//changer la taille du tableau
          ys = ["1", "2", "3", "4", "5", "6", "7"],
          xs = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18"];

// cree la base du svg
      var svg = d3.select("#chart")
                  .append("svg")
                  .attr("width", width + 90)                                              //+70 por agrandire vers la droite
                  .attr("height", height + 250)                                           //+200 pour agrandir l espace por l immage
                  .append("g") // crée un groupe contenant le tp
                  .attr("transform", "translate(" + 30 +"," + 50+ ")");// bouger le tp pour avoir de la place pour les axes

//axe des y
      var yLabels = svg.selectAll(".yLabel")
                       .data(ys)
                       .enter()
                       .append("text")
                       .text(function (d) { return d; })
                       .attr("x", 0)
                       .attr("y", function (d, i) { return i * (gridSize + 10 + espacecases); })             // + espacecases +10 car rectangle
                       .style("text-anchor", "end")
                       .attr("transform", "translate(-6," + gridSize / 1.5 + ")")
                       .attr("class", "yLabel mono axis");

// graduation axe des x
      var xLabels = svg.selectAll(".xLabel")
                       .data(xs)
                       .enter().append("text")
                       .text(function(d) { return d; })
                       .attr("x", function(d, i) { return i * (gridSize+ espacecases); }) //function (d,i) avec d=data et i=index of data
                       .attr("y", 0)
                       .style("text-anchor", "middle")
                       .attr("transform", "translate(" + gridSize / 2 + ", -6)")
                       .attr("class", "xLabel mono axis");

// prendre les données du fichier csv

      var newlist = function(csvFile){
          d3.csv(csvFile,function(d){
            return {
              AtomicNumber: d.AtomicNumber,
              Element:      d.Element,
              Symbole:      d.Symbole,
              AtomicWeight: d.AtomicWeight,
              Period:       d.Period,
              Group:        d.Group,
              Phase:        d.Phase,
              MostStableCrystal: d.MostStableCrystal,
              Type:         d.Type,
              IonicRadius:  d.IonicRadius,
              AtomicRadius: d.AtomicRadius,
              Electronegativity: d.Electronegativity,
              FirstIonizationPotential: d.FirstIonizationPotential,
              Density:      d.Density,
              MeltingPointK: d.MeltingPointK,
              BoilingPointK: d.BoilingPointK,
              Isotopes:     d.Isotopes,
              Discoverer:   d.Discoverer,
              YearofDiscovery: d.YearofDiscovery,
              SpecificHeatCapacity: d.SpecificHeatCapacity,
              ElectronConfiguration: d.ElectronConfiguration,
              DisplayRow: d.DisplayRow,
              DisplayColumn: d.DisplayColumn,};
          },

// traitement des données

        function(error,data) {
          var cards = svg.selectAll(".DisplayRow")
                         .data(data, function(d) {
                           return d.DisplayRow+':'+d.DisplayColumn;
                         });

          var word = function(d) {return (d.Element) ; };

          var g = cards.enter()
                       .append('g')
                       .attr("id", function(d){return d.Type})
                       .append('g')
                       .attr("id",function(d) {return "element"+(d.AtomicNumber)})
                       .on("click", function(d) { if (d.Symbole!="Hg") { return window.open("http://en.wikipedia.org/wiki/"+word(d), '_blank')}
                                                  else  { return window.open("http://en.wikipedia.org/wiki/"+word(d)+"_(element)", '_blank') };
                                                                   });


              g.attr("transform", function(d){
                                 var x = (d.DisplayColumn - 1) * (gridSize + espacecases),
                                     y = (d.DisplayRow - 1) * (gridSize + 10 + espacecases);
                        return "translate(" + x + "," + y + ")";
                        });

              g.append("rect")
               .attr("rx", 4) // arrondir les cases des elements
               .attr("ry", 4) // arrondir les cases des element
               .attr("class", "xpos bordered") // class=style definit dans le head
               .attr("width", gridSize) //largeur des cases d elements
               .attr("height", gridSize+10) //Hauteur...       //+10 pour faire rectangle
               .transition()
               .duration(2000)
               .style("fill", function(d) {
                     if (d.Type =="Transition Metal") {return "LightSkyBlue"}
                     else if (d.Type =="Alkali Metal")   { return "royalblue" }
                     else if (d.Type =="Noble Gas")   { return "Salmon" }
                     else if (d.Type =="Metalloid")   { return "grey" }
                     else if (d.Type =="Metal")   { return "Peru" }
                     else if (d.Type =="Nonmetal")   { return "gold" }
                     else if (d.Type =="Halogen")   { return "orange" }
                     else if (d.Type =="Alkaline Earth Metal")   { return "hotpink" }
                     else if (d.Type =="Lanthanide")   { return "YellowGreen" }
                     else if (d.Type =="Actinide")   { return "PapayaWhip" }
                     else if (d.AtomicNumber <= 112)   { return "LightSkyBlue" }
                     else if (d.AtomicNumber <= 116)   { return "Peru" }
                     else if (d.AtomicNumber <= 117)   { return "orange" }
                ;}) ;


              g.append("text")
               .text(function(d){
                  return (d.AtomicNumber);
                })
               .style("font-size",10)
               .attr("x", +10)
               .attr("y", +10)
               .style("text-anchor", "middle");

               g.append("text")
                .text(function(d) {
                  return (d.Symbole);
                })
                .style("font-size",30)
                .attr("x", +25)
                .attr("y", 40)
                .style("text-anchor", "middle")
                .on("mouseover", function(d){
                  var x = (d.DisplayColumn - 1) * (gridSize + espacecases),
                      y = (d.DisplayRow - 1) * (gridSize + 10 + espacecases);
                         d3.select("body")
                           .select("#element"+(d.AtomicNumber))
                           .transition()
                           .ease("quad")
                           .duration("500")
                           .attr("transform", "translate(" + 200 +"," + 20+ ") scale( 2.5 )")
                })
                .on("mouseleave", function(d){
                  var x = (d.DisplayColumn - 1) * (gridSize + espacecases),
                      y = (d.DisplayRow - 1) * (gridSize + 10 + espacecases);
                         d3.select("body")
                           .select("#element"+(d.AtomicNumber))
                           .transition()
                           .ease("quad")
                           .duration("300")
                           .attr("transform", "translate("+ x +"," + y+ ") scale( 1 )")
                });

               g.append("text")
                .text(function(d) {
                  return (d.AtomicWeight) ;
                })
                .style("font-size",7)
                .attr("x", +25)
                .attr("y", +50)
                .style("text-anchor", "middle")
                .text(word);


               g.append("text")
                .text(function(d) {
                 return (d.AtomicWeight) ;
               })
                .style("font-size",7)
                .attr("x", +25)
                .attr("y",+57)
                .style("text-anchor", "middle");

               g.append("text")
                .text(function(d) {
                  return (d.YearofDiscovery) ;
                 })
                .style("font-size",7)
                .attr("x", +40)
                .attr("y",+10)
                .style("text-anchor", "middle")
                .text(function(d) { return (d.YearofDiscovery) ; });

                //d3.select("body").selectAll("#Nonmetal").remove();
                //d3.select("body").select("#element1").remove();


     });

      };

newlist("PeriodicTable.csv")
  </script>

  </body>
</html>

I created a periodic table from a csv.file. I ploted all element in a svg and each element has group whith its own id. Now i'm trying to display a bigger element when the mouse stay on the atomic symbol. But this bigger element is unstable, it's blinking(going and coming back). I think a good way to fix that is to add a duration to mouseover but i have no idea how i can do that. If you think this is not the problem and there is another way, i'm open!

Table of elements output image


Solution

  • The problem is that the element that handles the mouseenter/mouseleave events is one of the elements that is being repositioned due to the transformation. So once it starts moving away from the mouse it triggers the mouseleave event and comes back.

    They way i solved it is to add the initial positioning on the outer g element as well as the mouse events handling. You will also need to add a transparent rectangle inside that so that it has contents once you start moving the inner g element.

    So the changed part is

         var gg = cards.enter()
                       .append('g')
                       .attr("id", function(d){return d.Type}),
               g = gg.append('g')
                       .attr("id",function(d) {return "element"+(d.AtomicNumber)})
                       .on("click", function(d) { if (d.Symbole!="Hg") { return window.open("http://en.wikipedia.org/wiki/"+word(d), '_blank')}
                                                  else  { return window.open("http://en.wikipedia.org/wiki/"+word(d)+"_(element)", '_blank') };
                                                                   });
    
    
              gg.attr("transform", function(d){
                                 var x = (d.DisplayColumn - 1) * (gridSize + espacecases),
                                     y = (d.DisplayRow - 1) * (gridSize + 10 + espacecases);
                        return "translate(" + x + "," + y + ")";
                        })
                .append('rect')
                .attr("width", gridSize) //largeur des cases d elements
                .attr("height", gridSize+10) //Hauteur...       //+10 pour faire rectangle
                .style("fill","transparent");
    
              g.append("rect")
               .attr("rx", 4) // arrondir les cases des elements
               .attr("ry", 4) // arrondir les cases des element
               .attr("class", "xpos bordered") // class=style definit dans le head
               .attr("width", gridSize) //largeur des cases d elements
               .attr("height", gridSize+10) //Hauteur...       //+10 pour faire rectangle
               .transition()
               .duration(2000)
               .style("fill", function(d) {
                     if (d.Type =="Transition Metal") {return "LightSkyBlue"}
                     else if (d.Type =="Alkali Metal")   { return "royalblue" }
                     else if (d.Type =="Noble Gas")   { return "Salmon" }
                     else if (d.Type =="Metalloid")   { return "grey" }
                     else if (d.Type =="Metal")   { return "Peru" }
                     else if (d.Type =="Nonmetal")   { return "gold" }
                     else if (d.Type =="Halogen")   { return "orange" }
                     else if (d.Type =="Alkaline Earth Metal")   { return "hotpink" }
                     else if (d.Type =="Lanthanide")   { return "YellowGreen" }
                     else if (d.Type =="Actinide")   { return "PapayaWhip" }
                     else if (d.AtomicNumber <= 112)   { return "LightSkyBlue" }
                     else if (d.AtomicNumber <= 116)   { return "Peru" }
                     else if (d.AtomicNumber <= 117)   { return "orange" }
                ;}) ;
    
    
              g.append("text")
               .text(function(d){
                  return (d.AtomicNumber);
                })
               .style("font-size",10)
               .attr("x", +10)
               .attr("y", +10)
               .style("text-anchor", "middle");
    
               g.append("text")
                .text(function(d) {
                  return (d.Symbole);
                })
                .style("font-size",30)
                .attr("x", +25)
                .attr("y", 40)
                .style("text-anchor", "middle");
    
              gg.on("mouseover", function(d){
                  var x = (d.DisplayColumn - 1) * (gridSize + espacecases),
                      y = (d.DisplayRow - 1) * (gridSize + 10 + espacecases);
                         d3.select("body")
                           .select("#element"+(d.AtomicNumber))
                           .transition()
                           .ease("quad")
                           .duration("500")
                           .attr("transform", "translate(" + (200-x) +"," + (20-y)+ ") scale( 2.5 )")
                })
                .on("mouseleave", function(d){
                  var x = (d.DisplayColumn - 1) * (gridSize + espacecases),
                      y = (d.DisplayRow - 1) * (gridSize + 10 + espacecases);
                         d3.select("body")
                           .select("#element"+(d.AtomicNumber))
                           .transition()
                           .ease("quad")
                           .duration("300")
                           .attr("transform", "scale( 1 )")
                });
    

    Demo at http://plnkr.co/edit/4jyRLSVuVMv3rfnwbJc5?p=preview