2017-08-10 1 views
0

J'ai créé un graphique avec un survol/un tooltop pour chaque élément de légende dans l'axe y. Le survol crée une info-bulle qui couvre la largeur du graphique à la hauteur de l'élément de légende y. J'ai positionné avec succès la hauteur et la largeur ainsi que l'emplacement de l'infobulle sur l'axe des x mais je ne peux pas trouver la bonne formule pour localiser le sommet de l'infobulle.Impossible de calculer les coordonnées verticales de l'info-bulle sur la légende de l'axe Y dans D3 v4

mouseover with incorrect vertical offset

var countryBox = d3.select("body").append("div") 
    .attr("class", "countryTip") 
    .style("opacity", 0); 

...

/* Build mouseover infobox for each country in y axis legend in 1800 */ 
h.selectAll(".axis--y .tick text") 
    .on("mouseover", function() { 
     totSpec = 0; 
     var myElement = d3.select(this); 
     var countryName = myElement.text(); 
     /* determine absolute coordinates for left edge of SVG */ 
     var matrix = this.getScreenCTM() 
      .translate(+this.getAttribute("cx"), +this.getAttribute("cy")); 
     h.selectAll("." + countryName.replace(/\s+/g, '_')).each(function(d) { 
      totSpec += d.freqEnd; 
      totSpec -= d.freqStart; 
      sumSpec = sumSpec + d.freqEnd - d.freqStart; 
     }); 
     var availPercent = totSpec/availSpec; 

     countryBox.transition() 
      .duration(200) 
      .style("opacity", .9); 
     var yText = getTranslation(d3.select(this.parentNode).attr("transform")); 
     countryBox.html(countryName + '</br>' + r(totSpec) + ' MHz assigned out of ' + r(availSpec) + ' MHz available. <br><b>Band occupancy ' + p(availPercent) + '</b>') 
      .style("left", (window.pageXOffset + matrix.e) + "px") 
      .style("top", (yText[1] - y.bandwidth()/2 - window.pageYOffset) + "px") 
      .style("height", y.bandwidth() + "px") 
      .style("width", width + "px"); 
     console.log("yText[1]: " + yText[1] + " halfBand: " + halfBand + " margin.top: " + margin.top + " window.pageYOffset: " + window.pageYOffset); 

    }) 
    .on("mouseout", function() { 
     countryBox.transition() 
      .duration(500) 
      .style("opacity", 0); 
    }); 

getTranslation est une fonction compensate for the absence of d3.transform in v4 à

function getTranslation(transform) { 
    var g = document.createElementNS("http://www.w3.org/2000/svg", "g"); 
    g.setAttributeNS(null, "transform", transform); 
    var matrix = g.transform.baseVal.consolidate().matrix; 
    return [matrix.e, matrix.f]; 
} 

Pour

.style("top", (yText[1] - y.bandwidth()/2 - window.pageYOffset) + "px")

  • yText[1] renvoie les coordonnées y de l'élément de légende de la souris y passe au-dessus, en substance le point médian vertical de la bande de pays en question.
  • y.bandwidth()/2 représente la moitié de la hauteur verticale de la bande et
  • window.pageYOffset compense défilement

Pour autant que je peux voir, cela devrait mettre le haut de l'info-bulle en haut de la bande x pertinente. Évidemment pas cependant. Le bootstrap est-il un facteur? S'il s'agit de svg pur, je trouve que je peux dessiner un cercle parfait disposé sur chaque bande utiliser yText[1] comme point central du cercle. Suis-je mélanger svg et html?

CSS

div.countryTip { 
    position: fixed; 
    z-index: 99; 
    text-align: left; 
    font-family: arial; 
    font-size: 1em; 
    line-height: 1.5; 
    padding: 1.5em; 
    background: #144667; 
    border: 0px; 
    color: white; 
    border-radius: 3px; 
    pointer-events: none; 
    -webkit-transform: translate3d(0, -0.5em, 0); 
    -moz-transform: translate3d(0, -0.5em, 0); 
    transform: translate3d(0, -0.5em, 0); 
    -webkit-transition: opacity 0.1s, -webkit-transform 0.1s; 
    -moz-transition: opacity 0.1s, -moz-transform 0.1s; 
    transition: opacity 0.1s, transform 0.1s; 
} 

Working site et full source

Mise à jour: Ajout d'un Plunker

Répondre

0

Enfin résolu cela. Je confondais les systèmes de coordonnées SVG et HTML.La réponse était d'utiliser l'élément y de la matrice de coordonnées défini par getScreenCTM()

let matrix = this.getScreenCTM() 
    .translate(+this.getAttribute('cx') +this.getAttribute('cy')) 

le résultat étant

.style('top', matrix.f - y.bandwidth()/2 + 8 + 'px') 

Ce poste sur understanding SVG coordinates et ce practical example sur infobulles SVG m'a aidé y arriver dans la fin.

0

Pointe du chapeau à @Gerald Furtado qui a fait remarquer que je devais ajouter le décalage supérieur du conteneur div pour l'élément SVG.

.style("top", (document.getElementById(divID).offsetTop + yText[1] - window.pageYOffset) + "px") 

a fait le travail bien que je reçois toujours un peu de variance verticale entre les différents onglets sur les infobulles que je ne peux pas expliquer.

Plunker updated