scaleQuantize,基于高度的颜色条

时间:2019-12-03 20:54:05

标签: javascript angular d3.js

我在这里有一个演示

https://stackblitz.com/edit/basic-bar-mt-pjt62p?file=src%2Fapp%2Fbar-chart.ts

它是Angular应用程序中的D3条形图。

我想根据那里的高度更改条形的颜色。

我正在尝试使用d3.scaleQuantize()来做到这一点。

this.q_scale = d3.scaleQuantize()
  .domain([ 600, 1000, d3.max( data, (d) => d.value) ])
  .range(['blue', 'green', 'red']); 

我正在传递范围内的颜色,我认为域将使用这些颜色。

小于600的条为蓝色,大于600的条为绿色,小于1000的条为红色。

d3.scaleQuantize()是执行此操作的正确方法。

如果是的话,我在做什么错

import { Component, Input, ElementRef, OnChanges, SimpleChanges, SimpleChange, ViewChild, HostListener } from "@angular/core";
import * as d3 from 'd3';

interface FLChart{
  date: string,
    value: number
}

@Component({
  selector: 'bar-chart',
  templateUrl: './bar-chart.html'
})

export class StackedChartCompoent {
  @Input() data: FLChart[];

  private margin = { top: 40, right: 20, bottom: 50, left: 40 };
  private w: number;
  private h: number = 400;
  private width: number;  
  private height = this.h - this.margin.top - this.margin.bottom;

  private x: any;
  private y: any;
  private y_axis: any;
  private x_axis: any;
  private svg: any;
  private g: any;
  private chart: any;
  private tooltip: any;
  private xAxis:any
  private yAxis:any
  private xScale:any
  private yScale:any
  private color:any

  private resizeTimeout: any;

  private qDomain = [500, 1000, 1500];
  private qRange = ['blue', 'green', 'red']

  @ViewChild('chartContainer')elementView: ElementRef;

    @HostListener('window:resize')
    onWindowResize() {

        if (this.resizeTimeout) {
            clearTimeout(this.resizeTimeout);
        }
        this.resizeTimeout = setTimeout((() => {
            this.w = this.elementView.nativeElement.offsetWidth;
            this.width = this.w - this.margin.left - this.margin.right;

            this.initScales();
            this.createAxis();
            this.drawUpdate(this.data);

        }).bind(this), 10);

    }

  constructor(private container: ElementRef) {}

  ngOnInit() {
    this.w = this.elementView.nativeElement.offsetWidth;
        this.width = this.w - this.margin.left - this.margin.right;
    this.initScales();
    this.initSvg();
    this.createAxis();
    this.drawUpdate(this.data);
  }

//----------------------- initScales

  private initScales() {
    this.x = d3.scaleBand()
      .range([0, this.width])
      .padding(.15)

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

  }

//----------------------- initSvg

  private initSvg() {

    this.svg = d3.select(this.container.nativeElement)
      .select('.chart-container')
      .append('svg')


    this.chart = this.svg.append('g')
      .attr("transform", "translate(" + this.margin.left + "," + this.margin.top + ")")  
  }

  private createAxis(){
        this.y_axis = d3.axisLeft(this.y)
                .tickPadding(10)
                .ticks(10)

        this.x_axis = d3.axisBottom(this.x)
                .scale(this.x)
                .tickPadding(10);

        this.chart.append("g").classed('y-axis', true);
        this.chart.append("g").classed('x-axis', true);
    }

//----------------------- drawUpdate

  private drawUpdate(data){
    this.x.domain(data.map( (d) => d.date) );

    this.y.domain([0, d3.max( data, (d) => d.value) ]);

    this.color = d3.scaleThreshold()
      .domain([600, 800])
      .range(['blue', 'green', 'red']); 

    const bar = this.chart.selectAll(".bar")
      .data(data)

      ///Enter
      bar.enter()
        .append("rect")
        .classed('bar', true)
        .attr('x', (d) => this.x(d.date))
        .attr("width", this.x.bandwidth())
        .attr("y", (d) => this.y(d.value))
        .attr("height", (d) => this.height - this.y(d.value))
        .attr('fill', (d) => {
          return this.color(d)
        });

      bar
        .attr('x', (d) => this.x(d.date))
        .attr("width", this.x.bandwidth())
        .attr("y", (d) => this.y(d.value))
        .attr("height", (d) => this.height - this.y(d.value))
        .style('fill', (d) => {
          return this.color(d)
        })
      bar.exit()
        .remove()  

      d3.select('.y-axis')
        .transition()
        .call(this.y_axis)
        .selectAll(".tick text")

      d3.select('.x-axis')
        .call(this.x_axis)
        .attr("transform", "translate(0," + this.height + ")")
        .selectAll(".tick text")   
        };


}

1 个答案:

答案 0 :(得分:1)

在已经提供的两个注释(使用阈值量表;将d.values传递到该量表)上,您对this的含义有疑问。

在回调内部,this是元素本身。所以,这:

.attr("fill", function(d){ 
    return this.q_scale(d.value)
}); 

毫无意义,因为比例(q_scale)不是元素的方法。

话虽如此,请使用箭头功能:

.attr("fill", (d) => this.q_scale(d.value));

或绑定其他this

.attr("fill", function(d){ 
    return this.q_scale(d.value)
}.bind(this));

以下是您的代码所做的更改:https://stackblitz.com/edit/basic-bar-mt-zehzcv?file=src/app/bar-chart.ts