Browse Source

Merge branch 'bar-titles' into 'main'

Bar Annotations

See merge request chartwerk/bar-pod!3
merge-requests/4/merge
Alexander Velikiy 3 years ago
parent
commit
e31ada2e2c
  1. 29
      demo.html
  2. 3
      dist/index.d.ts
  3. 2
      dist/index.js
  4. 5
      dist/types.d.ts
  5. 6375
      package-lock.json
  6. 4
      package.json
  7. 49
      src/index.ts
  8. 8
      src/types.ts

29
demo.html

@ -13,7 +13,7 @@
var pod = new ChartwerkBarPod(
document.getElementById('chart'),
[
{ target: 'test11', datapoints: getData(), matchedKey: 'm-1', color: 'red' },
{ 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' },
@ -29,7 +29,11 @@
maxBarWidth: 20,
zoomEvents: {
scroll: { zoom: { isActive: false }, pan: { isActive: false } },
}
},
annotations: [
{ key: 'm-1', color: 'red' },
{ key: 'm-2', color: 'green' }
]
}
);
console.time('render');
@ -39,23 +43,14 @@
function getData() {
return [
[100, 15], [110, 20], [300, 10],
[100, 15], [110, 20], [300, 10], [100, 15], [110, 20], [300, 10], [100, 15], [110, 20], [300, 10],
[100, 15], [110, 20], [300, 10], [100, 15], [110, 20], [300, 10], [100, 15], [110, 20], [300, 10], [100, 15], [110, 20], [300, 10],
[100, 15], [110, 20], [300, 10], [100, 15], [110, 20], [300, 10], [100, 15], [110, 20], [300, 10], [100, 15], [110, 20], [300, 10],
[100, 15], [110, 20], [300, 10], [100, 15], [110, 20], [300, 10], [100, 15], [110, 20], [300, 10], [100, 15], [110, 20], [300, 10],
[100, 15], [110, 20], [300, 10], [100, 15], [110, 20], [300, 10], [100, 15], [110, 20], [300, 10], [100, 15], [110, 20], [300, 10],
[100, 15], [110, 20], [300, 10], [100, 15], [110, 20], [300, 10], [100, 15], [110, 20], [300, 10], [100, 15], [110, 20], [300, 10],
[100, 15], [110, 20], [300, 10], [100, 15], [110, 20], [300, 10], [100, 15], [110, 20], [300, 10], [100, 15], [110, 20], [300, 10],
[100, 15], [110, 20], [300, 10], [100, 15], [110, 20], [300, 10], [100, 15], [110, 20], [300, 10], [100, 15], [110, 20], [300, 10],
[100, 15], [110, 20], [300, 10], [100, 15], [110, 20], [300, 10], [100, 15], [110, 20], [300, 10], [100, 15], [110, 20], [300, 10],
[100, 15], [110, 20], [300, 10], [100, 15], [110, 20], [300, 10], [100, 15], [110, 20], [300, 10], [100, 15], [110, 20], [300, 10],
[100, 15], [110, 20], [300, 10], [100, 15], [110, 20], [300, 10], [100, 15], [110, 20], [300, 10], [100, 15], [110, 20], [300, 10],
[100, 15], [110, 20], [300, 10], [100, 15], [110, 20], [300, 10], [100, 15], [110, 20], [300, 10], [100, 15], [110, 20], [300, 10],
[100, 15], [110, 20], [300, 10], [100, 15], [110, 20], [300, 10], [100, 15], [110, 20], [300, 10], [100, 15], [110, 20], [300, 10],
[100, 15], [110, 20], [300, 10], [100, 15], [110, 20], [300, 10], [100, 15], [110, 20], [300, 10], [100, 15], [110, 20], [300, 10],
[100, 15], [110, 20], [300, 10], [100, 15], [110, 20], [300, 10], [100, 15], [110, 20], [300, 10], [100, 15], [110, 20], [300, 10],
];
}
</script>
</body>
</html>
<style>
.overlay {
fill: black;
}
</style>

3
dist/index.d.ts vendored

@ -2,12 +2,12 @@ import { ChartwerkPod, TickOrientation, TimeFormat, AxisFormat } from '@chartwer
import { BarTimeSerie, BarOptions, RowValues } from './types';
import * as d3 from 'd3';
export declare class ChartwerkBarPod extends ChartwerkPod<BarTimeSerie, BarOptions> {
metricsContainer: any;
barYScale: null | d3.ScaleLinear<number, number>;
constructor(el: HTMLElement, _series?: BarTimeSerie[], _options?: BarOptions);
protected renderMetrics(): void;
setBarPodScales(): void;
renderSerie(data: any): void;
getTrianglePath(x: number, y: number, length: number): string;
getBarOpacity(rowValues: RowValues): number;
mergeMacthedSeriesAndSort(matchedSeries: any[]): any;
get seriesUniqKeys(): string[];
@ -77,6 +77,7 @@ export declare const VueChartwerkBarChartObject: {
panning(range: any): void;
contextMenu(evt: any): void;
sharedCrosshairMove(event: any): void;
renderStart(): void;
renderEnd(): void;
};
}[];

2
dist/index.js vendored

File diff suppressed because one or more lines are too long

5
dist/types.d.ts vendored

@ -12,6 +12,10 @@ export declare type BarOptionsParams = {
minBarWidth: number;
matching: boolean;
opacityFormatter: (data: RowValues) => number;
annotations: {
key: string;
color: string;
}[];
};
export declare type BarOptions = Options & Partial<BarOptionsParams>;
export declare type RowValues = {
@ -19,4 +23,5 @@ export declare type RowValues = {
values: number[];
additionalValues: (null | number)[];
colors: string[];
serieTarget: string[];
};

6375
package-lock.json generated

File diff suppressed because it is too large Load Diff

4
package.json

@ -1,6 +1,6 @@
{
"name": "@chartwerk/bar-pod",
"version": "0.2.5",
"version": "0.2.6",
"description": "Chartwerk bar pod",
"main": "dist/index.js",
"scripts": {
@ -15,7 +15,7 @@
"author": "CorpGlory",
"license": "Apache-2.0",
"dependencies": {
"@chartwerk/core": "gitlab:chartwerk/core#23b38f67809f64f021ea40998f8033c9a5100b31"
"@chartwerk/core": "0.3.10"
},
"devDependencies": {
"@types/d3": "^5.7.2",

49
src/index.ts

@ -13,7 +13,6 @@ const DEFAULT_BAR_OPTIONS: BarOptions = {
}
export class ChartwerkBarPod extends ChartwerkPod<BarTimeSerie, BarOptions> {
metricsContainer: any;
barYScale: null | d3.ScaleLinear<number, number> = null;
constructor(el: HTMLElement, _series: BarTimeSerie[] = [], _options: BarOptions = {}) {
@ -29,16 +28,6 @@ export class ChartwerkBarPod extends ChartwerkPod<BarTimeSerie, BarOptions> {
this.setBarPodScales();
// container for clip path
const clipContatiner = this.chartContainer
.append('g')
.attr('clip-path', `url(#${this.rectClipId})`)
.attr('class', 'metrics-container');
// container for panning
this.metricsContainer = clipContatiner
.append('g')
.attr('class', ' metrics-rect');
if(this.options.matching === false || this.seriesUniqKeys.length === 0) {
const zippedData = this.getZippedDataForRender(this.visibleSeries);
this.renderSerie(zippedData);
@ -58,11 +47,10 @@ export class ChartwerkBarPod extends ChartwerkPod<BarTimeSerie, BarOptions> {
}
renderSerie(data: any): void {
this.metricsContainer.selectAll(`.rects-container`)
this.metricContainer.selectAll(`.rects-container`)
.data(data)
.enter().append('g')
.attr('class', 'rects-container')
.attr('clip-path', `url(#${this.rectClipId})`)
.each((d: RowValues, i: number, nodes: any) => {
const container = d3.select(nodes[i]);
container.selectAll('rect')
@ -79,9 +67,37 @@ export class ChartwerkBarPod extends ChartwerkPod<BarTimeSerie, BarOptions> {
.attr('width', this.barWidth)
.attr('height', (val: number) => this.getBarHeight(val))
.on('contextmenu', this.contextMenu.bind(this));
// render bar annotations, its all hardcoded
if(_.isEmpty(this.options.annotations)) {
return;
}
// find all series for single matchedKey
const series = _.filter(this.series, 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);
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.max(Math.ceil(_.toNumber(rectSelection.attr('y'))) - this.barWidth, 0);
return this.getTrianglePath(x, y, this.barWidth);
})
.attr('fill', annotation.color);
});
}
// TODO: render bar labels
getTrianglePath(x: number, y: number, length: number): string {
// (x, y) - top left corner
return `M ${x - 2} ${y - 2} L ${x + length + 2} ${y - 2} L ${x + length / 2 } ${y + length - 2} z`;
}
getBarOpacity(rowValues: RowValues): number {
@ -139,8 +155,9 @@ export class ChartwerkBarPod extends ChartwerkPod<BarTimeSerie, BarOptions> {
const zippedAdditionalValuesColumn = _.zip(...additionalValuesColumns);
const zippedValuesColumn = _.zip(...valuesColumns);
const colors = _.map(series, serie => this.getBarColor(serie));
const zippedData = _.zip(keysColumn, zippedValuesColumn, zippedAdditionalValuesColumn);
const data = _.map(zippedData, row => { return { key: row[0], values: row[1], additionalValues: row[2], colors } });
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 } });
return data;
}

8
src/types.ts

@ -13,11 +13,17 @@ export type BarOptionsParams = {
minBarWidth: number; // in px
matching: boolean;
opacityFormatter: (data: RowValues) => number;
annotations: {
key: string, // matchedKey from series
// TODO: add enum with "triangle" option
color: string,
}[];
}
export type BarOptions = Options & Partial<BarOptionsParams>;
export type RowValues = {
key: number,
values: number[],
additionalValues: (null | number)[], // values in datapoints third column
colors: string[]
colors: string[],
serieTarget: string[],
}

Loading…
Cancel
Save