ilovelamp
ilovelamp

Reputation: 777

Basic Linechart using D3.js v4 (NOT v3)

I'm having a hard time finding an example of a line chart that doesn't use dates in D3.js v4, mostly cause I'm not sure how to create the xAxis using d3.scaleOrdinal() as I get this error (in TypeScript) when I try doing:

let xScale = d3.scaleOrdinal().domain(data.map(d => d.label)).range([0, width]);
svg.append('g') // x axis
  .attr('transform', `translate(${margin.left}, ${margin.top + height})`)
  .call(d3.axisBottom(xScale)); // <-- ERROR HERE


Error:

Argument of type 'ScaleOrdinal<string, {}>' is not assignable to parameter of type 'AxisScale<string>'.

Any super basic example on how to create a line chart with this data?:

[{label: 'A', value: 3}, {label: 'B', value: 4}, {label: 'C', value: 2}]

Thanks.

Upvotes: 2

Views: 2049

Answers (1)

Mikhail Shabrikov
Mikhail Shabrikov

Reputation: 8509

Look at this simple example of line chart with d3 version 4.5 - http://codepen.io/marcobiedermann/pen/GWGJvM

I forked it and reworked for your data - http://codepen.io/levvsha/pen/gWbXdm

const defaults = {
  width : 500,
  height: 370,
  margin: {
    top   : 15,
    right : 5,
    bottom: 35,
    left  : 60
  },
  axis: true,
  axisPadding: 5,
  xTicks: 3,
  yTicks: 3,
  lineCurve: d3.curveLinear
};

class LineChart {

  constructor(element, options) {
    Object.assign(this, defaults, options);

    this.element = element;
    this.init();
  }

  init() {
    const { margin } = this;
    const [ innerWidth, innerHeight ] = this.dimensions();

    const svg = this.svg = d3.select(this.element)
      .append('svg')
        .attr('width', this.width)
        .attr('height', this.height)
      .append('g')
        .attr('transform', `translate(${margin.left}, ${margin.top})`)

    const scaleX = this.scaleX = d3.scaleOrdinal()
      .range([0, innerWidth/2, innerWidth]);

    const scaleY = this.scaleY = d3.scaleLinear()
      .range([innerHeight, 0]);

    const xAxis = this.xAxis = d3.axisBottom(scaleX)
      .ticks(3)
      .tickValues(['A', 'B', 'C'])
      .tickPadding(8);

    const yAxis = this.yAxis = d3.axisLeft(scaleY)
      .ticks(this.yTicks)
      .tickPadding(8);

    svg
      .append('g')
        .attr('class', 'chart__axis chart__axis--x')
        .attr('transform', `translate(0, ${innerHeight + this.axisPadding})`)
        .call(xAxis);

    svg
      .append('g')
        .attr('class', 'chart__axis chart__axis--y')
        .attr('transform', `translate(${-this.axisPadding}, 0)`)
        .call(yAxis);

    svg
      .append('path')
        .attr('class', 'chart__line')

    this.line = d3.line()
      .curve(this.lineCurve)
      .x(data => scaleX(data.label))
      .y(data => scaleY(data.value));
  }

  dimensions() {
    const { margin } = this;

    return [
      this.width - margin.left - margin.right,
      this.height - margin.top - margin.bottom
    ];
  }

  renderAxis(data, options) {
    let { svg } = this;

    svg = options.animate ? svg.transition() : svg;

    svg
      .select('.chart__axis--x')
      .call(this.xAxis);

    svg
      .select('.chart__axis--y')
      .call(this.yAxis);
  }

  renderLine(data, options) {
    this.svg
      .select('.chart__line')
      .data([data])
      .transition()
      .attr('d', this.line);
  }

  render(data, options = {}) {
    this.scaleX.domain(data.map(data => data.label));
    this.scaleY.domain(d3.extent(data, data => data.value));

    if (this.axis) {
      this.renderAxis(data, options);
    }

    this.renderLine(data, options);
  }
}

const lineChart = new LineChart('.js-line-chart');

lineChart.render([{label: 'A', value: 3}, {label: 'B', value: 4}, {label: 'C', value: 2}]);

Upvotes: 3

Related Questions