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'; |
||||
|
||||
type ValueX = (number | string); |
||||
export type ValueX = (number | string); |
||||
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 = { |
||||
datapoints: [ValueX, ...ValueY[]]; // [x, y, y, y, ..., y], multiple y values as stacked bars
|
||||
datapoints: Datapoint[]; |
||||
annotation?: { |
||||
color: string; |
||||
size: { |
||||
max?: number; // type always SizeType.PX
|
||||
min?: number; // type always SizeType.PX
|
||||
} |
||||
} |
||||
opacityFormatter?: (data: RowValues) => number; |
||||
colorFormatter?: (data: any) => string; |
||||
}; |
||||
color: Color; |
||||
opacityFormatter?: OpacityFormatter; |
||||
} |
||||
export type BarSerie = Serie & BarSerieAdditionalParams; |
||||
|
||||
|
||||
export type BarAdditionalOptions = { |
||||
group: { // for more than 1 serie and discrete.enable == true
|
||||
by: { x: ValueX[] }; // union bars as one group, see examples/demo-group-by.html
|
||||
size: number; // type always SizeType.PERCENT
|
||||
type: { // BarPodType.DISCRETE or BarPodType.NON_DISCRETE. Cant be both
|
||||
[BarPodType.DISCRETE]: { |
||||
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
|
||||
groupSize: { value: number, type?: SizeType.PERCENT | SizeType.PX }; |
||||
}; |
||||
discrete: { |
||||
enable: boolean; // if false -> render bars as time chart | group will not work, see examples/demo-non-discrete.html
|
||||
[BarPodType.NON_DISCRETE]: { |
||||
barWidth: { |
||||
estimated?: { value: number, type?: SizeType }; |
||||
estimated?: { value: number, type?: SizeType.UNIT | SizeType.PX }; |
||||
max?: number; // type always SizeType.PX
|
||||
min?: number; // type always SizeType.PX
|
||||
} |
||||
}; |
||||
} |
||||
} |
||||
eventsCallbacks?: { |
||||
contextMenu?: (data: any) => void; |
||||
}; |
||||
} |
||||
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 { |
||||
UNIT = 'unit', // in units of X or Y values
|
||||
PX = 'px', |
||||
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