【问题标题】:D3 mouseover effect for each chart on one page一页上每个图表的 D3 鼠标悬停效果
【发布时间】:2014-09-26 13:07:50
【问题描述】:

我在一页上有多个 d3 图表,并希望为每个图表添加鼠标悬停效果。 目前只有一个图表受到影响并具有鼠标悬停效果。

我创建了一个包含多个图表的示例。 这是小提琴:http://jsfiddle.net/zumdpjzx/

for( var i= 1; i < 3; i++){

console.log(i);

var arrData = [
                ["2014-08-20", 100, 100],
                ["2014-08-21", 95, 85],
                ["2014-08-22", 93, 71],
                ["2014-08-23", 88, 57],
                ["2014-08-24", 86, 42],
                ["2014-08-25", 98, 28],
                ["2014-08-26", 117, 14],
                ["2014-08-27", 123, 0]
              ];



arrData = arrData.sort((function(index){
return function(a, b){
    return (a[index] === b[index] ? 0 : (a[index] < b[index] ? -1 : 1));
};
})(0));

 console.log("array: " + arrData);


var margin = {top: 40, right: 40, bottom: 60, left: 50},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;

var parseDate = d3.time.format("%Y-%m-%d").parse;


var x = d3.time.scale().range([0, width])

var y = d3.scale.linear().range([height, 0]);

var xAxis = d3.svg.axis()
                  .scale(x)
                  .orient("bottom")
                  .ticks(arrData.length)
                  .tickFormat(d3.time.format("%Y-%m-%d"));

var yAxis = d3.svg.axis()
              .scale(y)
              .orient("left");

var line = d3.svg.line()
             .x(function(d) { return x(d.date); })
             .y(function(d) { return y(d.close); });

 var line2 = d3.svg.line()
               .x(function(d) { return x(d.date); })
               .y(function(d) { return y(d.open); });

 var svg = d3.select("#chart" + i).append("svg")
             .attr("width", width + margin.left + margin.right)
             .attr("height", height + margin.top + margin.bottom)
             .append("g")
             .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

 var data = arrData.map(function(d) {
                          return {
                             //date: d[0],
                             date: parseDate(d[0]),
                             close: d[2],
                             open: d[1]
                          };

                       });

var length = arrData.length - 1;

// Scale the range of the data
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([0, d3.max(data, function(d) { return Math.max(d.close, d.open); })]);

svg.append("g").attr("class", "x axis")
               .attr("transform", "translate(0," + height + ")")
               .call(xAxis)
               .selectAll("text")  
               .style("text-anchor", "end")
               .attr("dx", "-.8em")
               .attr("dy", ".15em")
               .attr("transform", function(d) {
                     return "rotate(-65)" 
                     });

svg.append("g")
  .attr("class", "y axis")
  .call(yAxis)
  .append("text")
  .attr("transform", "rotate(-90)")
  .attr("y", 6)
  .attr("dy", ".71em")
  .style("text-anchor", "end")
  .text("Open Issues");

svg.append("path")
  .datum(data)
  .attr("class", "line")
  .attr("d", line);

svg.append("path")    // Add the valueline2 path.
.attr("class", "line")
.style("stroke", "red")
.attr("d", line2(data))
.text("line2");

svg.append("text")
.attr("transform", "translate(" + (width+3) + "," + y(data[length].open) + ")")
.attr("dy", ".35em")
.attr("text-anchor", "start")
.style("fill", "red")
.text("Open");

svg.append("text")
.attr("transform", "translate(" + (width+3) + "," + y(data[length].close) + ")")
.attr("dy", ".35em")
.attr("text-anchor", "start")
.style("fill", "steelblue")
.text("Close");

//mouse over
var focus = svg.append("g")
  .attr("class", "focus")
  .style("display", "none");

focus.append("circle")
  .attr("r", 4.5);
  focus.append("circle")
  .attr("r", 4.5);

var bisectDate = d3.bisector(function(d) { return d.date; }).left;
var formatValue = d3.format(",.2f");
var formatCurrency = function(d) { return  + d; };


focus.append("text")
  .attr("x", 9)
  .attr("dy", ".35em");

svg.append("rect")
  .attr("class", "overlay")
  .attr("width", width)
  .attr("height", height)
  .on("mouseover", function() { focus.style("display", null); })
  .on("mouseout", function() { focus.style("display", "none"); })
  .on("mousemove", mousemoveOpen);





}

function mousemoveOpen() {
var x0 = x.invert(d3.mouse(this)[0]),
    i = bisectDate(data, x0, 1),
    d0 = data[i - 1],
    d1 = data[i],
    d = x0 - d0.date > d1.date - x0 ? d1 : d0;
focus.attr("transform", "translate(" + x(d.date) + "," + y(d.open) + ")");
focus.select("text").text(formatCurrency(d.open));
}

编辑:

我现在找到了一个新的解决方案。这是小提琴:http://jsfiddle.net/4h72u83h/1/ 感谢您的帮助!

【问题讨论】:

    标签: javascript node.js d3.js charts


    【解决方案1】:

    您已经非常接近目标了,但您没有跟踪您在 mouseoutmouseovermousemove 处理程序中更新的焦点元素。

    你可以这样做:

    for (var i = 1; i < 3; i++) {
    
      console.log(i);
    
      var arrData = [
        ["2014-08-20", 100, 100],
        ["2014-08-21", 95, 85],
        ["2014-08-22", 93, 71],
        ["2014-08-23", 88, 57],
        ["2014-08-24", 86, 42],
        ["2014-08-25", 98, 28],
        ["2014-08-26", 117, 14],
        ["2014-08-27", 123, 0]
      ];
    
    
    
      arrData = arrData.sort((function(index) {
        return function(a, b) {
          return (a[index] === b[index] ? 0 : (a[index] < b[index] ? -1 : 1));
        };
      })(0));
    
      console.log("array: " + arrData);
    
    
      var margin = {
          top: 40,
          right: 40,
          bottom: 60,
          left: 50
        },
        width = 960 - margin.left - margin.right,
        height = 500 - margin.top - margin.bottom;
    
      var parseDate = d3.time.format("%Y-%m-%d").parse;
    
    
      var x = d3.time.scale()
        .range([0, width])
    
      var y = d3.scale.linear()
        .range([height, 0]);
    
      var xAxis = d3.svg.axis()
        .scale(x)
        .orient("bottom").ticks(arrData.length).tickFormat(d3.time.format("%Y-%m-%d"));
    
      var yAxis = d3.svg.axis()
        .scale(y)
        .orient("left");
    
      var line = d3.svg.line()
        .x(function(d) {
          return x(d.date);
        })
        .y(function(d) {
          return y(d.close);
        });
    
      var line2 = d3.svg.line()
        .x(function(d) {
          return x(d.date);
        })
        .y(function(d) {
          return y(d.open);
        });
    
      var svg = d3.select("#chart" + i).append("svg")
        .attr("width", width + margin.left + margin.right)
        .attr("height", height + margin.top + margin.bottom)
        .append("g")
        .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
    
      var data = arrData.map(function(d) {
        return {
          //date: d[0],
          date: parseDate(d[0]),
          close: d[2],
          open: d[1]
        };
    
      });
    
      console.log(data);
      console.log(arrData.length);
      var length = arrData.length - 1;
    
      // Scale the range of the data
      x.domain(d3.extent(data, function(d) {
        return d.date;
      }));
      y.domain([0, d3.max(data, function(d) {
        return Math.max(d.close, d.open);
      })]);
    
      svg.append("g")
        .attr("class", "x axis")
        .attr("transform", "translate(0," + height + ")")
        .call(xAxis)
        .selectAll("text")
        .style("text-anchor", "end")
        .attr("dx", "-.8em")
        .attr("dy", ".15em")
        .attr("transform", function(d) {
          return "rotate(-65)"
        });
    
      svg.append("g")
        .attr("class", "y axis")
        .call(yAxis)
        .append("text")
        .attr("transform", "rotate(-90)")
        .attr("y", 6)
        .attr("dy", ".71em")
        .style("text-anchor", "end")
        .text("Open Issues");
    
      svg.append("path")
        .datum(data)
        .attr("class", "line")
        .attr("d", line);
    
      svg.append("path") // Add the valueline2 path.
        .attr("class", "line")
        .style("stroke", "red")
        .attr("d", line2(data))
        .text("line2");
    
      svg.append("text")
        .attr("transform", "translate(" + (width + 3) + "," + y(data[length].open) + ")")
        .attr("dy", ".35em")
        .attr("text-anchor", "start")
        .style("fill", "red")
        .text("Open");
    
      svg.append("text")
        .attr("transform", "translate(" + (width + 3) + "," + y(data[length].close) + ")")
        .attr("dy", ".35em")
        .attr("text-anchor", "start")
        .style("fill", "steelblue")
        .text("Close");
    
      //mouse over
      var focus = svg.append("g")
        .attr("class", "focus")
        .style("display", "none");
    
      focus.append("circle")
        .attr("r", 4.5);
      focus.append("circle")
        .attr("r", 4.5);
    
      var bisectDate = d3.bisector(function(d) {
        return d.date;
      }).left;
      var formatValue = d3.format(",.2f");
      var formatCurrency = function(d) {
        return +d;
      };
    
    
      focus.append("text")
        .attr("x", 9)
        .attr("dy", ".35em");
    
      svg.append("rect")
        .attr("class", "overlay")
        .attr("width", width)
        .attr("height", height)
        .on("mouseover", function() {
          var thisFocus = d3.select(d3.select(this)[0][0].parentNode).select(".focus");
          thisFocus.style("display", null);
        })
        .on("mouseout", function() {
          var thisFocus = d3.select(d3.select(this)[0][0].parentNode).select(".focus");
          thisFocus.style("display", "none");
        })
        .on("mousemove", mousemoveOpen);
    }
    
    function mousemoveOpen() {
      var x0 = x.invert(d3.mouse(this)[0]),
        i = bisectDate(data, x0, 1),
        d0 = data[i - 1],
        d1 = data[i],
        d = x0 - d0.date > d1.date - x0 ? d1 : d0;
      var thisFocus = d3.select(d3.select(this)[0][0].parentNode).select(".focus");
      thisFocus.attr("transform", "translate(" + x(d.date) + "," + y(d.open) + ")");
      thisFocus.select("text").text(formatCurrency(d.open));
    }
    body {
      font: 10px sans-serif;
    }
    .axis path,
    .axis line {
      fill: none;
      stroke: #000;
      shape-rendering: crispEdges;
    }
    .line {
      fill: none;
      stroke: steelblue;
      stroke-width: 1.5px;
    }
    .overlay {
      fill: none;
      pointer-events: all;
    }
    .focus circle {
      fill: none;
      stroke: steelblue;
    }
    .legend {
      padding: 5px;
      font: 10px sans-serif;
      background: yellow;
      box-shadow: 2px 2px 1px #888;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
    
    <body>
      <div id="chart1"></div>
      <div id="chart2"></div>
    </body>

    基本上,我所做的就是修改mouseovermouseoutmousemove,以便它抓住要更新的正确焦点元素,然后对其进行更新。

    重要的是:

    var thisFocus = d3.select(d3.select(this)[0][0].parentNode).select(".focus");
    thisFocus.attr("transform", "translate(" + x(d.date) + "," + y(d.open) + ")");
    thisFocus.select("text").text(formatCurrency(d.open));
    

    第一行获取与接收鼠标事件的图形相对应的焦点。您会在 mouseovermouseout 处理程序中看到类似的行。

    我可能会建议您首先在一个对象中单独跟踪焦点元素,然后您可以在鼠标处理函数中使用该引用。一直选择它可能会对性能产生影响,尽管在这种情况下影响不大。

    【讨论】:

    • 谢谢。我很快就会尝试一下。
    【解决方案2】:

    mousemoveOpen 在您的示例中的两个图表上都被调用。看着它,“焦点”和“数据”存在于闭包之外。当 mousemoveOpen 被调用时,两者都将从全局范围中获取并使用它们设置的最后一个值。这就是为什么最后一张图表总是更新的原因:焦点和数据变量点引用最后一张图表。

    我尝试使用您的小提琴示例,但无法正常工作。您可以使用下划线或原生 javascript 的“绑定”

    【讨论】:

      猜你喜欢
      • 2018-01-23
      • 2016-09-06
      • 2013-11-23
      • 1970-01-01
      • 1970-01-01
      • 2015-04-22
      • 2010-12-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多