D3js 多线图 mouseOver [英] D3js mulitline chart mouseOver

查看:43
本文介绍了D3js 多线图 mouseOver的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将 this 鼠标悬停使用的 D3js 折线图示例适应我的多线图.

I'm trying to adapt this D3js line chart example of mouse-over usage to my multi-line chart.

似乎 mousemove 函数上的 d3.mouse(this)[0] 生成以下错误:无法读取 null 的属性 'sourceEvent'".

It seems that d3.mouse(this)[0] on the mousemove function generate the following error: "Cannot read property 'sourceEvent' of null".

1 知道为什么我收到 null sourceEvent 错误吗?

1 Any idea why I get the null sourceEvent error ?

2 有关如何将鼠标悬停示例从单折线图调整为多 (n) 折线图的任何提示?

2 Any tips on how to adapt the mouse over example from a single line chart to a multi (n) line chart ?

这是一个 jsfiddle 来演示这个问题.(还有解决方案)

Here is a jsfiddle to demonstrate the issue. ( And the solution )

var myApp = angular.module('app', []);
myApp.directive("lineChart", function() {
  return {
    restrict: 'E',
    scope: {
      data: '=',
      id: '@'
    },
    link: function (scope, element, attrs) {
      scope.$watch( 'data', function ( data ) {
        d3.select("#"+attrs.id).select("svg").remove();
        if (data) {
          var margin = {top: 20, right: 20, bottom: 30, left: 40},
              width = element[ 0 ].parentElement.offsetWidth - margin.left - margin.right,
              height = element[ 0 ].parentElement.offsetHeight - margin.top - margin.bottom;
          var parseDate = d3.time.format("%d-%b-%y").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")
              .innerTickSize(-height)
              .ticks(4)
              .outerTickSize(0)
              .tickPadding(5)
              .tickFormat(function(d) { return d3.time.format('%d/%m %H:%M')(new Date(d)); });
          var yAxis = d3.svg.axis()
              .scale(y)
              .orient("left")
              .innerTickSize(-width)
              .outerTickSize(0)
              .tickPadding(10);
          var line = d3.svg.line()
              .x(function(d) { return x(d[0]); })
              .y(function(d) { return y(d[1]); });
          var svg = d3.select(element[0]).append("svg")
              .attr("width", '100%')
              .attr("height", '100%')
              .attr('viewBox','0 0 '+ element[ 0 ].parentElement.offsetWidth +' '+ element[ 0 ].parentElement.offsetHeight )
            .append("g")
              .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
          var minX = d3.min(data, function (item) { return d3.min(item.values, function (d) { return d[0]; }) });
          var maxX = d3.max(data, function (item) { return d3.max(item.values, function (d) { return d[0]; }) });
          var minY = d3.min(data, function (item) { return d3.min(item.values, function (d) { return d[1]; }) });
          var maxY = d3.max(data, function (item) { return d3.max(item.values, function (d) { return d[1]; }) });
          x.domain([minX, maxX]);
          y.domain([0, maxY]);
          svg.append("g")
              .attr("class", "x axis")
              .attr("transform", "translate(0," + height + ")")
              .call(xAxis);
          svg.append("g")
              .attr("class", "y axis")
              .call(yAxis);
          var domaine = svg.selectAll(".domaine")
              .data(data)
              .enter().append("g")
              .attr("class", "domaine");
          domaine.append("path")
              .attr("class", "line")
              .attr("d", function (d) {
                  return line(d.values);
              })
              .style("stroke", function (d) {
                return d.color;
              });
          var focus = svg.append("g")
              .attr("class", "focus")
              .style("display", "none");
          focus.append("circle")
              .attr("r", 4.5);
          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", mousemove());
          function mousemove() {              
            var x0 = x.invert(d3.mouse(this)[0]),
                i = bisectDate(data, x0, 1),
                d0 = data[i - 1],
                d1 = data[i];/*
                To adapt for multi line
                ,
                d = x0 - d0.date > d1.date - x0 ? d1 : d0;
            focus.attr("transform", "translate(" + x(d.date) + "," + y(d.close) + ")");
            focus.select("text").text(formatCurrency(d.close));*/
          }
        }
      });
    }
  };
});
function MainCtrl($scope) {
$scope.lineData = [{"key": "users","color": "#16a085",
"values": [[1413814800000,4034.418],[1413815400000,5604.155000000001]]},
{"key": "users 2","color": "#d95600",
"values": [[1413814800000,3168.183],[1413815400000,1530.8435]]}];
}

推荐答案

写作时

.on("mousemove", mousemove());

它立即调用 mousemove 函数并将其返回值作为 侦听器功能"mousemove" 事件.因为您没有正确设置 this 这就是为什么 d3.mouse(this) 返回 null.

it is immediately call the mousemove function and passes its return value as the listener function to the "mousemove" event. Because you are not setting correctly the this that is why d3.mouse(this) returns null.

修复很简单:只需传入您的 mousemove 函数作为参考,不要调用它:

The fix is very easy: just pass in your mousemove function as reference and don't call it:

.on("mousemove", mousemove);

但是,即使在此修复之后,您仍然会在 fiddle 中出现错误,因为您的 bisectDate 功能缺失...

However even after this fix you will still get an error in the fiddle because your bisectDate function is missing...

这篇关于D3js 多线图 mouseOver的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆