一页上每个图表的D3鼠标悬停效果

时间:2014-09-26 13:07:50

标签: javascript node.js d3.js charts

我在一个页面上有多个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/ 谢谢你的帮助!

2 个答案:

答案 0 :(得分:0)

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

我尝试过你的小提琴示例,但我无法让它发挥作用。您可以使用下划线或本机javascript&#39; bind&#39;

答案 1 :(得分:0)

您非常接近该标记,但是您没有跟踪mouseoutmouseovermousemove处理程序中要更新的焦点元素

你可以这样做:

&#13;
&#13;
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));
}
&#13;
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;
}
&#13;
<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>
&#13;
&#13;
&#13;

基本上,我在那里做的是修改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处理程序中看到类似的行。

我可能建议你只是在一个对象中分别跟踪焦点元素,然后你可以在鼠标处理函数中使用该引用。一直选择它可能会对性能产生影响,但在这种情况下并非如此。