vargburz
2 years ago
2 changed files with 87 additions and 23 deletions
@ -0,0 +1,60 @@ |
|||||||
|
import { BarSerie, BarOptions, Datapoint, Color, ValueX, OpacityFormatter } from '../types'; |
||||||
|
|
||||||
|
import * as _ from 'lodash'; |
||||||
|
|
||||||
|
export type DataRow = { |
||||||
|
key: number, // x
|
||||||
|
values: number[], // y list
|
||||||
|
colors: string[], |
||||||
|
opacity: number[], |
||||||
|
serieTarget: string, |
||||||
|
} |
||||||
|
|
||||||
|
export class DataProcessor { |
||||||
|
_formattedDataRows: DataRow[]; |
||||||
|
|
||||||
|
constructor(protected series: BarSerie[], protected options: BarOptions) { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public get dataRows(): DataRow[] { |
||||||
|
return this._formattedDataRows; |
||||||
|
} |
||||||
|
|
||||||
|
protected setDataRowsForNonDiscreteType(): void { |
||||||
|
for(let serie of this.series) { |
||||||
|
const rows = _.map(serie.datapoints, (datapoint: Datapoint) => { |
||||||
|
const values = _.tail(datapoint); |
||||||
|
return { |
||||||
|
key: datapoint[0], // x
|
||||||
|
values, // y list
|
||||||
|
colors: this.getColorsForEachValue(values, serie.color, datapoint[0], serie.target), |
||||||
|
opacity: this.getOpacityForEachValue(values, serie.opacityFormatter, datapoint[0], serie.target), |
||||||
|
target: serie.target, |
||||||
|
} |
||||||
|
}); |
||||||
|
this._formattedDataRows = _.concat(this._formattedDataRows, rows); |
||||||
|
} |
||||||
|
this._formattedDataRows = _.sortBy(this._formattedDataRows, 'key'); |
||||||
|
} |
||||||
|
|
||||||
|
getColorsForEachValue(values: number[], color: Color, key: ValueX, target: string): string[] { |
||||||
|
if(_.isString(color)) { |
||||||
|
return _.map(values, value => color); |
||||||
|
} |
||||||
|
if(_.isArray(color)) { |
||||||
|
return _.map(values, (value, i) => color[i] || 'red'); |
||||||
|
} |
||||||
|
if(_.isFunction(color)) { |
||||||
|
return _.map(values, (value, i) => (color as Function)({ value, barIndex: i, key, target })); |
||||||
|
} |
||||||
|
throw new Error(`Unknown type of serie color: ${target} ${color}`); |
||||||
|
} |
||||||
|
|
||||||
|
getOpacityForEachValue(values: number[], opacity: OpacityFormatter | undefined, key: ValueX, target: string): number[] { |
||||||
|
if(opacity === undefined) { |
||||||
|
return _.map(values, value => 1); |
||||||
|
} |
||||||
|
return _.map(values, (value, i) => opacity({ value, barIndex: i, key, target }));
|
||||||
|
} |
||||||
|
} |
@ -1,51 +1,55 @@ |
|||||||
import { Serie, Options } from '@chartwerk/core'; |
import { Serie, Options } from '@chartwerk/core'; |
||||||
|
|
||||||
type ValueX = (number | string); |
export type ValueX = (number | string); |
||||||
type ValueY = number; |
type ValueY = number; |
||||||
|
export type Datapoint = [ValueX, ...ValueY[]]; // [x, y, y, y, ..., y], multiple y values as stacked bars
|
||||||
|
export type ColorFormatter = (data: { value: ValueY, key: ValueX, barIndex: number, target: string }) => string; |
||||||
|
export type OpacityFormatter = (data: { value: ValueY, key: ValueX, barIndex: number, target: string }) => number; |
||||||
|
export type Color = string | string[] | ColorFormatter; |
||||||
|
|
||||||
export type BarSerieAdditionalParams = { |
export type BarSerieAdditionalParams = { |
||||||
datapoints: [ValueX, ...ValueY[]]; // [x, y, y, y, ..., y], multiple y values as stacked bars
|
datapoints: Datapoint[]; |
||||||
annotation?: { |
annotation?: { |
||||||
color: string; |
color: string; |
||||||
size: { |
size: { |
||||||
max?: number; // type always SizeType.PX
|
max?: number; // type always SizeType.PX
|
||||||
min?: number; // type always SizeType.PX
|
min?: number; // type always SizeType.PX
|
||||||
} |
} |
||||||
} |
}; |
||||||
opacityFormatter?: (data: RowValues) => number; |
color: Color; |
||||||
colorFormatter?: (data: any) => string; |
opacityFormatter?: OpacityFormatter; |
||||||
} |
} |
||||||
export type BarSerie = Serie & BarSerieAdditionalParams; |
export type BarSerie = Serie & BarSerieAdditionalParams; |
||||||
|
|
||||||
|
|
||||||
export type BarAdditionalOptions = { |
export type BarAdditionalOptions = { |
||||||
group: { // for more than 1 serie and discrete.enable == true
|
type: { // BarPodType.DISCRETE or BarPodType.NON_DISCRETE. Cant be both
|
||||||
by: { x: ValueX[] }; // union bars as one group, see examples/demo-group-by.html
|
[BarPodType.DISCRETE]: { |
||||||
size: number; // type always SizeType.PERCENT
|
groupBy: { x: ValueX[] }; // union bars as one group, see examples/demo-group-by.html
|
||||||
}; |
innerSize: { value: number, type?: SizeType.PERCENT | SizeType.PX }; // size of bars inside one group
|
||||||
discrete: { |
groupSize: { value: number, type?: SizeType.PERCENT | SizeType.PX }; |
||||||
enable: boolean; // if false -> render bars as time chart | group will not work, see examples/demo-non-discrete.html
|
}; |
||||||
barWidth: { |
[BarPodType.NON_DISCRETE]: { |
||||||
estimated?: { value: number, type?: SizeType }; |
barWidth: { |
||||||
max?: number; // type always SizeType.PX
|
estimated?: { value: number, type?: SizeType.UNIT | SizeType.PX }; |
||||||
min?: number; // type always SizeType.PX
|
max?: number; // type always SizeType.PX
|
||||||
|
min?: number; // type always SizeType.PX
|
||||||
|
} |
||||||
} |
} |
||||||
}; |
} |
||||||
eventsCallbacks?: { |
eventsCallbacks?: { |
||||||
contextMenu?: (data: any) => void; |
contextMenu?: (data: any) => void; |
||||||
}; |
}; |
||||||
} |
} |
||||||
export type BarOptions = Options & Partial<BarAdditionalOptions>; |
export type BarOptions = Options & Partial<BarAdditionalOptions>; |
||||||
export type RowValues = { |
|
||||||
key: number, |
|
||||||
values: number[], |
|
||||||
additionalValues: (null | number)[], // values in datapoints third column
|
|
||||||
colors: (string | ((data: any) => string))[], |
|
||||||
serieTarget: string[], |
|
||||||
} |
|
||||||
|
|
||||||
export enum SizeType { |
export enum SizeType { |
||||||
UNIT = 'unit', // in units of X or Y values
|
UNIT = 'unit', // in units of X or Y values
|
||||||
PX = 'px', |
PX = 'px', |
||||||
PERCENT = 'percent', // from 0 to 100
|
PERCENT = 'percent', // from 0 to 100
|
||||||
} |
} |
||||||
|
|
||||||
|
export enum BarPodType { |
||||||
|
DISCRETE = 'discrete', // render bars as groups
|
||||||
|
NON_DISCRETE = 'non-discrete', // render bars as time chart
|
||||||
|
} |
||||||
|
Loading…
Reference in new issue