d3中的多线图工具提示给出错误

时间:2018-06-13 16:59:16

标签: javascript angular d3.js

我有一个多线图,我希望有一个工具提示,以便当我将鼠标悬停在线上时,它会显示x和y轴上的点。

我的数据位于下面的某个地方,我从某处here

重新呈现鼠标事件部分

我的数据格式如下,我将它作为对象传递给组件之间的角色

{storeid: "", peoplesum: 137.14285714285714, date: "2018-06-02"}
{storeid: "", peoplesum: 139.28571428571428, date: "2018-06-03"}
{storeid: "", peoplesum: 123, date: "2018-06-04"}
{storeid: "", peoplesum: 144, date: "2018-06-05"}
{storeid: "", peoplesum: 150, date: "2018-06-06"}
{storeid: "", peoplesum: 154.28571428571428, date: "2018-06-07"}
{storeid: "", peoplesum: 159.85714285714286, date: "2018-06-08"}
{storeid: "", peoplesum: 145.71428571428572, date: "2018-06-09"}
{storeid: "", peoplesum: 129.42857142857142, date: "2018-06-10"}
{storeid: "", peoplesum: 147, date: "2018-06-11"}
{storeid: "", peoplesum: 123, date: "2018-06-12"}

代码

import { Component, OnInit, Input } from '@angular/core';

import * as d3 from "d3"
import * as d3Scale from 'd3-scale';
import * as d3Shape from 'd3-shape';
import * as d3Array from 'd3-array';
import * as d3Axis from 'd3-axis';

import {timeParse} from "d3-time-format";


@Component({
  selector: 'app-d3graph',
  template: `
    <h2>{{subtitle}}</h2>
  `
})
export class D3graphComponent implements OnInit {
  @Input()  storeIntraffic: string;
  @Input() dateForD3: string;
  @Input() peopleInSumStr: string;

  title: string = 'D3.js with Angular 2!';
  subtitle: string = 'Line Chart';
  peopleInSumArr: any[];
  private margin = {top: 20, right: 20, bottom: 30, left: 50};
  private width: number;
  private height: number;
  private x: any;
  private y: any;
  private svg: any;
  private priceline: any;
  private line: d3Shape.Line<[number, number]>;
  d3Data: any;
  dashboard_date: any;
  myArray: any[];
  groupName: string;
  data: any;
  constructor() {
    this.margin = { top: 30, right: 20, bottom: 70, left: 50 },
    this.width = 1300 - this.margin.left - this.margin.right,
    this.height = 800 - this.margin.top - this.margin.bottom;
  }

  ngOnInit() { }
  ngAfterViewChecked() {
    if (this.storeIntraffic !== undefined && typeof this.storeIntraffic === 'string') {

        this.data = JSON.parse(this.peopleInSumStr);
        this.peopleInSumArr = JSON.parse(this.peopleInSumStr);
        this.dashboard_date = this.dateForD3;
    //   this.dashboard_date = this.dateForD3;
    //   console.log('d3 this.peopleInSumArr', this.peopleInSumStr);
    //   this.peopleInSumArr = JSON.parse(this.peopleInSumStr);
    //   console.log('d3 this.peopleInSumArr jajdjhdhjd', this.peopleInSumArr);
    //   console.log('this.dateForD3', this.dateForD3);
    //   this.storeIntraffic_plot();
        this.initSvg();
        this.initAxis();
        this.drawAxis();
        this.drawLine();


    }
  }
  private initSvg() {
    d3.select("svg").remove();
    this.svg = d3.select("#svgcontainer")
    .append("svg")
        .attr("width", this.width + this.margin.left + this.margin.right)
        .attr("height", this.height + this.margin.top + this.margin.bottom)
    .append("g")
        .attr("transform", 
              "translate(" + this.margin.left + "," + this.margin.top + ")")
     .attr("stroke-width", 2);
  }
  private initAxis() {
    // Parse the date / time
    var parseDate = timeParse("%b %Y");


    // Set the ranges
    this.x = d3Scale.scaleTime().range([0, this.width]);
    this.y = d3Scale.scaleLinear().range([this.height, 0]);
  }
  private drawAxis() {
      var X = this.x;
      var Y = this.y;
      // Define the line
      this.priceline = d3Shape.line()
          .x(function (d) { return X(new Date(d.date)); })
          .y(function (d) { return Y(d.peoplesum); });
  }
  private drawLine() {
      var mindate = new Date(this.dashboard_date['startTime']),
          maxdate = new Date(this.dashboard_date['endTime']);
      this.x.domain(d3.extent([mindate, maxdate]));
      // Scale the range of the data
      var svgVar = this.svg;
      var pricelineVar = this.priceline;
      var margin = this.margin;
      var height = this.height;
      this.y.domain([0, d3.max(this.data, function (d) { return d.peoplesum; })]);
      console.log("this.data", this.data);
      // Nest the entries by symbol
      var dataNest = d3.nest()
          .key(function (d) { return d.storeid;})
          .entries(this.data);
      console.log("asdasd", dataNest);
      // set the colour scale
      var color = d3.scaleOrdinal(d3.schemeCategory10);
      console.log("width", this.width);
      console.log("width", dataNest.length);
      var legendSpace = this.width / dataNest.length; // spacing for the legend
      console.log("this.legendSpace", legendSpace);
      // Loop through each symbol / key
      dataNest.forEach(function (d, i) {
          svgVar.append("path")
              .attr("class", "line")
              .style("stroke", function () { // Add the colours dynamically
                  return d.color = color(d.key);
              })
              .on("mouseover", onMouseOver)
              .attr("d",d.peoplesum)
              .attr("d", pricelineVar(d.values))
              .attr("stroke-width", 3)
              .style("fill", "none")

                  function onMouseOver(d, i) {
            d3.select(this)
            .attr('class', 'highlight');

            d3.select(this)

               .transition()     
               .duration(200)
               //.attr('width', this.x.bandwidth() + 5)

               .attr("y", function(d) { return this.y(d.peoplesum) - 10; })
               .attr("height", function(d) { return height - this.y(d.peoplesum) + 10; })

            .append("text")
               .attr('class', 'val')
               .attr('x', function() {
                  return this.X(d.date);
               })

            .attr('y', function() {
               return this.Y(d.peoplesum) ;
            })
         }

          // Add the Legend
          svgVar.append("text")
              .attr("x", (legendSpace / 2) + i * legendSpace)  // space legend
              .attr("y", height + (margin.bottom / 2) + 5)
              .attr("class", "legend")    // style the legend
              .style("fill", function () { // Add the colours dynamically
                  return d.color = color(d.key);
              })
              .text(d.key)
              .attr("stroke-width", 3)




      });
      console.log("after", dataNest);
      // Add the X Axis
      this.svg.append("g")
          .attr("class", "axis")
          .attr("transform", "translate(0," + this.height + ")")
          .call(d3.axisBottom(this.x));

      // Add the Y Axis
      this.svg.append("g")
          .attr("class", "axis")
          .call(d3.axisLeft(this.y));

  }
  }

我不确定 pricelineVar(d.values)在这里做了什么,我得到的错误是:

**core.js:1598 ERROR TypeError: Cannot read property 'peoplesum' of undefined
    at SVGPathElement.<anonymous> (d3graph.component.ts:140)**

1 个答案:

答案 0 :(得分:0)

通过将代码更改为以下代码段,我能够解决错误

   svgVar.selectAll("path")
    .data(dataNest)
    .enter()
    .append("path")
    .attr("class", "line")
    .style("stroke", function () { // Add the colours dynamically
                  return d.color = color(d.key);
              })

     .on("mouseover", onMouseOver)
    .attr("d", function(d) { return pricelineVar(d.values); })
    .attr("fill","none");