Mouseover event on two charts at the same time d3.

2020-02-29 11:32发布

The code in the link is for two pie charts. http://jsbin.com/vipodidiyo/edit?html,css,js,outputThey are almost the same just different data and positions. When user mouseover a piece of pie, that piece and tooltip will pup up in that pie chart.

My question is... when user mouseover a piece of pie, how can I make the popups happen in both of the charts. For example, if user mouseover the green part in the first pie chart, the green parts and tooltips in both charts will show up at the same time.

How can I make two charts connected? Does anyone have clue about this? Appreciate!!

Updated

I found a similar question here and try to change the code follow Lars's answer. Interactions that affect multiple separate charts in d3.js? I assigned a class name 'path', and changed d3.select(this) to d3.select('.path'). But wherever my mouse is, the purple part of first pie chart pops up. Here is my updated JSbins http://jsbin.com/gozuyekibi/edit?html,css,js,output

var path = svg.selectAll('path').
    data(pie(data)).
    enter().
    append('path').
    attr('d', arc).
    attr('class','path').
    //attr('id','pathid').
    attr('fill', function(d,i){
     return color(d.data.label);}). 
   on('mouseover', function(d) {
     d3.select('.path').transition()
      .duration(1000)
      .attr("d", arcHover);     
       var total = d3.sum(data.map(function(d) {
          return d.count;
       }));
       var percent = Math.round(1000 * d.data.count / total) / 10;
        tooltip.select('.label').html(d.data.label); 
        tooltip.select('.count').html(d.data.count); 
        tooltip.select('.percent').html(percent + '%'); 
        tooltip.style('display', 'block');
       }).       
    on('mouseout', function() {
     d3.select('.path').transition()
      .duration(500)
      .attr("d", arc);      
        tooltip.style('display', 'none');                    
      });

标签: d3.js
1条回答
▲ chillily
2楼-- · 2020-02-29 12:10

First, assign a single class to your tooltips and clean up that css. Next, assign each arc path a class so that your can pair your paths on mouseover. Then generalize your mouseover to operate on both paths:

.on('mouseover', function(d0) {

    // apply over to both paths
    d3.selectAll('path.' + d0.data.label).transition()
      .duration(1000)
      .attr("d", arcHover)
      // now loop each of them
      .each(function(d1) {
        // get a sum for the group of paths
        var total = d3.sum(this.parentNode.childNodes, function(d2) {
          return d2.value;
        });
        // and a percent
        var percent = Math.round(1000 * d1.value / total) / 10;

        // find correct tooltip
        var tooltip = d3.select(this.ownerSVGElement.parentNode.childNodes[1]);
        tooltip.select('.label').html(d1.data.label);
        tooltip.select('.count').html(d1.data.count);
        tooltip.select('.percent').html(percent + '%');
        tooltip.style('display', 'block');

      })
  })
  .on('mouseout', function(d) {

      // apply to both paths
      d3.selectAll('path.' + d.data.label).transition()
        .duration(500)
        .attr("d", arc);

      // hide all tooltips
      d3.selectAll('.tooltip').style('display', 'none');
  });

Full code:

<!DOCTYPE html>
<html>

<head>
  <style>
    #pieChart1 {
      height: 360px;
      position: relative;
      width: 360px;
    }
    
    .tooltip {
      background: #fdd0a2;
      box-shadow: 0 0 5px #999999;
      color: #333;
      display: none;
      left: 300px;
      padding: 10px;
      position: absolute;
      text-align: center;
      width: 80px;
      z-index: 10;
    }
    
    #tooltip1 {
      top: 220px;
    }
    
    #tooltip2 {
      top: 580px;
    }
  </style>
</head>

<body>
  <div id="pieChart1"></div>
  <div id="pieChart2"></div>
  <script src="http://d3js.org/d3.v3.min.js"></script>


  <script>
    var data1 = [{
      label: 'Station1',
      count: 10
    }, {
      label: 'Station2',
      count: 20
    }, {
      label: 'Station3',
      count: 30
    }];
    var data2 = [{
      label: 'Station1',
      count: 15
    }, {
      label: 'Station2',
      count: 80
    }, {
      label: 'Station3',
      count: 20
    }];

    var drawPieChartFunction = function(data, chartId, tooltipName) {

      var margin = {
          top: 20,
          right: 40,
          bottom: 120,
          left: 80
        },
        width = 700 - margin.right - margin.left,
        height = 500 - margin.top - margin.bottom;

      var radius = Math.min(width, height) / 2;
      var donutWidth = 105;
      var legendRectSize = 18;
      var legendSpacing = 4;

      var color = d3.
      scale.
      ordinal().
      range(['#98df8a', '#c5b0d5', '#9edae5']).
      domain(d3.keys(data[0]).filter(function(key) {
        return key === 'label';
      }));

      var svg = d3.
      select(chartId).
      append('svg').
      attr({
        'width': width + margin.right + margin.left,
        'height': height + margin.top + margin.bottom
      }).
      append('g').
      attr('transform', 'translate(' + ((width + margin.right + margin.left) / 2) +
        ',' + ((height + margin.top + margin.bottom) / 2) + ')');

      var arc = d3.svg.arc().
      innerRadius(radius - donutWidth).
      outerRadius(radius);

      var arcHover = d3.svg.arc().
      innerRadius(radius - donutWidth).
      outerRadius(radius + 10);

      var pie = d3.layout.pie().
      value(function(d) {
        return d.count;
      });
      
      var tooltip = d3.select(chartId)
        .append('div')
        .attr('class', 'tooltip')
        .attr('id', tooltipName);
      tooltip.append('div')
        .attr('class', 'label');
      tooltip.append('div')
        .attr('class', 'count');
      tooltip.append('div')
        .attr('class', 'percent');
      
      var path = svg.selectAll('path').
        data(pie(data)).
        enter().
        append('path').
        attr('d', arc).
        attr('class', function(d) {
          return d.data.label;
        }).
        attr('fill', function(d, i) {
          return color(d.data.label);
        }).
        on('mouseover', function(d0) {

          d3.selectAll('path.' + d0.data.label).transition()
            .duration(1000)
            .attr("d", arcHover)
            .each(function(d1) {
              var total = d3.sum(this.parentNode.childNodes, function(d2) {
                return d2.value;
              });
              var percent = Math.round(1000 * d1.value / total) / 10;
              
              // find correct tooltip
              var tooltip = d3.select(this.ownerSVGElement.parentNode.childNodes[1]);
              tooltip.select('.label').html(d1.data.label);
              tooltip.select('.count').html(d1.data.count);
              tooltip.select('.percent').html(percent + '%');
              tooltip.style('display', 'block');
  
            })
      }).
      on('mouseout', function(d) {
        d3.selectAll('path.' + d.data.label).transition()
          .duration(500)
          .attr("d", arc);
        d3.selectAll('.tooltip').style('display', 'none');
      });
      return path;
    };
    drawPieChartFunction(data1, '#pieChart1', 'tooltip1');
    drawPieChartFunction(data2, '#pieChart2', 'tooltip2');
  </script>
</body>

</html>

查看更多
登录 后发表回答