将鼠标悬停在超链接工具提示上时动态返回刻度值

时间:2018-09-20 04:25:15

标签: javascript html5 d3.js

我正在用d3.js(v4)绘制分组的条形图。在此,我已将工具提示作为超链接。

我的要求:当我将鼠标悬停在工具提示上时,在代码中,它应该返回相应的钢筋组x轴刻度值,通过该值,我会将工具提示网址设置为唯一的html文件。

我也可以使用“ data 1。week”来获取xtick值。但是,它并没有达到目的,因为我需要在运行时使用工具提示悬停行为来映射此值。

CSV文件

Week,Total,Pass,Fail
w-32,4,4,0
w-33,2,1,1
w-34,2,0,2
w-37,2,1,1
w-38,1,1,0
w-39,1,1,0

工作代码

<!DOCTYPE html>
<html>
<meta http-equiv="content-type" content="text/html; charset=UTF8">
<style>

@-webkit-keyframes bounceIn {
    0% {
      opacity: 0;
      -webkit-transform: scale(.3);
    }
    50% {
      opacity: 1;
      -webkit-transform: scale(1.05);
    }
    70% {
      -webkit-transform: scale(.9);
    }
    100% {
      -webkit-transform: scale(1);
    }
  }
  @keyframes bounceIn {
    0% {
      opacity: 0;
      transform: scale(.3);
    }
    50% {
      opacity: 1;
      transform: scale(1.05);
    }
    70% {
      transform: scale(.9);
    }
    100% {
      transform: scale(1);
    }
  }

  .d3-tip.animate {
    animation: bounceIn 0.2s ease-out;
    -webkit-animation: bounceIn 0.2s ease-out;
  }
  .d3-tip span {
    color: #ff00c7;
  }

.d3-tip {
  line-height: 1;
  font-weight: bold;
  padding: 8px;
  background: #FFE4C4;
  color: white;
  border-radius: 2px;
  text-decoration: none;
}

/* Creates a small triangle extender for the tooltip */
.d3-tip:after {
  <!--box-sizing: border-box;-->
  display: inline;
  font-size: 10px;
  width: 100%;
  line-height: 1;
  color: #FFE4C4;
  content: "\25BC";
  position: absolute;
  text-align: center;
}

/* Style northward tooltips differently */
.d3-tip.n:after {
  margin: -1px 0 0 0;
  top: 100%;
  left: 0;
}

<!-- For setting overall graph dimensions:Start -->
</style>
<body>
<svg width="600" height="400"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3-tip/0.7.1/d3-tip.min.js"></script>
<script>
labels = ["Total", "Pass", "Fail"];
<!-- For setting overall graph dimensions:End -->

<!-- For setting graph margins:Start -->
var svg = d3.select("svg"),
    margin = {top: 33, right: 10,bottom: 150, left: 24},
    width = +svg.attr("width") - margin.left - margin.right,
    height = +svg.attr("height") - margin.top - margin.bottom,
    g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var colour = ["#a9a9a9", "#66cc00", "#ff3333"]

<!-- For gaping between bar groups-->
var x0 = d3.scaleBand()
    .rangeRound([0, width])
    .paddingInner(0.2);

<!-- For gaping between bars in groups-->
var x1 = d3.scaleBand()
    .padding(0.01);

var y = d3.scaleLinear()
    .rangeRound([height, 0]);

var z = d3.scaleOrdinal()
    .range(["#a9a9a9", "#66cc00", "#ff3333"]);

var timeout;

<!--Data read from csv and plot grouped bar chart-->
d3.csv("weekwise.csv", function(d, i, columns) {
  for (var i = 1, n = columns.length; i < n; ++i) d[columns[i]] = +d[columns[i]];
  return d;
}, function(error, data) {
   if (error) throw error;
        <!--console.log(data.length);-->
       var tool_tip = d3.tip()
       .attr('class', 'd3-tip')
      .offset([-8, 0])
      .html(function(d) {
           #Help needed here
           #This is where tool tip is getting set dynamically. However, all the bar are poiting to same html file.
           #I'll let each bar point to unique html file dynamically, if get the xtick value
           return '<a href= '+"wk"+31+"-"+d.key+"-"+d.value+".html" +' target="_parent">' + d.value + "</a>";
        }
    })

  svg.call(tool_tip)
  var keys = data.columns.slice(1);
  x0.domain(data.map(function(d) { return d.Week; }));
  <!--console.log(x0(d.Week));-->
  x1.domain(keys).rangeRound([0, x0.bandwidth()]);
  y.domain([0, d3.max(data, function(d) { return d3.max(keys, function(key) { return d[key]; }); })]).nice();
  g.append("g")
    .selectAll("g")
    .data(data)
    .enter().append("g")
    .attr("transform", function(d) { return "translate(" + x0(d.Week) + ",0)"; })
    .selectAll("rect")
    .data(function(d) { return keys.map(function(key) { return {key: key, value: d[key]}; }); })
    .enter().append("rect")
      .attr("x", function(d) { return x1(d.key); })
      .attr("y", function(d) { return y(d.value); })
      .attr("width", x1.bandwidth())
      .attr("height", function(d) { return height - y(d.value); })
      .attr("fill", function(d) { return z(d.key); })
      <!--// Tooltip stuff after this-->
        .on('mouseover', function(d) {
          <!--console.log(d);-->
          var context = this;
          var args = [].slice.call(arguments);
          args.push(this);
          clearTimeout(timeout);
          timeout = setTimeout(function() {
            tool_tip.show.apply(context, args);
            }, 800);
        })
       <!--.on('mouseout', tool_tip.hide)-->
       .on('mouseout', function(d) {
          var context = this;
          var args = [].slice.call(arguments);
          args.push(this);
          clearTimeout(timeout);
          timeout = setTimeout(function() {
            tool_tip.hide.apply(context, args);
          }, 2000);
        })

    g.append("g")
      .attr("class", "axis")
      .attr("transform", "translate(0," + height + ")")
      .call(d3.axisBottom(x0));
    console.log(g);
 <!--Code for adding graph title-->
        g.append("g")
        .attr("class", "axis")
        .call(d3.axisLeft(y).ticks(null, "s"))
    .append("text")
        .attr("x", (width / 2))
        .attr("y", 0 - (margin.top / 1.5))
        .attr("fill", "#000")
        .attr("text-anchor", "middle")
        .style("font-size", "14px")
        .style("font-weight", "bold")
        <!--.style("text-decoration", "underline")-->
        .text("Build Statistics-v8.0.18");

<!--Code for defining and appending legend-->

var legend = g.append("g")
            .attr("class", "legend")
            .attr("height", 100)
            .attr("width", 100)
        .attr('transform', 'translate(-5,' + (height + 50) + ')')
        .style("font", "12px sans-serif");

    legend.selectAll('rect')
        .data(labels)
      .enter()
      .append("rect")
          .attr("x", function(d, i){
              var xPost = legendXPosition(labels, i, 6);
              return xPost;
          })
      .attr("y", -12)
          .attr("width", 12)
          .attr("height", 12)
          .style("fill", function(d, i) {
              var color = colour[i];
              return color;
          });

    legend.selectAll('text')
      .data(labels)
      .enter()
      .append("text")
          .attr("x", function(d, i){
              var xPost = legendXPositionText(labels, i, 22, 6);
              return xPost;
          })
      .attr("y", -1)
          .text(function(d) {
              return d;
          });


  function legendXPositionText(data, position, textOffset, avgFontWidth){
    return legendXPosition(data, position, avgFontWidth) + textOffset;
  }

  function legendXPosition(data, position, avgFontWidth){
    if(position == 0){
        return 0;
    } else {
        var xPostiion = 0;
        for(i = 0; i < position; i++){
            xPostiion += (data[i].length * avgFontWidth + 40);
        }
        return xPostiion;
    }
  }
});
</script>
</body>
</html>

请查看使用以上代码生成的图形。

enter image description here

2 个答案:

答案 0 :(得分:1)

d3-tip不允许对数据或节点进行太多摆弄,因此,您不得不坚持让d3-tip从触发它的节点返回数据(在此情况下,您会丢失父节点)或父节点(您将无法获得有关悬停在哪个节点上的信息)。解决方案是将更多数据添加到每个节点(即在绑定到每个节点的数据中包括星期),或者在将鼠标悬停在节点上时动态提取星期数据,例如:

    .on('mouseover', function(d) {
      // if d.parent isn't defined, get the parent node of the current selection
      // and add that data to the current node
      if ( ! d.parent ) {
        d.parent = d3.select( this.parentNode ).datum();
      }
        tool_tip.show(d);
    }

如果您尝试以其他方式操纵tip.show()的参数,则由于d3-tip在内部使用参数,会引发其他错误;它们并没有像您想象的那样直接传递给tip.html()函数。

您最好将周数据包括在绑定数据中来规避这一点,但是:

.data(function(d) {
  return keys.map(function(key) { return {key: key, value: d[key], week: d.Week }; });
})

答案 1 :(得分:-1)

是否考虑过将周数添加到绑定数据中?

.data(d => keys.map(key => ( {key: key, value: d[key], week:d.Week.slice(2)} )) )