Compare commits

...

44 Commits

Author SHA1 Message Date
rozetko 18a88e422c 0.8.1 2 months ago
rozetko 3b837a94a5 Merge pull request 'Fix bar width calculation' (#7) from fix-bar-width-calculation into main 2 months ago
rozetko 0302ed6c62 hotfix 2 months ago
rozetko 1b4a894460 revert 2 months ago
rozetko 71a0bc4e3b fix bar width calculation 2 months ago
rozetko 509adf0543 0.8.0 10 months ago
rozetko e2b41ac100 upd package json 10 months ago
rozetko 4a3ce4f26d revert to 0.6.6 10 months ago
rozetko f16667f6ef Merge pull request 'Update dependencies' (#1) from upd-deps into main 1 year ago
rozetko 1a557a3c5b 0.7.2 1 year ago
rozetko 4da741a9f8 upd deps 1 year ago
rozetko 22af590e1d 0.7.1 2 years ago
rozetko 246d47c923 hotfix: support empty series 2 years ago
vargburz 2fa25b2dcc 0.7.0 2 years ago
Alexander Velikiy 22809f9a01 Merge branch 'bar-pod-refactoring' into 'main' 2 years ago
vargburz 91d5fe35a1 Bar Pod: Discrete and Non-Discrete types 2 years ago
vargburz 3777ba470c try to adddiscrete type 2 years ago
vargburz cdd03b410c init data processor with non discrete type 2 years ago
vargburz 032d80188e new data and options formats 2 years ago
vargburz 135a286bf3 move bar annotations to a separate model 2 years ago
vargburz 01136eece8 0.6.6 2 years ago
Alexander Velikiy 038f8e2272 Merge branch 'fix-bar-color-formatter' into 'main' 2 years ago
vargburz fa17465b97 remove some unused types 2 years ago
vargburz 4d41cb5373 fix color formatter 2 years ago
rozetko 1aea1edf22 0.6.5 2 years ago
rozetko b75ae144f6 Merge branch 'bars-handle-mouse-out-event' into 'main' 2 years ago
rozetko f7a5ccfff9 handle non-existing `this.overlay` case 2 years ago
rozetko f597a2ac47 fix indentation 2 years ago
rozetko 790b9671f7 minor refactoring 2 years ago
rozetko 70b077286b bars: handle `mouseout` event 2 years ago
rozetko b8e47469de 0.6.4 2 years ago
rozetko e241deffe0 Merge branch 'bar-events-fixes' into 'main' 2 years ago
rozetko 578d642dd2 upd core to 0.6.10 2 years ago
rozetko ae6aa53901 bar events fixes 2 years ago
rozetko 42a8fe4adc Merge branch 'do-not-pan-on-bars' into 'main' 2 years ago
rozetko 182bc4cc98 0.6.3 2 years ago
rozetko f3b20926f7 do not pan on bars drag 2 years ago
vargburz 936bdb62f5 fix annotations 2 years ago
vargburz fd3e15d30f use new core with models 3 years ago
vargburz ffc79f96c8 0.6.0-beta 3 years ago
vargburz 5c8edae96e core init 3 years ago
vargburz 68c42bdabc 0.5.3 3 years ago
vargburz 56177d6060 0.5.2 3 years ago
vargburz 190eecbae2 stable core version 3 years ago
  1. 17
      examples/demo.html
  2. 20
      package.json
  3. 225
      src/index.ts
  4. 50
      src/models/bar_options.ts
  5. 15
      src/models/bar_series.ts
  6. 35
      src/types.ts
  7. 5132
      yarn.lock

17
examples/demo.html

@ -13,10 +13,10 @@
var pod = new ChartwerkBarPod(
document.getElementById('chart'),
[
{ target: 'test11', datapoints: getData(), matchedKey: 'm-1', color: 'red' },
{ target: 'test12', datapoints: [[100, 10], [200, 20], [300, 10]], matchedKey: 'm-1', color: 'green' },
{ target: 'test21', datapoints: [[130, 10], [230, 26], [330, 15]], matchedKey: 'm-2', color: 'yellow'},
{ target: 'test22', datapoints: [[130, 10], [230, 27], [330, 10]], matchedKey: 'm-2', color: 'blue' },
{ target: 'test11', datapoints: getData(), matchedKey: 'm-1', color: 'red', colorFormatter: (data) => ['green', 'yellow'][data.rowIndex] },
// { target: 'test12', datapoints: [[100, 10], [200, 20], [300, 10]], matchedKey: 'm-1', color: 'green' },
// { target: 'test21', datapoints: [[130, 10], [230, 26], [330, 15]], matchedKey: 'm-2', color: 'yellow'},
// { target: 'test22', datapoints: [[130, 10], [230, 27], [330, 10]], matchedKey: 'm-2', color: 'blue' },
],
{
usePanning: false,
@ -24,8 +24,8 @@
x: { format: 'custom', invert: false, valueFormatter: (value) => { return 'L' + value; } },
y: { format: 'custom', invert: false, range: [0, 30], valueFormatter: (value) => { return value + '%'; } }
},
stacked: true,
matching: true,
stacked: false,
matching: false,
maxBarWidth: 20,
minBarWidth: 4,
zoomEvents: {
@ -37,7 +37,8 @@
],
eventsCallbacks: {
zoomIn: (range) => { console.log('range', range) }
}
},
renderLegend: false,
}
);
console.time('render');
@ -46,7 +47,7 @@
function getData() {
return [
[100, 15], [110, 20], [300, 10],
[100, 15], [200, 20], [300, 10],
];
}
</script>

20
package.json

@ -1,12 +1,16 @@
{
"name": "@chartwerk/bar-pod",
"version": "0.5.1",
"version": "0.8.1",
"description": "Chartwerk bar pod",
"main": "dist/index.js",
"files": [
"/dist"
],
"scripts": {
"build": "webpack --config build/webpack.prod.conf.js && webpack --config build/webpack.dev.conf.js",
"dev": "webpack --watch --config build/webpack.dev.conf.js",
"test": "echo \"Error: no test specified\" && exit 1"
"test": "echo \"Error: no test specified\" && exit 1",
"update-core": "yarn up @chartwerk/core && yarn up @chartwerk/core@latest"
},
"repository": {
"type": "git",
@ -18,12 +22,12 @@
"@chartwerk/core": "latest"
},
"devDependencies": {
"css-loader": "^3.4.2",
"style-loader": "^1.1.3",
"ts-loader": "^6.2.1",
"typescript": "^3.8.3",
"webpack": "^4.42.0",
"webpack-cli": "^3.3.11"
"css-loader": "^6.8.1",
"style-loader": "^3.3.3",
"ts-loader": "^9.4.3",
"typescript": "^5.1.3",
"webpack": "^5.87.0",
"webpack-cli": "^5.1.4"
},
"packageManager": "yarn@3.2.1"
}

225
src/index.ts

@ -1,48 +1,48 @@
import { ChartwerkPod, VueChartwerkPodMixin, TickOrientation, TimeFormat, AxisFormat } from '@chartwerk/core';
import { ChartwerkPod, VueChartwerkPodMixin, TimeFormat, AxisFormat } from '@chartwerk/core';
import { BarTimeSerie, BarOptions, RowValues } from './types';
import { BarConfig } from './models/bar_options';
import { BarSeries } from './models/bar_series';
import { BarSerie, BarOptions, RowValues } from './types';
import { findClosest } from './utils';
import * as d3 from 'd3';
import * as _ from 'lodash';
const DEFAULT_BAR_OPTIONS: BarOptions = {
renderBarLabels: false,
stacked: false,
matching: false
}
export class ChartwerkBarPod extends ChartwerkPod<BarTimeSerie, BarOptions> {
export class ChartwerkBarPod extends ChartwerkPod<BarSerie, BarOptions> {
barYScale: null | d3.ScaleLinear<number, number> = null;
_seriesDataForRendring = [];
series: BarSeries;
options: BarConfig;
constructor(el: HTMLElement, _series: BarTimeSerie[] = [], _options: BarOptions = {}) {
constructor(el: HTMLElement, _series: BarSerie[] = [], _options: BarOptions = {}) {
super(el, _series, _options);
_.defaults(this.options, DEFAULT_BAR_OPTIONS);
this.series = new BarSeries(_series);
this.options = new BarConfig(_options);
}
protected renderMetrics(): void {
if(this.series.length === 0 || this.series[0].datapoints.length === 0) {
if(!this.series.isSeriesAvailable) {
this.renderNoDataPointsMessage();
return;
}
this.setBarPodScales();
this.setSeriesDataForRendering();
this.renderSerie(this._seriesDataForRendring);
}
get isMatchingDisabled(): boolean {
return this.options.matching === false || this.seriesUniqKeys.length === 0;
return this.options.barOptions.matching === false || this.seriesUniqKeys.length === 0;
}
setSeriesDataForRendering(): void {
if(this.isMatchingDisabled) {
this._seriesDataForRendring = this.getZippedDataForRender(this.visibleSeries);
this._seriesDataForRendring = this.getZippedDataForRender(this.series.visibleSeries);
} else {
const matchedSeries = this.seriesForMatching.map(
(series: BarTimeSerie[], idx: number) => this.getZippedDataForRender(series)
(series: BarSerie[], idx: number) => this.getZippedDataForRender(series)
);
this._seriesDataForRendring = this.mergeMacthedSeriesAndSort(matchedSeries);
}
@ -59,51 +59,63 @@ export class ChartwerkBarPod extends ChartwerkPod<BarTimeSerie, BarOptions> {
.data(data)
.enter().append('g')
.attr('class', 'rects-container')
.each((d: RowValues, i: number, nodes: any) => {
const container = d3.select(nodes[i]);
.each((d: RowValues, rowIndex: number, nodes: any) => {
const container = d3.select(nodes[rowIndex]);
container.selectAll('rect')
.data(d.values)
.enter().append('rect')
.style('fill', (val, i) => d.colors[i])
.attr('opacity', () => this.getBarOpacity(d))
.attr('x', (val: number, idx: number) => {
return this.getBarPositionX(d.key, idx);
})
.attr('y', (val: number, idx: number) => {
return this.getBarPositionY(val, idx, d.values);
})
.attr('width', this.barWidth)
.attr('height', (val: number) => this.getBarHeight(val))
.on('contextmenu', this.contextMenu.bind(this));
.data(d.values)
.enter().append('rect')
.style('fill', (val, idx) => this.getBarColor(d, val, idx, rowIndex))
.attr('opacity', () => this.getBarOpacity(d))
.attr('x', (val: number, idx: number) => {
return this.getBarPositionX(d.key, idx);
})
.attr('y', (val: number, idx: number) => {
return this.getBarPositionY(val, idx, d.values);
})
.attr('width', this.barWidth)
.attr('height', (val: number) => this.getBarHeight(val))
.on('contextmenu', this.contextMenu.bind(this))
.on('mouseover', this.redirectEventToOverlay.bind(this))
.on('mousemove', this.redirectEventToOverlay.bind(this))
.on('mouseout', this.redirectEventToOverlay.bind(this))
.on('mousedown', () => { d3.event.stopPropagation(); });
// render bar annotations, its all hardcoded
if(_.isEmpty(this.options.annotations)) {
if(_.isEmpty(this.options.barOptions.annotations)) {
return;
}
// find all series for single matchedKey
const series = _.filter(this.series, serie => _.includes(d.serieTarget, serie.target));
const series = _.filter(this.series.visibleSeries, serie => _.includes(d.serieTarget, serie.target));
const matchedKeys = _.map(series, serie => serie.matchedKey); // here matchedKeys should be equal
const key = matchedKeys[0];
const lastRect = _.last(container.selectAll('rect')?.nodes());
const annotation = _.find(this.options.annotations, a => a.key === key);
const annotation = _.find(this.options.barOptions.annotations, a => a.key === key);
if(!lastRect || !key || !annotation) {
return;
}
const rectSelection = d3.select(lastRect);
// render triangle
container.append('path')
.attr('d', () => {
const x = Math.ceil(_.toNumber(rectSelection.attr('x')));
const y = Math.ceil(_.toNumber(rectSelection.attr('y')));
const options = { max: this.options.maxAnnotationSize, min: this.options.minAnnotationSize };
const options = { max: this.options.barOptions.maxAnnotationSize, min: this.options.barOptions.minAnnotationSize };
return this.getTrianglePath(x, y, this.barWidth, options);
})
.attr('fill', annotation.color);
.attr('fill', annotation.color)
.on('mouseover', this.redirectEventToOverlay.bind(this))
.on('mousemove', this.redirectEventToOverlay.bind(this))
.on('mouseout', this.redirectEventToOverlay.bind(this))
.on('mousedown', () => { d3.event.stopPropagation(); });
});
}
redirectEventToOverlay(): void {
this.overlay?.node().dispatchEvent(new MouseEvent(d3.event.type, d3.event));
}
getTrianglePath(x: number, y: number, length: number, options?: { max: number, min: number }): string {
// (x, y) - top left corner of bar
const minTriangleSize = options?.min || 6;
@ -111,8 +123,8 @@ export class ChartwerkBarPod extends ChartwerkPod<BarTimeSerie, BarOptions> {
const yOffset = 4; // offset between triangle and bar
const centerX = x + length / 2;
const correctedLength = _.clamp(length, minTriangleSize, maxTriagleSize);
const topY = Math.max(y - correctedLength - yOffset, 4);
const topY = Math.max(y - correctedLength - yOffset, 4);
const topLeftCorner = {
x: centerX - correctedLength / 2,
y: topY,
@ -132,10 +144,17 @@ export class ChartwerkBarPod extends ChartwerkPod<BarTimeSerie, BarOptions> {
}
getBarOpacity(rowValues: RowValues): number {
if(this.options.opacityFormatter === undefined) {
if(this.options.barOptions.opacityFormatter === undefined) {
return 1;
}
return this.options.opacityFormatter(rowValues);
return this.options.barOptions.opacityFormatter(rowValues);
}
getBarColor(rowValues: RowValues, val: number, i: number, rowIndex: number): string {
if(_.isFunction(rowValues.colors[i])) {
return (rowValues.colors[i] as Function)({ rowData: rowValues, val, stackedIndex: i, rowIndex });
}
return (rowValues.colors[i] as string);
}
mergeMacthedSeriesAndSort(matchedSeries: any[]) {
@ -155,27 +174,27 @@ export class ChartwerkBarPod extends ChartwerkPod<BarTimeSerie, BarOptions> {
}
get seriesUniqKeys(): string[] {
if(this.visibleSeries.length === 0) {
if(!this.series.isSeriesAvailable) {
return [];
}
const keys = this.visibleSeries.map(serie => serie.matchedKey);
const keys = this.series.visibleSeries.map(serie => serie.matchedKey);
const uniqKeys = _.uniq(keys);
const filteredKeys = _.filter(uniqKeys, key => key !== undefined);
return filteredKeys;
}
get seriesForMatching(): BarTimeSerie[][] {
get seriesForMatching(): BarSerie[][] {
if(this.seriesUniqKeys.length === 0) {
return [this.visibleSeries];
return [this.series.visibleSeries];
}
const seriesList = this.seriesUniqKeys.map(key => {
const seriesWithKey = _.filter(this.visibleSeries, serie => serie.matchedKey === key);
const seriesWithKey = _.filter(this.series.visibleSeries, serie => serie.matchedKey === key);
return seriesWithKey;
});
return seriesList;
}
getZippedDataForRender(series: BarTimeSerie[]): RowValues[] {
getZippedDataForRender(series: BarSerie[]): RowValues[] {
if(series.length === 0) {
throw new Error('There is no visible series');
}
@ -185,7 +204,7 @@ export class ChartwerkBarPod extends ChartwerkPod<BarTimeSerie, BarOptions> {
const additionalValuesColumns = _.map(series, serie => _.map(serie.datapoints, row => row[2] !== undefined ? row[2] : null));
const zippedAdditionalValuesColumn = _.zip(...additionalValuesColumns);
const zippedValuesColumn = _.zip(...valuesColumns);
const colors = _.map(series, serie => this.getBarColor(serie));
const colors = _.map(series, serie => serie.colorFormatter || serie.color);
const tagrets = _.map(series, serie => serie.target);
const zippedData = _.zip(keysColumn, zippedValuesColumn, zippedAdditionalValuesColumn, tagrets);
const data = _.map(zippedData, row => { return { key: row[0], values: row[1], additionalValues: row[2], colors, serieTarget: tagrets } });
@ -195,7 +214,7 @@ export class ChartwerkBarPod extends ChartwerkPod<BarTimeSerie, BarOptions> {
public renderSharedCrosshair(values: { x?: number, y?: number }): void {
this.crosshair.style('display', null);
const x = this.xScale(values.x);
const x = this.state.xScale(values.x);
this.crosshair.select('#crosshair-line-x')
.attr('x1', x)
.attr('x2', x);
@ -209,59 +228,40 @@ export class ChartwerkBarPod extends ChartwerkPod<BarTimeSerie, BarOptions> {
// TODO: mouse move work bad with matching
const event = d3.mouse(this.chartContainer.node());
const eventX = event[0];
if(this.isOutOfChart() === true) {
this.crosshair.style('display', 'none');
return;
}
this.crosshair.select('#crosshair-line-x')
.attr('x1', eventX)
.attr('x2', eventX);
const series = this.getSeriesPointFromMousePosition(eventX);
if(this.options.eventsCallbacks !== undefined && this.options.eventsCallbacks.mouseMove !== undefined) {
this.options.eventsCallbacks.mouseMove({
x: d3.event.pageX,
y: d3.event.pageY,
time: this.xScale.invert(eventX),
series,
chartX: eventX,
chartWidth: this.width
});
} else {
console.log('mouse move, but there is no callback');
}
this.options.callbackMouseMove({
x: d3.event.pageX,
y: d3.event.pageY,
time: this.state.xScale.invert(eventX),
series,
chartX: eventX,
chartWidth: this.width
});
}
getSeriesPointFromMousePosition(eventX: number): any[] | undefined {
if(this.series === undefined || this.series.length === 0) {
if(!this.series.isSeriesAvailable) {
return undefined;
}
const mousePoisitionKey = Math.ceil(this.xScale.invert(eventX));
const mousePoisitionKey = Math.ceil(this.state.xScale.invert(eventX));
const keys = _.map(this._seriesDataForRendring, el => el.key);
const idx = findClosest(keys, mousePoisitionKey);
return this._seriesDataForRendring[idx];
}
getBarColor(serie: any) {
if(serie.color === undefined) {
return this.getSerieColor(0);
}
return serie.color;
}
onMouseOver(): void {
this.crosshair.style('display', null);
this.crosshair.raise();
}
onMouseOut(): void {
if(this.options.eventsCallbacks !== undefined && this.options.eventsCallbacks.mouseOut !== undefined) {
this.options.eventsCallbacks.mouseOut();
} else {
console.log('mouse out, but there is no callback');
}
this.options.callbackMouseOut();
this.crosshair.style('display', 'none');
}
@ -272,30 +272,26 @@ export class ChartwerkBarPod extends ChartwerkPod<BarTimeSerie, BarOptions> {
const event = d3.mouse(this.chartContainer.node());
const eventX = event[0];
const series = this.getSeriesPointFromMousePosition(eventX);
if(this.options.eventsCallbacks !== undefined && this.options.eventsCallbacks.contextMenu !== undefined) {
this.options.eventsCallbacks.contextMenu({
x: d3.event.pageX,
y: d3.event.pageY,
time: this.xScale.invert(eventX),
series,
chartX: eventX
});
} else {
console.log('contextmenu, but there is no callback');
}
this.options.callbackContextMenu({
pageX: d3.event.pageX,
pageY: d3.event.pageY,
xVal: this.state.xScale.invert(eventX),
series,
chartX: eventX
});
}
get barWidth(): number {
// TODO: here we use first value + timeInterval as bar width. It is not a good idea
const xAxisStartValue = _.first(this.series[0].datapoints)[0];
let width = this.xScale(xAxisStartValue + this.timeInterval) / 2;
if(this.options.barWidth !== undefined) {
const xAxisStartValue = _.first(this.series.visibleSeries[0].datapoints)[0];
const xAxisEndValue = _.last(this.series.visibleSeries[0].datapoints)[0];
const timeInterval = (xAxisEndValue - xAxisStartValue) / this.series.visibleSeries[0].datapoints.length;
let width = this.state.xScale(timeInterval) / 2;
if(this.options.barOptions.barWidth !== undefined) {
// barWidth now has axis-x dimension
width = this.xScale(this.state.getMinValueX() + this.options.barWidth);
width = this.state.xScale(this.state.getMinValueX() + this.options.barOptions.barWidth);
}
let rectColumns = this.visibleSeries.length;
if(this.options.stacked === true) {
let rectColumns = this.series.visibleSeries.length;
if(this.options.barOptions.stacked === true) {
rectColumns = 1;
}
return this.updateBarWidthWithBorders(width / rectColumns);
@ -303,11 +299,11 @@ export class ChartwerkBarPod extends ChartwerkPod<BarTimeSerie, BarOptions> {
updateBarWidthWithBorders(width: number): number {
let barWidth = width;
if(this.options.minBarWidth !== undefined) {
barWidth = Math.max(barWidth, this.options.minBarWidth);
if(this.options.barOptions.minBarWidth !== undefined) {
barWidth = Math.max(barWidth, this.options.barOptions.minBarWidth);
}
if(this.options.maxBarWidth !== undefined) {
barWidth = Math.min(barWidth, this.options.maxBarWidth);
if(this.options.barOptions.maxBarWidth !== undefined) {
barWidth = Math.min(barWidth, this.options.barOptions.maxBarWidth);
}
return barWidth;
}
@ -320,8 +316,8 @@ export class ChartwerkBarPod extends ChartwerkPod<BarTimeSerie, BarOptions> {
}
getBarPositionX(key: number, idx: number): number {
let xPosition: number = this.xScale(key);
if(this.options.stacked === false) {
let xPosition: number = this.state.xScale(key);
if(this.options.barOptions.stacked === false) {
xPosition += idx * this.barWidth;
}
return xPosition;
@ -329,7 +325,7 @@ export class ChartwerkBarPod extends ChartwerkPod<BarTimeSerie, BarOptions> {
getBarPositionY(val: number, idx: number, values: number[]): number {
let yPosition: number = this.barYScale(Math.max(val, 0));
if(this.options.stacked === true) {
if(this.options.barOptions.stacked === true) {
const previousBarsHeight = _.sum(
_.map(_.range(idx), i => this.getBarHeight(values[i]))
);
@ -354,15 +350,15 @@ export class ChartwerkBarPod extends ChartwerkPod<BarTimeSerie, BarOptions> {
}
getYMaxValue(): number | undefined {
if(this.series === undefined || this.series.length === 0 || this.series[0].datapoints.length === 0) {
if(!this.series.isSeriesAvailable) {
return undefined;
}
if(this.options.axis.y !== undefined && this.options.axis.y.range !== undefined) {
if(this.options.axis.y.range) {
return _.max(this.options.axis.y.range);
}
let maxValue: number;
if(this.options.stacked === true) {
if(this.options.matching === true && this.seriesUniqKeys.length > 0) {
if(this.options.barOptions.stacked === true) {
if(this.options.barOptions.matching === true && this.seriesUniqKeys.length > 0) {
const maxValues = this.seriesForMatching.map(series => {
const valuesColumns = _.map(series, serie => _.map(serie.datapoints, row => row[1]));
const zippedValuesColumn = _.zip(...valuesColumns);
@ -370,14 +366,13 @@ export class ChartwerkBarPod extends ChartwerkPod<BarTimeSerie, BarOptions> {
});
return _.max(maxValues);
} else {
const valuesColumns = _.map(this.visibleSeries, serie => _.map(serie.datapoints, row => row[1]));
const valuesColumns = _.map(this.series.visibleSeries, serie => _.map(serie.datapoints, row => row[1]));
const zippedValuesColumn = _.zip(...valuesColumns);
maxValue = _.max(_.map(zippedValuesColumn, row => _.sum(row)));
maxValue = _.max(_.map(zippedValuesColumn, row => _.sum(row)));
}
} else {
console.log('else')
maxValue = _.max(
this.visibleSeries.map(
this.series.visibleSeries.map(
serie => _.maxBy<number[]>(serie.datapoints, dp => dp[1])[0]
)
);
@ -409,4 +404,4 @@ export const VueChartwerkBarChartObject = {
}
};
export { BarTimeSerie, BarOptions, TickOrientation, TimeFormat, AxisFormat };
export { BarSerie, BarOptions, TimeFormat, AxisFormat };

50
src/models/bar_options.ts

@ -0,0 +1,50 @@
import { CoreOptions } from '@chartwerk/core';
import { BarOptions, BarAdditionalOptions } from '../types';
import * as _ from 'lodash';
const BAR_SERIE_DEFAULTS = {
renderBarLabels: false,
stacked: false,
barWidth: undefined,
maxBarWidth: undefined,
minBarWidth: undefined,
maxAnnotationSize: undefined,
minAnnotationSize: undefined,
matching: false,
opacityFormatter: undefined,
annotations: [],
};
export class BarConfig extends CoreOptions<BarOptions> {
constructor(options: BarOptions) {
super(options, BAR_SERIE_DEFAULTS);
}
get barOptions(): BarAdditionalOptions {
return {
renderBarLabels: this._options.renderBarLabels,
stacked: this._options.stacked,
barWidth: this._options.barWidth,
maxBarWidth: this._options.maxBarWidth,
minBarWidth: this._options.minBarWidth,
maxAnnotationSize: this._options.maxAnnotationSize,
minAnnotationSize: this._options.minAnnotationSize,
matching: this._options.matching,
opacityFormatter: this._options.opacityFormatter,
annotations: this._options.annotations,
}
}
// event callbacks
callbackContextMenu(data: any): void {
if(_.has(this._options.eventsCallbacks, 'contextMenu')) {
this._options.eventsCallbacks.contextMenu(data);
}
}
get contextMenu(): (evt: any) => void {
return this._options.eventsCallbacks.contextMenu;
}
}

15
src/models/bar_series.ts

@ -0,0 +1,15 @@
import { CoreSeries } from '@chartwerk/core';
import { BarSerie } from '../types';
const BAR_SERIE_DEFAULTS = {
matchedKey: undefined,
colorFormatter: undefined
};
export class BarSeries extends CoreSeries<BarSerie> {
constructor(series: BarSerie[]) {
super(series, BAR_SERIE_DEFAULTS);
}
}

35
src/types.ts

@ -1,31 +1,34 @@
import { TimeSerie, Options } from '@chartwerk/core';
import { Serie, Options } from '@chartwerk/core';
export type BarSerieParams = {
matchedKey: string;
colorFormatter: (serie: BarTimeSerie) => string;
colorFormatter: (serie: BarSerie) => string;
}
export type BarTimeSerie = TimeSerie & Partial<BarSerieParams>;
export type BarOptionsParams = {
renderBarLabels: boolean;
stacked: boolean;
barWidth: number; // width in x axis unit
maxBarWidth: number; // in px
minBarWidth: number; // in px
maxAnnotationSize: number; // in px TODO: move to annotaions
minAnnotationSize: number; // in px
matching: boolean;
opacityFormatter: (data: RowValues) => number;
annotations: {
export type BarSerie = Serie & Partial<BarSerieParams>;
export type BarAdditionalOptions = {
renderBarLabels?: boolean;
stacked?: boolean;
barWidth?: number; // width in x axis unit
maxBarWidth?: number; // in px
minBarWidth?: number; // in px
maxAnnotationSize?: number; // in px TODO: move to annotaions
minAnnotationSize?: number; // in px
matching?: boolean;
opacityFormatter?: (data: RowValues) => number;
annotations?: {
key: string, // matchedKey from series
// TODO: add enum with "triangle" option
color: string,
}[];
eventsCallbacks?: {
contextMenu?: (data: any) => void;
}
}
export type BarOptions = Options & Partial<BarOptionsParams>;
export type BarOptions = Options & Partial<BarAdditionalOptions>;
export type RowValues = {
key: number,
values: number[],
additionalValues: (null | number)[], // values in datapoints third column
colors: string[],
colors: (string | ((data: any) => string))[],
serieTarget: string[],
}

5132
yarn.lock

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save