diff --git a/src/models/data_processor.ts b/src/models/data_processor.ts index e69de29..6cedea2 100644 --- a/src/models/data_processor.ts +++ b/src/models/data_processor.ts @@ -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 })); + } +} diff --git a/src/types.ts b/src/types.ts index 7aff2de..1bf9934 100755 --- a/src/types.ts +++ b/src/types.ts @@ -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 - }; - discrete: { - enable: boolean; // if false -> render bars as time chart | group will not work, see examples/demo-non-discrete.html - barWidth: { - estimated?: { value: number, type?: SizeType }; - max?: number; // type always SizeType.PX - min?: number; // type always SizeType.PX + 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 }; + }; + [BarPodType.NON_DISCRETE]: { + barWidth: { + 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; -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 +}