Browse Source

render annotions

merge-requests/3/head
vargburz 2 years ago
parent
commit
84f166d9fd
  1. 29
      demo.html
  2. 1
      dist/index.d.ts
  3. 2
      dist/index.js
  4. 6
      dist/types.d.ts
  5. 44
      src/index.ts
  6. 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', annotation: { enabled: true, type: 'triangle', color: 'green' } },
{ 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>

1
dist/index.d.ts vendored

@ -2,7 +2,6 @@ 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;

2
dist/index.js vendored

File diff suppressed because one or more lines are too long

6
dist/types.d.ts vendored

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

44
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,30 @@ export class ChartwerkBarPod extends ChartwerkPod<BarTimeSerie, BarOptions> {
.attr('width', this.barWidth)
.attr('height', (val: number) => this.getBarHeight(val))
.on('contextmenu', this.contextMenu.bind(this));
});
// TODO: render bar labels
// render bar annotations, its all hardcoded
if(_.isEmpty(this.options.annotations)) {
return;
}
const series = _.filter(this.series, serie => _.includes(d.serieTarget, serie.target));
const matchedKeys = _.map(series, serie => serie.matchedKey);
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);
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 `M ${x} ${y} L ${x + this.barWidth } ${y} L ${x + this.barWidth / 2} ${ y + this.barWidth / 2} z`;
})
.attr('fill', annotation.color);
});
}
getBarOpacity(rowValues: RowValues): number {
@ -139,8 +148,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
type?: string, // only "triangle" for now
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