在d3 v4分组条形图中显示更多数据

时间:2018-03-28 10:54:23

标签: javascript angular d3.js

我正在使用带角度4的d3 V4来开发分组条形图。这是我的代码。

imports;

let d3: any = D3;

@Component({
  selector: 'grouped-bar-chart',
  template: '<ng-content></ng-content>'
})
export class GroupedBarChartComponent {

  @Input('chartConfig') config: GroupedBarChartConfigModel;

  htmlElement: HTMLElement;
  host;
  width;
  height;
  innerWidth;
  innerHeight;
  margin;
  x0Scale;
  x1Scale;
  yScale;
  zScale; // color scale
  svg;
  tooltip;
  breakPoint; // used to check if we are on small screens or not
  keys;
  dataset;
  disabledSeries;

  constructor(private element: ElementRef) {
    if (this.config == null) {
      this.config = new GroupedBarChartConfigModel();
    }
    this.htmlElement = this.element.nativeElement;
    this.host = d3.select(this.element.nativeElement);
    this.innerWidth = window.innerWidth;
    this.innerHeight = window.innerHeight;
    this.breakPoint = 768;
    this.keys = []; // this holds bars contains in one cluster
    this.disabledSeries = [];
    this.margin = this.config.margin;

    this.ngOnChanges();
  }

  @HostListener('window:resize', ['$event'])
  onResize(event) {
    this.ngOnChanges();
  }

  /**
   * Every time the @Input is updated, rebuild the chart
   **/
  ngOnChanges(): void {
    if (!this.config || !this.host || this.config.dataset.length === 0) return;
    this.init();
    this.setup();
    this.buildSVG();
    this.scaleAxises();
    this.drawXAxis();
    this.drawYAxis();
    this.populate();
    this.drawLegend();
  }

  /**
   * Initialize chart dataset
   */
  init(): void {
    let data;

    this.dataset = data;
  }

  /**
   * Basically we get the window size and build the container configs
   * also we create the xScale, yScale & zScale(color scale) ranges depending on calculations
   **/
  setup(): void {
    this.keys = [];
    this.width = this.config.width - this.margin.left - this.margin.right;
    this.height = this.config.height - this.margin.top - this.margin.bottom;

    // determine the geometry of the bars and spaces the individual bars within a cluster
    this.x0Scale = d3.scaleBand().rangeRound([0, this.width]).paddingInner(0.01);

    // spaces the different clusters of bars across the page
    this.x1Scale = d3.scaleBand().padding(0.05);

    this.yScale = d3.scaleLinear().rangeRound([this.height, 0]);

    this.zScale = d3.scaleOrdinal()
      .range(GraphColorPalette.PALETTE);

    this.dataset[0].values.map((d: any) => {
      if (this.keys.indexOf(d.key) === -1) {
        this.keys.push(d.key);
      }

    });
  }

  /**
   *  build  SVG element using configurations
   **/
  buildSVG(): void {
    this.host.html('');
    this.svg = this.host.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 + ')');

    this.svg.append('rect')
      .attr('x', 0)
      .attr('y', 0)
      .attr('width', this.width)
      .attr('height', this.height)
      .style('fill', '#eee')
      .append('g')
      .attr('transform', 'translate(' + this.margin.left + ',' + this.margin.top + ')');
  }

  /**
   **/
  scaleAxises(): void {

    this.x0Scale.domain(this.dataset.map((d: any) => {
      return d.key;
    }));

    this.x1Scale.domain(this.keys).rangeRound([0, this.x0Scale.bandwidth()]);

    let maxDomain = d3.max(this.dataset, (d: any) => {
      return d3.max(this.keys, (key: any, i: number) => {
        return d.values[i].value;
      })
    });

    this.yScale.domain([0, maxDomain + 1]).nice();
  }

  /**
   * Populate the chart using
   **/
  populate(): void {
    this.drawColumns(this.x1Scale, this.keys, this.dataset);
    this.createToolTips();

    // add a title to the graph
    this.svg.append("text")
      .attr("x", (this.width / 2))
      .attr("y", 0 - (this.margin.top / 2))
      .attr("text-anchor", this.config.titlePosition)
      .attr("class", "title")
      .style("font-size", "18px")
      .style("text-decoration", "underline")
      .text(this.config.title);
  }

  drawColumns(x1Scale: any, keys: Array<string>, data: any): void {
    this.svg.append("g")
      .attr("class", "chart-layer")
      .selectAll("g")
      .data(data)
      .enter().append("g")
      .attr("transform", (d: any) => {
        return "translate(" + this.x0Scale(d.key) + ",0)";
      })
      .selectAll("rect")
      .data((d: any) => {
        return keys.map((key, i) => {
          return {id: d.key, key: key, name: d.name, value: d.values[i].value};
        });
      })
      .enter().append("rect")
      .attr("fill", (d) => {
        return this.zScale(d.key);
      })
      .attr("class", "bar")
      .style('cursor', 'pointer')
      .on("mousemove", (d: any) => {
        this.showTooltip(d);
      })
      .on("mouseout", () => {
        this.hideTooltip();
      })
      .attr("x", (d: any) => {
        return x1Scale(d.key);
      })
      .attr("y", this.height)
      .attr("width", x1Scale.bandwidth())
      .transition()
      .ease(d3.easeLinear)
      .duration(1000)
      .delay((d, i) => {
        return i * 50;
      })
      .attr("y", (d) => {
        return this.yScale(d.value);
      })
      .attr("height", (d) => {
        return Math.abs(this.height - this.yScale(d.value));
      })
  }

  createToolTips(): void {
    // Define the div for the tooltip
    this.tooltip = d3.select("body")
      .append("div")
      .attr("class", "tooltip");
  }

  showTooltip(d: any) {

    // Show tooltip
    this.tooltip.transition()
      .duration(200)
      .style("display", "inline");

    this.tooltip
      .html(d.id + "<br>" + d.name + "<br>" + d.key + ": " + d.value)
      .style("left", d3.event.pageX + 10 + "px")
      .style("top", d3.event.pageY - 25 + "px")
      .style("position", "absolute")
      .style("width", "auto")
      .style("height", "auto")
      .style("border", "0 none")
      .style("border-radius", "8px")
      .style("border-shadow", "-3px 3px 15px #888888")
      .style("padding", "5px")
      .style("text-align", "center")
      .style("font", "12px sans-serif")
      .style("background", "none repeat scroll 0 0 #fff")
      .style('color', '#000');

  }

  hideTooltip() {
    this.tooltip.transition()
      .duration(500)
      .style("display", "none");
  }

  /**
   * Create X-axis
   **/
  drawXAxis(): void {
    this.svg.append("g")
      .attr("class", "axis axis--x")
      .attr("transform", "translate(0," + this.height + ")")
      .call(d3.axisBottom(this.x0Scale)
        .tickSize(0)
        .tickPadding(6));

    // Add title to x axis
    this.svg.append("text")
      .attr("class", "axis-x--label")
      .attr("dy", "0.32em")
      .attr("fill", "#000")
      .attr("font-weight", "bold")
      .attr("text-anchor", this.config.xLabelPosition)
      .attr("transform", () => {
          switch (this.config.xLabelPosition) {
            case ChartLabelPositions.START:
              return "translate(" + (0) + "," + (this.height - (this.margin.bottom / 10) + 40) + ")";
            case ChartLabelPositions.MIDDLE:
              return "translate(" + (this.width / 2) + "," + (this.height - (this.margin.bottom / 10) + 40) + ")";
            case ChartLabelPositions.END:
              return "translate(" + (this.width) + "," + (this.height - (this.margin.bottom / 10) + 40) + ")";
            default:
              //do nothing
              break;
          }
        }
      )
      .text(this.config.xLabel);
  }

  /**
   * Create Y-axis
   **/
  drawYAxis(): void {
    this.svg.append("g")
      .attr("class", "axis axis--y")
      .call(d3.axisLeft(this.yScale).tickSize(-this.width).ticks(null, "s"))
      .append("text")
      .attr("x", 2)
      .attr("y", this.yScale(this.yScale.ticks().pop()) + 0.5)
      .attr("dy", "0.32em")
      .attr("fill", "#000")
      .attr("font-weight", "bold")
      .attr("text-anchor", this.config.yLabelPosition)
      .text(this.config.yLabel);
  }

}

我在图表中显示的数据超过500个。问题是如果有更多的数据,那么条形图没有显示。但如果我隐藏了一些关于传奇的系列,那么就会显示条形图。如何在此图表中显示更多数据。

任何建议都表示赞赏。

谢谢!

0 个答案:

没有答案