diff --git a/src/index.ts b/src/index.ts index acc4dd7..affe6bb 100644 --- a/src/index.ts +++ b/src/index.ts @@ -138,6 +138,7 @@ abstract class ChartwerkPod { protected deltaYTransform = 0; protected debouncedRender = debounce(this.render.bind(this), 100); + protected svgElParams: SvgElParams; // components protected grid: Grid; @@ -162,12 +163,11 @@ abstract class ChartwerkPod { this.series = cloneDeep(_series); this.d3 = _d3; - this.initPodState(); - this.d3Node = this.d3.select(this.el); this.addEventListeners(); this.createSvg(); + this.initPodState(); this.initComponents(); } @@ -233,16 +233,21 @@ abstract class ChartwerkPod { public abstract hideSharedCrosshair(): void; protected initPodState(): void { - this.state = new PodState(this.series, this.options); + const boxPararms = { + height: this.height, + width: this.width, + } + this.state = new PodState(this.d3, boxPararms, this.series, this.options); } protected initComponents(): void { // TODO: make chartContainer a separate class with SvgElParams inside to avoid duplication + // TODO: bad connection between State and Grid const svgElParams = { height: this.height, width: this.width, - xScale: this.xScale, - yScale: this.yScale, + xScale: this.state.xScale, + yScale: this.state.yScale, } this.grid = new Grid(this.d3, this.chartContainer, svgElParams, this.options.grid); @@ -848,47 +853,16 @@ abstract class ChartwerkPod { .range([0, this.height]); } - // TODO: scales should be moved to State. Because it dependes on changeable ranges get xScale(): d3.ScaleLinear { - if(this._xScale === null) { - const domain = this.state.xValueRange; - this._xScale = this.d3.scaleLinear() - .domain(domain) - .range([0, this.width]); - } - return this._xScale; + return this.state.xScale; } get yScale(): d3.ScaleLinear { - if(this._yScale === null) { - let domain = this.state.yValueRange; - domain = sortBy(domain) as [number, number]; - if(this.options.axis.y.invert === true) { - domain = reverse(domain); - } - this._yScale = this.d3.scaleLinear() - .domain(domain) - .range([this.height, 0]); // inversed, because d3 y-axis goes from top to bottom - } - return this._yScale; + return this.state.yScale; } protected get y1Scale(): d3.ScaleLinear { - if(this.state.isSeriesUnavailable || this.options.axis.y1 === undefined || this.options.axis.y1.isActive === false) { - return null; - } - // scale for y1 axis(right y axis) - if(this._y1Scale === null) { - let domain = this.state.y1ValueRange; - domain = sortBy(domain) as [number, number]; - if(this.options.axis.y1.invert === true) { - domain = reverse(domain); - } - this._y1Scale = this.d3.scaleLinear() - .domain(domain) - .range([this.height, 0]); // inversed, because d3 y-axis goes from top to bottom - } - return this._y1Scale; + return this.state.y1Scale; } getd3TimeRangeEvery(count: number): d3.TimeInterval { diff --git a/src/state.ts b/src/state.ts index e903ffb..c777193 100755 --- a/src/state.ts +++ b/src/state.ts @@ -1,10 +1,15 @@ import { TimeSerie, Options, yAxisOrientation } from './types'; +// we import only d3 types here +import * as d3 from 'd3'; + import cloneDeep from 'lodash/cloneDeep'; import min from 'lodash/min'; import minBy from 'lodash/minBy'; import max from 'lodash/max'; import maxBy from 'lodash/maxBy'; +import sortBy from 'lodash/sortBy'; +import reverse from 'lodash/reverse'; const DEFAULT_AXIS_RANGE = [0, 1]; @@ -14,29 +19,80 @@ const DEFAULT_TRANSFORM = { k: 1 } -// TODO: replace all getters with fields. Because getters will be recalculated on each call +// TODO: replace all getters with fields. Because getters will be recalculated on each call. Use scales as example. // TODO: remove duplicates in max/min values. // TODO: add scales // TODO: PodState can be divided in two classes, but it is hard now. export class PodState { private _xValueRange: [number, number]; private _yValueRange: [number, number]; - private _y1ValueRange: [number, number] | undefined = undefined; // can be undefined, because y1 - is an optional param + private _y1ValueRange: [number, number]; private _transform: { x: number, y: number, k: number } = cloneDeep(DEFAULT_TRANSFORM); + private _xScale: d3.ScaleLinear; + private _yScale: d3.ScaleLinear; + private _y1Scale: d3.ScaleLinear; constructor( + protected _d3: typeof d3, + protected boxParams: { height: number, width: number }, protected series: T[], protected options: O, ) { this.initRanges(); + this.initScales(); } protected initRanges(): void { this._xValueRange = [this.minValueX, this.maxValueX]; this._yValueRange = [this.minValueY, this.maxValueY]; - if(this.options.axis.y1.isActive) { - this._y1ValueRange = [this.minValueY1, this.maxValueY1]; + this._y1ValueRange = [this.minValueY1, this.maxValueY1]; + } + + protected initScales(): void { + this.setXScale(); + this.setYScale(); + this.setY1Scale(); + } + + protected setYScale(): void { + let domain = this._yValueRange; + domain = sortBy(domain) as [number, number]; + if(this.options.axis.y.invert === true) { + domain = reverse(domain); + } + this._yScale = this._d3.scaleLinear() + .domain(domain) + .range([this.boxParams.height, 0]); // inversed, because d3 y-axis goes from top to bottom; + } + + protected setXScale(): void { + const domain = this._xValueRange; + this._xScale = this._d3.scaleLinear() + .domain(domain) + .range([0, this.boxParams.width]); + } + + protected setY1Scale(): void { + let domain = this._y1ValueRange; + domain = sortBy(domain) as [number, number]; + if(this.options.axis.y1.invert === true) { + domain = reverse(domain); } + this._y1Scale = this._d3.scaleLinear() + .domain(domain) + .range([this.boxParams.height, 0]); // inversed, because d3 y-axis goes from top to bottom + } + + get yScale(): d3.ScaleLinear { + return this._yScale; + } + + get xScale(): d3.ScaleLinear { + return this._xScale; + } + + get y1Scale(): d3.ScaleLinear { + return this._y1Scale; } get xValueRange(): [number, number] | undefined { @@ -57,14 +113,17 @@ export class PodState { set xValueRange(range: [number, number]) { this._xValueRange = range; + this.setXScale(); } set yValueRange(range: [number, number]) { this._yValueRange = range; + this.setYScale(); } set y1ValueRange(range: [number, number]) { this._y1ValueRange = range; + this.setY1Scale(); } set transform(transform: { x?: number, y?: number, k?: number }) {