【问题标题】:Highlight pie chart on hover d3js在悬停 d3js 上突出显示饼图
【发布时间】:2017-11-27 23:08:24
【问题描述】:

我正在尝试使用 d3js 获取饼图。截至目前悬停标题工作正常。我还试图在悬停时增加所选饼图的大小。以下是我在mousemove 上所做的事情:

var arcOver = d3.arc()
    .innerRadius(0)
    .outerRadius(150 + 10);

.on("mousemove", function(d) {
    tooltip.transition().duration(200)
        .style("opacity", 0.9);
    tooltip.select("div").html(d.data.name + " <br><strong>" + d.data.value + "</strong>")
        .style("position", "fixed")
        .style("text-align", "center")
        .style("width", "120px")
        .style("height", "45px")
        .style("padding", "2px")
        .style("font", "12px sans-serif")
        .style("background", "lightsteelblue")
        .style("border", "0px")
        .style("border-radius", "8px")
        .style("left", (d3.event.pageX + 15) + "px")
        .style("top", (d3.event.pageY - 28) + "px");
    d3.select(this).transition()
        .duration(1000)
        .attr("g", arcOver);

})

这是小提琴的链接,其代码与悬停时文本显示的工作原理相同,但所选饼图的大小不会增加。为了这个目的,我怎么能得到这两个东西。谢谢。

https://jsfiddle.net/snt1/gLjjv5ch/3/

【问题讨论】:

    标签: javascript html d3.js pie-chart


    【解决方案1】:

    现在您的mousemove 事件正在监听&lt;g&gt; 元素。但是,路径是组元素的子元素。

    因此,将this 与firstNode 结合使用。此外,路径没有"g" 属性,而是"d":

    d3.select(this.firstChild).transition()
        .attr("d", arcOver);
    

    这是您的更新代码:

    var toCSV = [{
      "name": "SEASONAL_LYQ1",
      "code": "SEASONAL_LYQ1",
      "parent": "SEASONAL_POP",
      "value": "0",
      "label": "LYQ1",
      "children": []
    }, {
      "name": "SEASONAL_LYQ2",
      "code": "SEASONAL_LYQ2",
      "parent": "SEASONAL_POP",
      "value": "10",
      "label": "LYQ2",
      "children": []
    }, {
      "name": "SEASONAL_LYQ3",
      "code": "SEASONAL_LYQ3",
      "parent": "SEASONAL_POP",
      "value": "16",
      "label": "LYQ3",
      "children": []
    }, {
      "name": "SEASONAL_LYQ4",
      "code": "SEASONAL_LYQ4",
      "parent": "SEASONAL_POP",
      "value": "10",
      "label": "LYQ4",
      "children": []
    }, {
      "name": "SEASONAL_CYQ1",
      "code": "SEASONAL_CYQ1",
      "parent": "SEASONAL_POP",
      "value": "0",
      "label": "CYQ1",
      "children": []
    }, {
      "name": "SEASONAL_CYQ2",
      "code": "SEASONAL_CYQ2",
      "parent": "SEASONAL_POP",
      "value": "10",
      "label": "CYQ2",
      "children": []
    }, {
      "name": "SEASONAL_CYQ3",
      "code": "SEASONAL_CYQ3",
      "parent": "SEASONAL_POP",
      "value": "16",
      "label": "CYQ3",
      "children": []
    }, {
      "name": "SEASONAL_CYQ4",
      "code": "SEASONAL_CYQ4",
      "parent": "SEASONAL_POP",
      "value": "10",
      "label": "CYQ4",
      "children": []
    }];
    var margin = {
        top: 30,
        right: 20,
        bottom: 20,
        left: 20
      },
      width = 400,
      height = 400;
    var radius = Math.min(width, height) / 4;
    var donutWidth = 75;
    var color = d3.scaleOrdinal(d3.schemeCategory20);
    var count = 0;
    // var svg = d3.select("div#donuts").append("svg")
    var svg = d3.select("#charts").append("svg")
      .attr('width', width)
      .attr('height', height)
      .append('g')
      .attr('transform', 'translate(' + (width / 2) +
        ',' + (height / 2) + ')');
    
    
    var arc = d3.arc()
      .innerRadius(0)
      .outerRadius(100);
    //        var arc = d3.svg.arc().outerRadius(r);
    var arcOver = d3.arc()
      .innerRadius(0)
      .outerRadius(150 + 10);
    
    var pie = d3.pie()
      .sort(null)
      .value(function(d) {
        return d.value;
      });
    var pcnt = d3.sum(toCSV, function(d) {
      return d.value;
    });
    
    // avoiding overlap labels
    var getAngle = function(d) {
      return (180 / Math.PI * (d.startAngle + d.endAngle) / 2 - 90);
    };
    var g = svg.selectAll(".arc")
      .data(pie(toCSV))
      .enter().append("g")
      .attr('class', "arc")
      .on("mouseover", function() {
        tooltip.style("display", null);
      })
      .on("mousemove", function(d) {
        tooltip.transition().duration(200)
          .style("opacity", 0.9);
        tooltip.select("div").html(d.data.name + " <br><strong>" + d.data.value + "</strong>")
          .style("position", "fixed")
          .style("text-align", "center")
          .style("width", "120px")
          .style("height", "45px")
          .style("padding", "2px")
          .style("font", "12px sans-serif")
          .style("background", "lightsteelblue")
          .style("border", "0px")
          .style("border-radius", "8px")
          .style("left", (d3.event.pageX + 15) + "px")
          .style("top", (d3.event.pageY - 28) + "px");
        d3.select(this.firstChild).transition()
          .attr("d", arcOver);
    
      })
      .on("mouseout", function() {
        tooltip.style("display", "none")
        d3.select(this.firstChild).transition()
          .attr("d", arc)
          .attr("stroke", "none");
      })
    
    /*   .on("mouseover", function(d) {
    					         	            d3.select(this)
    				         	                   .transition()
    					         	               .duration(1000)
    					         	               .attr("d", arcOver);
    					         	        })
    	         	        .on("mouseout", function(d) {
    	         	            d3.select(this).transition()            
    	         	               .attr("d", arc)
    	         	               .attr("stroke","none");
    	         	        });*/
    
    var tooltip = d3.select("body").append("div")
      .attr("class", "tooltip")
      .style("opacity", 0.5);
    
    tooltip.append("rect")
      .attr("width", 30)
      .attr("height", 20)
      .attr("fill", "#ffffff")
      .style("opacity", 0.5);
    
    tooltip.append("div")
      .attr("x", 15)
      .attr("dy", "1.2em")
      .style("text-anchor", "middle")
      .attr("font-size", "1.5em")
      .attr("font-weight", "bold");
    
    
    
    g.append("path")
      .attr("d", arc)
      .style("fill", function(d) {
        return color(d.data.name);
      });
    
    count = 0;
    //Legend for charts 
    var legend = svg.selectAll(".legend")
      .data(toCSV).enter()
      .append("g").attr("class", "legend")
      .attr("legend-id", function(d) {
        return count++;
      })
      .attr("transform", function(d, i) {
        return "translate(-30," + (-90 + i * 20) + ")";
      });
    
    
    legend.append("rect")
      .attr("x", width / 1.9)
      .attr("word-wrap", "break-word")
      .attr("width", 18).attr("height", 18)
      .style("fill", function(d) {
        return color(d.name);
      });
    legend.append("text").attr("x", width / 2)
      .attr("y", 9).attr("dy", ".35em")
    
      .style("text-anchor", "end").text(function(d) {
        return d.label;
      });
      .chart {
      background: #eee;
      padding: 3px;
    }
    
    .chart div {
      width: 0;
      transition: all 1s ease-out;
      -moz-transition: all 1s ease-out;
      -webkit-transition: all 1s ease-out;
    }
    
    .chart div {
      font: 10px sans-serif;
      background-color: steelblue;
      text-align: right;
      padding: 3px;
      margin: 5px;
      color: white;
      box-shadow: 2px 2px 2px #666;
    }
    
    .bar {
      fill: orange;
    }
    
    .bar:hover {
      fill: red;
    }
    
    rect.background {
      fill: white;
    }
    
    .axis {
      shape-rendering: crispEdges;
    }
    
    .axis path,
    .axis line {
      fill: none;
      stroke: #000;
    }
    
    tooltip {
      position: absolute;
      text-align: center;
      width: 120px;
      height: 45px;
      padding: 2px;
      font: 12px sans-serif;
      background: lightsteelblue;
      border: 0px;
      border-radius: 8px;
      pointer-events: none;
    }
    
    bar {
      fill: #8CD3DD;
    }
    
    bar:hover {
      fill: #F56C4E;
    }
    
    
    /* .tick:nth-child(3n) text {
        visibility: hidden;
    } */
    
    .d3-tip {
      line-height: 1;
      font-weight: bold;
      padding: 12px;
      background: rgba(0, 0, 0, 0.8);
      color: #fff;
      border-radius: 2px;
    }
    
    
    /* 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: rgba(0, 0, 0, 0.8);
      content: "\25BC";
      position: absolute;
      text-align: center;
    }
    
    
    /* Style northward tooltips differently */
    
    .d3-tip.n:after {
      margin: -1px 0 0 0;
      top: 100%;
      left: 0;
    }
    
    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: rgba(0, 0, 0, 0.8);
      content: "\25BC";
      position: absolute;
      text-align: center;
    }
    
    Style northward tooltips differently .d3-tip.n:after {
      margin: -1px 0 0 0;
      top: 100%;
      left: 0;
    }
    
    svg text.label {
      fill: #ff0000;
      font: 25px;
      text-anchor: middle;
      font-weight: 400;
      text-anchor: middle;
      font-size: 125%;
      text-anchor: start;
    }
    
    path {
      stroke: steelblue;
      stroke-width: 2;
      /*   fill: none; */
      /* commenting out to show multiple ring donut chart. */
    }
    
    pathline {
      fill: none;
      stroke-width: 2;
      stroke: #000;
    }
    
    .axis path,
    .axis line {
      fill: none;
      stroke: grey;
      stroke-width: 1;
      shape-rendering: crispEdges;
    }
    
    .graph {
      width: auto;
    }
    
    .tooltip {
      color: black;
    }
    
    .axis {
      font: 12px sans-serif, Georgia, Arial;
    }
    
    .axis path,
    .axis line {
      fill: none;
      stroke: #dadada;
      shape-rendering: crispEdges;
    }
    
    
    /* ANGULAR MODAL */
    
    .dialogdemoBasicUsage #popupContainer {
      position: relative;
    }
    
    .dialogdemoBasicUsage .footer {
      width: 100%;
      text-align: center;
      margin-left: 20px;
    }
    
    .dialogdemoBasicUsage .footer,
    .dialogdemoBasicUsage .footer>code {
      font-size: 0.8em;
      margin-top: 50px;
    }
    
    .dialogdemoBasicUsage button {
      width: 200px;
    }
    
    .dialogdemoBasicUsage div#status {
      color: #c60008;
    }
    
    .dialogdemoBasicUsage .dialog-demo-prerendered md-checkbox {
      margin-bottom: 0;
    }
    
    
    /* Angular grids */
    
    .gridListdemoBasicUsage md-grid-list {
      margin: 8px;
    }
    
    gridListdemoBasicUsage .gray {
      background: #f5f5f5;
    }
    
    .gridListdemoBasicUsage .green {
      background: #b9f6ca;
    }
    
    .gridListdemoBasicUsage .yellow {
      background: #ffff8d;
    }
    
    .gridListdemoBasicUsage .blue {
      background: #84ffff;
    }
    
    .gridListdemoBasicUsage .purple {
      background: #b388ff;
    }
    
    .gridListdemoBasicUsage .red {
      background: #ff8a80;
    }
    
    .gridListdemoBasicUsage md-grid-tile {
      transition: all 400ms ease-out 50ms;
    }
    
    md-grid-list md-grid-tile md-grid-tile-footer,
    md-grid-list md-grid-tile md-grid-tile-header {
      height: 25px;
    }
    
    .svg-container {
      display: inline-block;
      position: relative;
      width: 100%;
      padding-bottom: 12%;
      vertical-align: top;
      overflow: hidden;
    }
    
    .line {
      fill: none;
      stroke: steelblue;
      stroke-width: 1.5px;
    }
    
    .svg-content-responsive {
      display: inline-block;
      position: absolute;
      top: 10px;
      left: 0;
    }
    
    .svg-content {
      display: inline-block;
      position: absolute;
      top: 0;
      left: 0;
    }
    
    #linechart {
      width: 100%;
      height: 100%;
      position: absolute;
    }
    
    
    /* TESTING GRIDS */
    
    .chart-tile {
      display: block;
      height: 100%;
      width: 100%;
    }
    
    .gridListdemoDynamicTiles .s64 {
      font-size: 64px;
    }
    
    .gridListdemoDynamicTiles .s32 {
      font-size: 48px;
    }
    
    .gridListdemoDynamicTiles md-grid-list {
      margin: 8px;
    }
    
    .gridListdemoDynamicTiles md-grid-tile {
      box-shadow: 2px 2px 3px 3px #888888;
      transition: all 300ms ease-out 50ms;
    }
    
    .gridListdemoDynamicTiles md-grid-tile md-grid-tile-footer {
      background: rgba(0, 0, 0, 0.68);
      height: 36px;
    }
    
    .gridListdemoDynamicTiles md-grid-tile-footer figcaption {
      width: 100%;
    }
    
    .gridListdemoDynamicTiles md-grid-tile-footer figcaption h3 {
      margin: 0;
      font-weight: 700;
      width: 100%;
      text-align: center;
    }
    
    
    /*
    Copyright 2016 Google Inc. All Rights Reserved. 
    Use of this source code is governed by an MIT-style license that can be in foundin the LICENSE file at https://material.angularjs.org/license.
    */
    
    @media (min-width: 1200px) {
      .container {
        width: 1400px;
        margin-right: -50px;
      }
    }
    
    @media only screen and (max-width: 260px) and (min-width: 1600px) {
      .container {
        width: 1700px;
        margin-right: -50px;
      }
    }
    
    #wrapper {
      border-style: solid;
      height: 100px;
      width: 200px;
    }
    
    #dropdown {
      vertical-align: middle;
      width: 80px;
      margin-left: 300px;
      margin-top: -30px;
    }
    
    
    /* Styles go here */
    
    .gridster-item {
      background-color: darkgrey;
    }
    
    .my-class {
      border: 1px solid red;
      height: 50px;
    }
    
    body {
      background-color: #fcfcfc;
    }
    
    .container {
      text-align: center;
      padding: 15px;
    }
    
    .left-div {
      display: inline-block;
      max-width: 300px;
      text-align: left;
      padding: 30px;
      background-color: #ddd;
      border-radius: 3px;
      margin: 15px;
      vertical-align: top;
    }
    
    .right-div {
      display: inline-block;
      max-width: 150px;
      text-align: left;
      padding: 30px;
      background-color: #ddd;
      border-radius: 3px;
      margin: 15px;
    }
    
    .left-text,
    .right-text {
      font: 300 16px/1.6 'Helvetica Neue' sans-serif;
      color: #333;
    }
    
    @media screen and (max-width: 600px) {
      .left-div,
      .right-div {
        max-width: 100%;
      }
    <script src="https://d3js.org/d3.v4.min.js"></script>
    <div id="charts"></div>

    【讨论】:

      【解决方案2】:

      您需要在鼠标悬停时更新每个饼图段的d 属性。但是,您正在尝试转换父 g - 这不起作用。

      让我们看看你的代码:

      d3.select(this).transition()
        .duration(1000)
        .attr("g", arcOver);
      })
      

      this 是什么?这是g,虽然我假设.attr("g" 是.attr("d" - 两者都不会设置子path 元素的d 属性(并且g 没有d 属性改变)。

      您需要选择子路径元素,然后应用新的路径数据:

      d3.select(this)      // make a selection of the parent g
        .select("path")    // select the child path element
        .transition()      // create a transition for the path
        .attr("d", arcOver)// update the path's d attribute
        .duration(1000);   // do it slowly.
      })
      

      鼠标移开后,您需要重置弧线:

      d3.select(this)      // make a selection of the parent g
        .select("path")    // select the child path element
        .transition()      // create a transition for the path
        .attr("d", arc)    // update the path's d attribute
        .duration(1000);   // do it slowly.
      })
      

      我已将突出显示的触发器更改为 mouseover - 您只需在鼠标第一次进入饼图段时调用它一次。这是updated fiddle。

      【讨论】:

      • SO 处应该有一个警告,例如 “有人正在为这个问题输入答案...”
      • 我知道使用 d3.select 很好,特别适合新手,但原生 JS 几乎总是更快:jsperf.com/d3-select-vs-native-js/1 如果你有大量元素,这种差异会增加。
      • 是的,以后会开始将其添加到更多答案中。
      猜你喜欢
      • 1970-01-01
      • 2018-07-31
      • 2018-12-11
      • 2019-09-04
      • 2014-06-21
      • 1970-01-01
      • 2023-03-12
      • 2022-09-29
      • 1970-01-01
      相关资源
      最近更新 更多