|
|
|
import { Serie, yAxisOrientation } from '../types';
|
|
|
|
import { palette } from '../colors';
|
|
|
|
|
|
|
|
import lodashDefaultsDeep from 'lodash/defaultsDeep';
|
|
|
|
import lodashMap from 'lodash/map';
|
|
|
|
import lodashCloneDeep from 'lodash/cloneDeep';
|
|
|
|
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';
|
|
|
|
import lodashIsNil from 'lodash/isNil';
|
|
|
|
import lodashIncludes from 'lodash/includes';
|
|
|
|
|
|
|
|
|
|
|
|
export const CORE_SERIE_DEFAULTS = {
|
|
|
|
alias: '',
|
|
|
|
target: '',
|
|
|
|
visible: true,
|
|
|
|
yOrientation: yAxisOrientation.LEFT,
|
|
|
|
datapoints: [],
|
|
|
|
class: '',
|
|
|
|
// fields below will be set in "fillDefaults" method
|
|
|
|
idx: undefined,
|
|
|
|
color: undefined,
|
|
|
|
};
|
|
|
|
|
|
|
|
export enum Extremum {
|
|
|
|
MIN = 'min',
|
|
|
|
MAX = 'max',
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export class CoreSeries<T extends Serie> {
|
|
|
|
_series: Array<T> = [];
|
|
|
|
|
|
|
|
constructor(series: T[], private _podDefaults?: Partial<T>) {
|
|
|
|
this.setSeries(series);
|
|
|
|
}
|
|
|
|
|
|
|
|
public updateSeries(series: T[]): void {
|
|
|
|
this.setSeries(series);
|
|
|
|
}
|
|
|
|
|
|
|
|
protected setSeries(series: T[]): void {
|
|
|
|
this._series = lodashMap(series, (serie, serieIdx) => this.fillDefaults(lodashCloneDeep(serie), serieIdx));
|
|
|
|
this.ensureSeriesValid(this._series);
|
|
|
|
}
|
|
|
|
|
|
|
|
ensureSeriesValid(series: T[]): void {
|
|
|
|
const targets = lodashMap(series, serie => serie.target);
|
|
|
|
const uniqTargets = lodashUniq(targets);
|
|
|
|
if(uniqTargets.length !== series.length) {
|
|
|
|
throw new Error(`All serie.target should be uniq`);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
protected fillDefaults(serie: T, idx: number): T {
|
|
|
|
let defaults = lodashCloneDeep(this.getDefaults());
|
|
|
|
defaults.color = palette[idx % palette.length];
|
|
|
|
defaults.idx = idx;
|
|
|
|
lodashDefaultsDeep(serie, defaults);
|
|
|
|
return serie;
|
|
|
|
}
|
|
|
|
|
|
|
|
// this getter can be overrited in Pod
|
|
|
|
protected getDefaults(): Partial<T> {
|
|
|
|
return lodashDefaultsDeep(this._podDefaults, CORE_SERIE_DEFAULTS);
|
|
|
|
}
|
|
|
|
|
|
|
|
private _isSerieEmpty(serie: T): boolean {
|
|
|
|
if(serie.datapoints.length > 0) {
|
|
|
|
for(const datapoint of serie.datapoints) {
|
|
|
|
// TODO: axis-related
|
|
|
|
if(!lodashIsNil(datapoint[1])) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
get isSeriesAvailable(): boolean {
|
|
|
|
if(this.visibleSeries.length > 0) {
|
|
|
|
const seriesEmptiness = lodashMap(this.visibleSeries, this._isSerieEmpty.bind(this));
|
|
|
|
|
|
|
|
return lodashIncludes(seriesEmptiness, false);
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
get visibleSeries(): Array<T> {
|
|
|
|
return this._series.filter(serie => serie.visible);
|
|
|
|
}
|
|
|
|
|
|
|
|
get allSeries(): Array<T> {
|
|
|
|
return this._series;
|
|
|
|
}
|
|
|
|
|
|
|
|
get leftYRelatedSeries(): Array<T> {
|
|
|
|
return this.visibleSeries.filter(serie => serie.yOrientation === yAxisOrientation.LEFT);
|
|
|
|
}
|
|
|
|
|
|
|
|
get rightYRelatedSeries(): Array<T> {
|
|
|
|
return this.visibleSeries.filter(serie => serie.yOrientation === yAxisOrientation.RIGHT);
|
|
|
|
}
|
|
|
|
|
|
|
|
get areSeriesForY1Exist(): boolean {
|
|
|
|
return this.rightYRelatedSeries.length > 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
get areSeriesForYExist(): boolean {
|
|
|
|
return this.leftYRelatedSeries.length > 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
get minValueY(): number | undefined {
|
|
|
|
return lodashMin(
|
|
|
|
this.leftYRelatedSeries.map(
|
|
|
|
serie => {
|
|
|
|
const mins = lodashMinBy<number[]>(serie.datapoints, dp => dp[1]);
|
|
|
|
return !lodashIsNil(mins) ? mins[1] : undefined;
|
|
|
|
}
|
|
|
|
)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
get maxValueY(): number | undefined {
|
|
|
|
return lodashMax(
|
|
|
|
this.leftYRelatedSeries.map(
|
|
|
|
serie => {
|
|
|
|
const maxs = lodashMaxBy<number[]>(serie.datapoints, dp => dp[1]);
|
|
|
|
return !lodashIsNil(maxs) ? maxs[1] : undefined;
|
|
|
|
}
|
|
|
|
)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
get minValueX(): number | undefined {
|
|
|
|
return lodashMin(
|
|
|
|
this.visibleSeries.map(
|
|
|
|
serie => {
|
|
|
|
const mins = lodashMinBy<number[]>(serie.datapoints, dp => dp[0]);
|
|
|
|
return !lodashIsNil(mins) ? mins[0] : undefined;
|
|
|
|
}
|
|
|
|
)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
get maxValueX(): number | undefined {
|
|
|
|
return lodashMax(
|
|
|
|
this.visibleSeries.map(
|
|
|
|
serie => {
|
|
|
|
const maxs = lodashMaxBy<number[]>(serie.datapoints, dp => dp[0]);
|
|
|
|
return !lodashIsNil(maxs) ? maxs[0] : undefined;
|
|
|
|
}
|
|
|
|
)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
get minValueY1(): number | undefined {
|
|
|
|
return lodashMin(
|
|
|
|
this.rightYRelatedSeries.map(
|
|
|
|
serie => {
|
|
|
|
const mins = lodashMinBy<number[]>(serie.datapoints, dp => dp[1]);
|
|
|
|
return !lodashIsNil(mins) ? mins[1] : undefined;
|
|
|
|
}
|
|
|
|
)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
get maxValueY1(): number | undefined {
|
|
|
|
return lodashMax(
|
|
|
|
this.rightYRelatedSeries.map(
|
|
|
|
serie => {
|
|
|
|
const maxs = lodashMaxBy<number[]>(serie.datapoints, dp => dp[1]);
|
|
|
|
return !lodashIsNil(maxs) ? maxs[1] : undefined;
|
|
|
|
}
|
|
|
|
)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|