chartjs / Chart.js

Simple HTML5 Charts using the <canvas> tag
https://www.chartjs.org/
MIT License
64.51k stars 11.9k forks source link

Can't register a custom scale on chartjs #10975

Open visantiago99 opened 1 year ago

visantiago99 commented 1 year ago

Expected behavior

I'm trying to create a custom scale using ChartJs version 3.9.1, where it says to create a custom scale you just need to create a class that extends Chart.Scale from 'chartjs'.

After creating this class they tell you need to set the id property in order to access this id in chart options as

scales:{y: {type: 'MyScale'}}

image

Current behavior

The problem is that the interface of Chart.Scale says that its Id is readonly, so I cant se't it.

That's my code so far:

import {
  ChartComponentLike, Tick, Scale, Chart,
} from 'chart.js';
import StringUtils from '../../../lib/string';

class PowerFactorScale extends Scale {
  public determineDataLimits() {
    const withWorstIndValue = (previousValue: number, nextValue: number) => (nextValue > 0
            && nextValue < previousValue
      ? nextValue - 0.01
      : previousValue);
    const toWorstIndValue = (dataset: any) => dataset.data.reduce(withWorstIndValue, 1);

    const withWorstCapValue = (previousValue: number, nextValue: number) => (nextValue < 0
            && nextValue > previousValue
      ? nextValue - 0.01
      : previousValue);
    const toWorstCapValue = (dataset: any) => dataset.data.reduce(withWorstCapValue, -1);

    const worstIndValues: number[] = this.chart.data.datasets.map(toWorstIndValue);
    const worstCapValues: number[] = this.chart.data.datasets.map(toWorstCapValue);

    worstIndValues.push(0.88);
    worstCapValues.push(-0.88);
    this.max = Math.min(...worstIndValues);
    this.min = Math.max(...worstCapValues);
  }

  public buildTicks(): Tick[] {
    const worstPossibleValue = Math.min(
      Math.abs(this.max),
      Math.abs(this.min),
    );

    const interval = (1 - worstPossibleValue) / 3;
    const firstInterval = 1 - interval;
    const middleInterval = 1 - interval * 2;
    const lastInterval = 1 - interval * 3;

    // eslint-disable-next-line no-return-assign
    return this.ticks = [
      lastInterval,
      middleInterval,
      firstInterval,
      1,
      -firstInterval,
      -middleInterval,
      -lastInterval,
    ].map(StringUtils.toPowerFactorScale) as unknown as Tick[];
  }

  public getLabelForIndex(index: number, datasetIndex: number) {
    return this.chart.data.datasets[datasetIndex].data[index];
  }

  public getPixelForTick(index: number) {
    const { chartArea } = this.chart;
    const chartHeight = chartArea.bottom - chartArea.top;
    const tickHeight = chartHeight / (this.ticks.length - 1);

    return index * tickHeight + chartArea.top;
  }

  public getPixelForValue(value: number) {
    const { chartArea } = this.chart;
    const chartHeight = chartArea.bottom - chartArea.top;
    const tickHeight = chartHeight / (this.ticks.length - 1);
    // eslint-disable-next-line no-mixed-operators
    const chartCenter = tickHeight * (this.ticks.length - 1) / 2 + chartArea.top;

    const worstPossibleValue = Math.min(
      Math.abs(this.max),
      Math.abs(this.min),
    );

    const interval = (1 - worstPossibleValue) / 3;
    const heightPerValue = tickHeight / interval;

    if (value === 0) {
      return chartCenter;
    }

    if (value === 1) {
      return chartCenter - 0.003 * heightPerValue;
    }

    if (value > 0) {
      return Math.min(chartHeight, chartCenter - (1 - value) * heightPerValue);
    }

    return Math.min(chartHeight, chartCenter - (-1 - value) * heightPerValue);
  }
}

PowerFactorScale.prototype.id = 'teste';

Chart.register(PowerFactorScale as unknown as ChartComponentLike);

// Chart.registry.addScales(PowerFactorScale as unknown as ChartComponentLike);

I've tried to set the id doing this.id = 'test' but it keeps saying I can't set it because its readonly.

image

Reproducible sample

https://www.typescriptlang.org/play?#

Optional extra steps/info to reproduce

No response

Possible solution

No response

Context

No response

chart.js version

3.9.1

Browser name and version

No response

Link to your project

No response

gbaron commented 1 year ago

Can you try to set the id in the class constructor?

wokis commented 5 months ago

This works for me.

export class MyScale extends Scale {
  static id: string = 'myScale';
}