Browse Source

Merge branch 'oop-core-part-2' into 'main'

OOP core part 2

See merge request chartwerk/core!19
merge-requests/20/merge
rozetko 3 years ago
parent
commit
4b3775c571
  1. 44
      src/components/grid.ts
  2. 7
      src/css/style.css
  3. 82
      src/index.ts
  4. 52
      src/models/series.ts
  5. 128
      src/models/state.ts

44
src/components/grid.ts

@ -2,49 +2,29 @@ import { GridOptions, SvgElParams } from '../types';
import * as d3 from 'd3'; import * as d3 from 'd3';
import defaultsDeep from 'lodash/defaultsDeep';
const DEFAULT_GRID_TICK_COUNT = 5;
const DEFAULT_GRID_OPTIONS: GridOptions = {
x: {
enabled: true,
ticksCount: DEFAULT_GRID_TICK_COUNT,
},
y: {
enabled: true,
ticksCount: DEFAULT_GRID_TICK_COUNT,
},
}
// Grid Class - is a core component, which can be a separate Pod in the future. (but not in current Pod terminology) // Grid Class - is a core component, which can be a separate Pod in the future. (but not in current Pod terminology)
// All components have construcor with required args: svg element which will be filled with this component and options for it. // All components have construcor with required args: svg element which will be filled with this component and options for it.
// All compoтents have a reqiured method "render", which will be called in core costructor. <- this solution is temporary. // All compoтents have a reqiured method "render", which will be called in core costructor. <- this solution is temporary.
// Each component has its own default options.
// svgElement should be a separate class with its own height, width, xScale, yScale params to avoid SvgElParams as argument. // svgElement should be a separate class with its own height, width, xScale, yScale params to avoid SvgElParams as argument.
// We have a general problem with passing d3 as argument everywhere. Fix it, and remove from arg in constructor here. // We have a general problem with passing d3 as argument everywhere. Fix it, and remove from arg in constructor here.
export class Grid { export class Grid {
protected gridOptions: GridOptions;
constructor( constructor(
private _svgEl: d3.Selection<SVGElement, unknown, null, undefined>, private _svgEl: d3.Selection<SVGElement, unknown, null, undefined>,
private _svgElParams: SvgElParams, private _svgElParams: SvgElParams,
_gridOptions: GridOptions, protected gridOptions: GridOptions,
) { ) {}
this.gridOptions = this.setOptionDefaults(_gridOptions);
}
protected setOptionDefaults(gridOptions: GridOptions): GridOptions {
return defaultsDeep(gridOptions, DEFAULT_GRID_OPTIONS);
}
public render(): void { public render(): void {
// TODO: temporary. Move out of here this.clear();
this._svgEl.selectAll('.grid').remove();
this.renderGridLinesX(); this.renderGridLinesX();
this.renderGridLinesY(); this.renderGridLinesY();
this.updateStylesOfTicks(); }
clear(): void {
// TODO: temporary. Move out of here
this._svgEl.selectAll('.grid').remove();
} }
renderGridLinesX(): void { renderGridLinesX(): void {
@ -79,12 +59,4 @@ export class Grid {
.tickFormat(() => '') .tickFormat(() => '')
); );
} }
updateStylesOfTicks(): void {
// TODO: add options for these actions
this._svgEl.selectAll('.grid').selectAll('.tick')
.attr('opacity', '0.5');
this._svgEl.selectAll('.grid').select('.domain')
.style('pointer-events', 'none');
}
} }

7
src/css/style.css

@ -1,9 +1,14 @@
.grid path { .grid path {
stroke-width: 0; stroke-width: 0;
} }
.grid line { .grid line {
stroke: lightgrey; stroke: lightgrey;
stroke-opacity: 0.7; stroke-opacity: 0.7;
shape-rendering: crispEdges; shape-rendering: crispEdges;
} }
.grid .tick {
opacity: 0.5;
}
.grid .domain {
pointer-events: none;
}

82
src/index.ts

@ -1,5 +1,5 @@
import VueChartwerkPodMixin from './VueChartwerkPodMixin'; import VueChartwerkPodMixin from './VueChartwerkPodMixin';
import { PodState } from './state'; import { PodState } from './models/state';
import { Grid } from './components/grid'; import { Grid } from './components/grid';
import { CoreSeries } from './models/series'; import { CoreSeries } from './models/series';
@ -165,8 +165,7 @@ abstract class ChartwerkPod<T extends CoreSerie, O extends Options> {
height: this.height, height: this.height,
width: this.width, width: this.width,
} }
// TODO: use instanses instead of oblects this.state = new PodState(boxPararms, this.coreSeries, this.coreOptions);
this.state = new PodState(boxPararms, this.coreSeries.visibleSeries, this.coreOptions.allOptions);
} }
protected initComponents(): void { protected initComponents(): void {
@ -232,7 +231,7 @@ abstract class ChartwerkPod<T extends CoreSerie, O extends Options> {
.attr('id', 'x-axis-container') .attr('id', 'x-axis-container')
.style('pointer-events', 'none') .style('pointer-events', 'none')
.call( .call(
d3.axisBottom(this.xScale) d3.axisBottom(this.state.xScale)
.ticks(this.coreOptions.axis.x.ticksCount) .ticks(this.coreOptions.axis.x.ticksCount)
.tickSize(DEFAULT_TICK_SIZE) .tickSize(DEFAULT_TICK_SIZE)
.tickFormat(this.getAxisTicksFormatter(this.coreOptions.axis.x)) .tickFormat(this.getAxisTicksFormatter(this.coreOptions.axis.x))
@ -251,7 +250,7 @@ abstract class ChartwerkPod<T extends CoreSerie, O extends Options> {
.style('pointer-events', 'none') .style('pointer-events', 'none')
// TODO: number of ticks shouldn't be hardcoded // TODO: number of ticks shouldn't be hardcoded
.call( .call(
d3.axisLeft(this.yScale) d3.axisLeft(this.state.yScale)
.ticks(this.coreOptions.axis.y.ticksCount) .ticks(this.coreOptions.axis.y.ticksCount)
.tickSize(DEFAULT_TICK_SIZE) .tickSize(DEFAULT_TICK_SIZE)
.tickFormat(this.getAxisTicksFormatter(this.coreOptions.axis.y)) .tickFormat(this.getAxisTicksFormatter(this.coreOptions.axis.y))
@ -277,7 +276,7 @@ abstract class ChartwerkPod<T extends CoreSerie, O extends Options> {
.style('pointer-events', 'none') .style('pointer-events', 'none')
// TODO: number of ticks shouldn't be hardcoded // TODO: number of ticks shouldn't be hardcoded
.call( .call(
d3.axisRight(this.y1Scale) d3.axisRight(this.state.y1Scale)
.ticks(DEFAULT_TICK_COUNT) .ticks(DEFAULT_TICK_COUNT)
.tickSize(DEFAULT_TICK_SIZE) .tickSize(DEFAULT_TICK_SIZE)
.tickFormat(this.getAxisTicksFormatter(this.coreOptions.axis.y1)) .tickFormat(this.getAxisTicksFormatter(this.coreOptions.axis.y1))
@ -416,10 +415,10 @@ abstract class ChartwerkPod<T extends CoreSerie, O extends Options> {
.attr('fill', 'none'); .attr('fill', 'none');
} }
this.initScaleX = this.xScale.copy(); this.initScaleX = this.state.xScale.copy();
this.initScaleY = this.yScale.copy(); this.initScaleY = this.state.yScale.copy();
if(this.coreOptions.axis.y1.isActive) { if(this.coreOptions.axis.y1.isActive) {
this.initScaleY1 = this.y1Scale.copy(); this.initScaleY1 = this.state.y1Scale.copy();
} }
this.pan = d3.zoom() this.pan = d3.zoom()
.on('zoom', this.onPanning.bind(this)) .on('zoom', this.onPanning.bind(this))
@ -611,18 +610,18 @@ abstract class ChartwerkPod<T extends CoreSerie, O extends Options> {
rescaleAxisX(transformX: number): void { rescaleAxisX(transformX: number): void {
this.state.transform = { x: transformX }; this.state.transform = { x: transformX };
const rescaleX = d3.event.transform.rescaleX(this.initScaleX); const rescaleX = d3.event.transform.rescaleX(this.initScaleX);
this.xAxisElement.call(d3.axisBottom(this.xScale).scale(rescaleX)); this.xAxisElement.call(d3.axisBottom(this.state.xScale).scale(rescaleX));
this.state.xValueRange = [rescaleX.invert(0), rescaleX.invert(this.width)]; this.state.xValueRange = [rescaleX.invert(0), rescaleX.invert(this.width)];
} }
rescaleAxisY(transformY: number): void { rescaleAxisY(transformY: number): void {
this.state.transform = { y: transformY }; this.state.transform = { y: transformY };
const rescaleY = d3.event.transform.rescaleY(this.initScaleY); const rescaleY = d3.event.transform.rescaleY(this.initScaleY);
this.yAxisElement.call(d3.axisLeft(this.yScale).scale(rescaleY)); this.yAxisElement.call(d3.axisLeft(this.state.yScale).scale(rescaleY));
this.state.yValueRange = [rescaleY.invert(0), rescaleY.invert(this.height)]; this.state.yValueRange = [rescaleY.invert(0), rescaleY.invert(this.height)];
if(this.y1AxisElement) { if(this.y1AxisElement) {
const rescaleY1 = d3.event.transform.rescaleY(this.initScaleY1); const rescaleY1 = d3.event.transform.rescaleY(this.initScaleY1);
this.y1AxisElement.call(d3.axisLeft(this.y1Scale).scale(rescaleY1)); this.y1AxisElement.call(d3.axisLeft(this.state.y1Scale).scale(rescaleY1));
this.state.y1ValueRange = [rescaleY1.invert(0), rescaleY1.invert(this.height)]; this.state.y1ValueRange = [rescaleY1.invert(0), rescaleY1.invert(this.height)];
// TODO: y1 axis jumps on panning // TODO: y1 axis jumps on panning
this.y1AxisElement.selectAll('line').attr('x2', 2); this.y1AxisElement.selectAll('line').attr('x2', 2);
@ -639,7 +638,7 @@ abstract class ChartwerkPod<T extends CoreSerie, O extends Options> {
case ScrollPanOrientation.HORIZONTAL: case ScrollPanOrientation.HORIZONTAL:
// @ts-ignore // @ts-ignore
const signX = Math.sign(event.transform.x); const signX = Math.sign(event.transform.x);
const transformX = this.absXScale.invert(Math.abs(transformStep)); const transformX = this.state.absXScale.invert(Math.abs(transformStep));
let rangeX = this.state.xValueRange; let rangeX = this.state.xValueRange;
this.state.xValueRange = [rangeX[0] + signX * transformX, rangeX[1] + signX * transformX]; this.state.xValueRange = [rangeX[0] + signX * transformX, rangeX[1] + signX * transformX];
const translateX = this.state.transform.x + signX * transformStep; const translateX = this.state.transform.x + signX * transformStep;
@ -652,7 +651,7 @@ abstract class ChartwerkPod<T extends CoreSerie, O extends Options> {
signY = -signY; signY = -signY;
} }
let rangeY = this.state.yValueRange; let rangeY = this.state.yValueRange;
const transformY = this.absYScale.invert(transformStep); const transformY = this.state.absYScale.invert(transformStep);
this.deltaYTransform = this.deltaYTransform + transformStep; this.deltaYTransform = this.deltaYTransform + transformStep;
// TODO: not hardcoded bounds // TODO: not hardcoded bounds
if(this.deltaYTransform > this.height * 0.9) { if(this.deltaYTransform > this.height * 0.9) {
@ -735,23 +734,23 @@ abstract class ChartwerkPod<T extends CoreSerie, O extends Options> {
let yRange: [number, number]; let yRange: [number, number];
switch(this.coreOptions.mouseZoomEvent.orientation) { switch(this.coreOptions.mouseZoomEvent.orientation) {
case BrushOrientation.HORIZONTAL: case BrushOrientation.HORIZONTAL:
const startTimestamp = this.xScale.invert(extent[0]); const startTimestamp = this.state.xScale.invert(extent[0]);
const endTimestamp = this.xScale.invert(extent[1]); const endTimestamp = this.state.xScale.invert(extent[1]);
xRange = [startTimestamp, endTimestamp]; xRange = [startTimestamp, endTimestamp];
this.state.xValueRange = xRange; this.state.xValueRange = xRange;
break; break;
case BrushOrientation.VERTICAL: case BrushOrientation.VERTICAL:
const upperY = this.yScale.invert(extent[0]); const upperY = this.state.yScale.invert(extent[0]);
const bottomY = this.yScale.invert(extent[1]); const bottomY = this.state.yScale.invert(extent[1]);
// TODO: add min zoom y // TODO: add min zoom y
yRange = [upperY, bottomY]; yRange = [upperY, bottomY];
this.state.yValueRange = yRange; this.state.yValueRange = yRange;
break; break;
case BrushOrientation.RECTANGLE: case BrushOrientation.RECTANGLE:
const bothStartTimestamp = this.xScale.invert(extent[0][0]); const bothStartTimestamp = this.state.xScale.invert(extent[0][0]);
const bothEndTimestamp = this.xScale.invert(extent[1][0]); const bothEndTimestamp = this.state.xScale.invert(extent[1][0]);
const bothUpperY = this.yScale.invert(extent[0][1]); const bothUpperY = this.state.yScale.invert(extent[0][1]);
const bothBottomY = this.yScale.invert(extent[1][1]); const bothBottomY = this.state.yScale.invert(extent[1][1]);
xRange = [bothStartTimestamp, bothEndTimestamp]; xRange = [bothStartTimestamp, bothEndTimestamp];
yRange = [bothUpperY, bothBottomY]; yRange = [bothUpperY, bothBottomY];
this.state.xValueRange = xRange; this.state.xValueRange = xRange;
@ -762,10 +761,10 @@ abstract class ChartwerkPod<T extends CoreSerie, O extends Options> {
if(selectionAtts === undefined) { if(selectionAtts === undefined) {
break; break;
} }
const scaledX0 = this.xScale.invert(selectionAtts.x); const scaledX0 = this.state.xScale.invert(selectionAtts.x);
const scaledX1 = this.xScale.invert(selectionAtts.x + selectionAtts.width); const scaledX1 = this.state.xScale.invert(selectionAtts.x + selectionAtts.width);
const scaledY0 = this.yScale.invert(selectionAtts.y); const scaledY0 = this.state.yScale.invert(selectionAtts.y);
const scaledY1 = this.yScale.invert(selectionAtts.y + selectionAtts.height); const scaledY1 = this.state.yScale.invert(selectionAtts.y + selectionAtts.height);
xRange = [scaledX0, scaledX1]; xRange = [scaledX0, scaledX1];
yRange = [scaledY0, scaledY1]; yRange = [scaledY0, scaledY1];
this.state.xValueRange = xRange; this.state.xValueRange = xRange;
@ -777,8 +776,8 @@ abstract class ChartwerkPod<T extends CoreSerie, O extends Options> {
} }
protected zoomOut(): void { protected zoomOut(): void {
let xAxisMiddleValue: number = this.xScale.invert(this.width / 2); let xAxisMiddleValue: number = this.state.xScale.invert(this.width / 2);
let yAxisMiddleValue: number = this.yScale.invert(this.height / 2); let yAxisMiddleValue: number = this.state.yScale.invert(this.height / 2);
const centers = { const centers = {
x: xAxisMiddleValue, x: xAxisMiddleValue,
y: yAxisMiddleValue y: yAxisMiddleValue
@ -786,33 +785,6 @@ abstract class ChartwerkPod<T extends CoreSerie, O extends Options> {
this.coreOptions.callbackZoomOut(centers); this.coreOptions.callbackZoomOut(centers);
} }
// TODO: move to State
get absXScale(): d3.ScaleLinear<number, number> {
const domain = [0, Math.abs(this.state.getMaxValueX() - this.state.getMinValueX())];
return d3.scaleLinear()
.domain(domain)
.range([0, this.width]);
}
get absYScale(): d3.ScaleLinear<number, number> {
const domain = [0, Math.abs(this.state.getMaxValueY() - this.state.getMinValueY())];
return d3.scaleLinear()
.domain(domain)
.range([0, this.height]);
}
get xScale(): d3.ScaleLinear<number, number> {
return this.state.xScale;
}
get yScale(): d3.ScaleLinear<number, number> {
return this.state.yScale;
}
protected get y1Scale(): d3.ScaleLinear<number, number> {
return this.state.y1Scale;
}
getd3TimeRangeEvery(count: number): d3.TimeInterval { getd3TimeRangeEvery(count: number): d3.TimeInterval {
if(this.coreOptions.allOptions.timeInterval.timeFormat === undefined) { if(this.coreOptions.allOptions.timeInterval.timeFormat === undefined) {
return d3.timeMinute.every(count); return d3.timeMinute.every(count);

52
src/models/series.ts

@ -5,6 +5,10 @@ import lodashDefaultsDeep from 'lodash/defaultsDeep';
import lodashMap from 'lodash/map'; import lodashMap from 'lodash/map';
import lodashCloneDeep from 'lodash/cloneDeep'; import lodashCloneDeep from 'lodash/cloneDeep';
import lodashUniq from 'lodash/uniq'; import lodashUniq from 'lodash/uniq';
import lodashMin from 'lodash/min';
import lodashMinBy from 'lodash/minBy';
import lodashMax from 'lodash/max';
import lodashMaxBy from 'lodash/maxBy';
const SERIE_DEFAULTS = { const SERIE_DEFAULTS = {
@ -70,4 +74,52 @@ export class CoreSeries<T extends CoreSerie> {
get rightYRelatedSeries(): Array<T> { get rightYRelatedSeries(): Array<T> {
return this.visibleSeries.filter(serie => serie.yOrientation = yAxisOrientation.RIGHT); return this.visibleSeries.filter(serie => serie.yOrientation = yAxisOrientation.RIGHT);
} }
get minValueY(): number {
return lodashMin(
this.leftYRelatedSeries.map(
serie => lodashMinBy<number[]>(serie.datapoints, dp => dp[1])[1]
)
);
}
get maxValueY(): number {
return lodashMax(
this.leftYRelatedSeries.map(
serie => lodashMaxBy<number[]>(serie.datapoints, dp => dp[1])[1]
)
);
}
get minValueX(): number {
return lodashMin(
this.visibleSeries.map(
serie => lodashMinBy<number[]>(serie.datapoints, dp => dp[0])[0]
)
);
}
get maxValueX(): number {
return lodashMax(
this.visibleSeries.map(
serie => lodashMaxBy<number[]>(serie.datapoints, dp => dp[0])[0]
)
);
}
get minValueY1(): number {
return lodashMin(
this.rightYRelatedSeries.map(
serie => lodashMinBy<number[]>(serie.datapoints, dp => dp[1])[1]
)
);
}
get maxValueY1(): number {
return lodashMax(
this.rightYRelatedSeries.map(
serie => lodashMaxBy<number[]>(serie.datapoints, dp => dp[1])[1]
)
);
}
} }

128
src/state.ts → src/models/state.ts

@ -1,4 +1,6 @@
import { CoreSerie, Options, yAxisOrientation } from './types'; import { CoreSerie, Options, yAxisOrientation } from '../types';
import { CoreSeries } from './series';
import { CoreOptions } from './options';
import * as d3 from 'd3'; import * as d3 from 'd3';
@ -20,7 +22,6 @@ const DEFAULT_TRANSFORM = {
// TODO: replace all getters with fields. Because getters will be recalculated on each call. Use scales as example. // 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: remove duplicates in max/min values.
// TODO: PodState can be divided in two classes, but it is hard now.
// TODO: PodState.transform has conflicts with d3.zoom.event.transform. It should be synchronized. // TODO: PodState.transform has conflicts with d3.zoom.event.transform. It should be synchronized.
export class PodState<T extends CoreSerie, O extends Options> { export class PodState<T extends CoreSerie, O extends Options> {
private _xValueRange: [number, number]; private _xValueRange: [number, number];
@ -33,8 +34,8 @@ export class PodState<T extends CoreSerie, O extends Options> {
constructor( constructor(
protected boxParams: { height: number, width: number }, protected boxParams: { height: number, width: number },
protected series: T[], protected coreSeries: CoreSeries<T>,
protected options: O, protected coreOptions: CoreOptions<O>,
) { ) {
this.setInitialRanges(); this.setInitialRanges();
this.initScales(); this.initScales();
@ -55,7 +56,7 @@ export class PodState<T extends CoreSerie, O extends Options> {
protected setYScale(): void { protected setYScale(): void {
let domain = this._yValueRange; let domain = this._yValueRange;
domain = sortBy(domain) as [number, number]; domain = sortBy(domain) as [number, number];
if(this.options.axis.y.invert === true) { if(this.coreOptions.axis.y.invert === true) {
domain = reverse(domain); domain = reverse(domain);
} }
this._yScale = d3.scaleLinear() this._yScale = d3.scaleLinear()
@ -64,7 +65,10 @@ export class PodState<T extends CoreSerie, O extends Options> {
} }
protected setXScale(): void { protected setXScale(): void {
const domain = this._xValueRange; let domain = this._xValueRange;
if(this.coreOptions.axis.x.invert === true) {
domain = reverse(domain);
}
this._xScale = d3.scaleLinear() this._xScale = d3.scaleLinear()
.domain(domain) .domain(domain)
.range([0, this.boxParams.width]); .range([0, this.boxParams.width]);
@ -73,7 +77,7 @@ export class PodState<T extends CoreSerie, O extends Options> {
protected setY1Scale(): void { protected setY1Scale(): void {
let domain = this._y1ValueRange; let domain = this._y1ValueRange;
domain = sortBy(domain) as [number, number]; domain = sortBy(domain) as [number, number];
if(this.options.axis.y1.invert === true) { if(this.coreOptions.axis.y1.invert === true) {
domain = reverse(domain); domain = reverse(domain);
} }
this._y1Scale = d3.scaleLinear() this._y1Scale = d3.scaleLinear()
@ -137,117 +141,79 @@ export class PodState<T extends CoreSerie, O extends Options> {
} }
public getMinValueY(): number { public getMinValueY(): number {
if(this.isSeriesUnavailable) { if(!this.coreSeries.isSeriesAvailable) {
return DEFAULT_AXIS_RANGE[0]; return DEFAULT_AXIS_RANGE[0];
} }
if(this.options.axis.y !== undefined && this.options.axis.y.range !== undefined) { if(this.coreOptions.axis.y.range !== undefined) {
return min(this.options.axis.y.range); return min(this.coreOptions.axis.y.range);
} }
const minValue = min( return this.coreSeries.minValueY;
this.series
.filter(serie => serie.visible !== false && this.filterSerieByYAxisOrientation(serie, yAxisOrientation.LEFT))
.map(
serie => minBy<number[]>(serie.datapoints, dp => dp[1])[1]
)
);
return minValue;
} }
public getMaxValueY(): number { public getMaxValueY(): number {
if(this.isSeriesUnavailable) { if(!this.coreSeries.isSeriesAvailable) {
return DEFAULT_AXIS_RANGE[1]; return DEFAULT_AXIS_RANGE[1];
} }
if(this.options.axis.y !== undefined && this.options.axis.y.range !== undefined) { if(this.coreOptions.axis.y.range !== undefined) {
return max(this.options.axis.y.range); return max(this.coreOptions.axis.y.range);
} }
const maxValue = max( return this.coreSeries.maxValueY;
this.series
.filter(serie => serie.visible !== false && this.filterSerieByYAxisOrientation(serie, yAxisOrientation.LEFT))
.map(
serie => maxBy<number[]>(serie.datapoints, dp => dp[1])[1]
)
);
return maxValue;
} }
public getMinValueX(): number { public getMinValueX(): number {
if(this.isSeriesUnavailable) { if(!this.coreSeries.isSeriesAvailable) {
return DEFAULT_AXIS_RANGE[0]; return DEFAULT_AXIS_RANGE[0];
} }
if(this.options.axis.x !== undefined && this.options.axis.x.range !== undefined) { if(this.coreOptions.axis.x.range !== undefined) {
return min(this.options.axis.x.range); return min(this.coreOptions.axis.x.range);
} }
const minValue = min( return this.coreSeries.minValueX;
this.series
.filter(serie => serie.visible !== false)
.map(
serie => minBy<number[]>(serie.datapoints, dp => dp[0])[0]
)
);
return minValue;
} }
public getMaxValueX(): number { public getMaxValueX(): number {
if(this.isSeriesUnavailable) { if(!this.coreSeries.isSeriesAvailable) {
return DEFAULT_AXIS_RANGE[1]; return DEFAULT_AXIS_RANGE[1];
} }
if(this.options.axis.x !== undefined && this.options.axis.x.range !== undefined) {
return max(this.options.axis.x.range) if(this.coreOptions.axis.x.range !== undefined) {
return max(this.coreOptions.axis.x.range);
} }
const maxValue = max( return this.coreSeries.maxValueX;
this.series
.filter(serie => serie.visible !== false)
.map(
serie => maxBy<number[]>(serie.datapoints, dp => dp[0])[0]
)
);
return maxValue;
} }
public getMinValueY1(): number { public getMinValueY1(): number {
if(this.isSeriesUnavailable || this.options.axis.y1 === undefined || this.options.axis.y1.isActive === false) { if(!this.coreSeries.isSeriesAvailable) {
return DEFAULT_AXIS_RANGE[0]; return DEFAULT_AXIS_RANGE[0];
} }
if(this.options.axis.y1.range !== undefined) { if(this.coreOptions.axis.y1.range !== undefined) {
return min(this.options.axis.y1.range); return min(this.coreOptions.axis.y1.range);
} }
const minValue = min( return this.coreSeries.minValueY;
this.series
.filter(serie => serie.visible !== false && this.filterSerieByYAxisOrientation(serie, yAxisOrientation.RIGHT))
.map(
serie => minBy<number[]>(serie.datapoints, dp => dp[1])[1]
)
);
return minValue;
} }
public getMaxValueY1(): number { public getMaxValueY1(): number {
if(this.isSeriesUnavailable || this.options.axis.y1 === undefined || this.options.axis.y1.isActive === false) { if(!this.coreSeries.isSeriesAvailable) {
return DEFAULT_AXIS_RANGE[1]; return DEFAULT_AXIS_RANGE[1];
} }
if(this.options.axis.y1 !== undefined && this.options.axis.y1.range !== undefined) { if(this.coreOptions.axis.y1.range !== undefined) {
return max(this.options.axis.y1.range); return max(this.coreOptions.axis.y1.range);
} }
const maxValue = max( return this.coreSeries.maxValueY;
this.series
.filter(serie => serie.visible !== false && this.filterSerieByYAxisOrientation(serie, yAxisOrientation.RIGHT))
.map(
serie => maxBy<number[]>(serie.datapoints, dp => dp[1])[1]
)
);
return maxValue;
} }
get isSeriesUnavailable(): boolean { // getters for correct transform
return this.series === undefined || this.series.length === 0 || get absXScale(): d3.ScaleLinear<number, number> {
max(this.series.map(serie => serie.datapoints.length)) === 0; const domain = [0, Math.abs(this.getMaxValueX() - this.getMinValueX())];
return d3.scaleLinear()
.domain(domain)
.range([0, this.boxParams.width]);
} }
protected filterSerieByYAxisOrientation(serie: T, orientation: yAxisOrientation): boolean { get absYScale(): d3.ScaleLinear<number, number> {
if(serie.yOrientation === undefined) { const domain = [0, Math.abs(this.getMaxValueY() - this.getMinValueY())];
return true; return d3.scaleLinear()
} .domain(domain)
return serie.yOrientation === orientation; .range([0, this.boxParams.height]);
} }
} }
Loading…
Cancel
Save