Chartwerk Bar Pod
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

157 lines
4.9 KiB

import { ChartwerkPod, VueChartwerkPodMixin, TimeFormat, AxisFormat } from '@chartwerk/core';
import { BarConfig } from './models/bar_options';
import { BarSeries } from './models/bar_series';
import { BarAnnotation } from './models/bar_annotation';
import { DataProcessor, DataRow, DataItem } from './models/data_processor';
import { BarGroup } from './models/bar_group';
import { setBarScaleY, setBarScaleX } from './models/bar_state';
import {
BarSerie, BarOptions, DiscreteConfig, NonDiscreteConfig,
BarPodType, SizeType, CallbackEvent, Color, Opacity,
ColorFormatter, OpacityFormatter,
Datapoint, ValueX, ValueY,
} from './types';
import { findClosest } from './utils';
import * as d3 from 'd3';
import * as _ from 'lodash';
export class ChartwerkBarPod extends ChartwerkPod<BarSerie, BarOptions> {
barYScale: null | d3.ScaleLinear<number, number> = null;
dataProcessor: DataProcessor;
series: BarSeries;
options: BarConfig;
constructor(el: HTMLElement, _series: BarSerie[] = [], _options: BarOptions = {}) {
super(el, _series, _options);
this.series = new BarSeries(_series);
this.options = new BarConfig(_options);
this.dataProcessor = new DataProcessor(this.series.visibleSeries, this.options);
setBarScaleY(this.state, this.dataProcessor.dataRows, this.options);
setBarScaleX(this.state, this.dataProcessor.dataRows, this.options);
}
protected renderMetrics(): void {
if(!this.series.isSeriesAvailable) {
this.renderNoDataPointsMessage();
return;
}
this.dataProcessor.dataRows.forEach((dataRow: DataRow) => {
const barGroup = new BarGroup(
this.overlay, this.metricContainer,
dataRow, this.options, this.state,
{ width: this.width, height: this.height, zeroHorizon: this.state.yScale(0) },
this.dataProcessor.dataRows.length
);
this.renderAnnotationForGroup(barGroup, dataRow);
});
}
renderAnnotationForGroup(barGroup: BarGroup, dataRow: DataRow): void {
if(this.options.barType === BarPodType.DISCRETE) {
return;
}
const target = _.first(dataRow.items).target;
const serie = this.series.getSerieByTarget(target);
if(!serie.annotation?.enable) {
return;
}
const annotationOptions = {
size: barGroup.getGroupWidth(),
max: serie.annotation.size.max,
min: serie.annotation.size.min,
color: serie.annotation.color,
};
new BarAnnotation(this.overlay, barGroup.getGroupContainer(), annotationOptions);
}
public renderSharedCrosshair(values: { x?: number, y?: number }): void {
this.crosshair.style('display', null);
const x = this.state.xScale(values.x);
this.crosshair.select('#crosshair-line-x')
.attr('x1', x)
.attr('x2', x);
}
public hideSharedCrosshair(): void {
this.crosshair.style('display', 'none');
}
onMouseMove(): void {
// TODO: mouse move work bad with matching
const event = d3.mouse(this.chartContainer.node());
const eventX = event[0];
this.crosshair.select('#crosshair-line-x')
.attr('x1', eventX)
.attr('x2', eventX);
const dataRow = this.getDataRowFromMousePosition(eventX);
this.options.callbackMouseMove({
position: {
eventX: event[0],
eventY: event[1],
pageX: d3.event.pageX,
pageY: d3.event.pageY,
valueX: this.state.xScale.invert(event[0]),
valueY: this.state.yScale.invert(event[1]),
},
data: dataRow,
});
}
getDataRowFromMousePosition(eventX: number): DataRow | undefined {
if(!this.series.isSeriesAvailable) {
return undefined;
}
const mousePoisitionKey = Math.ceil(this.state.xScale.invert(eventX));
const keys = _.map(this.dataProcessor.dataRows, (dataRow: DataRow) => dataRow.key);
const idx = findClosest(keys, mousePoisitionKey);
return this.dataProcessor.dataRows[idx];
}
onMouseOver(): void {
this.crosshair.style('display', null);
this.crosshair.raise();
}
onMouseOut(): void {
this.options.callbackMouseOut();
this.crosshair.style('display', 'none');
}
}
// it is used with Vue.component, e.g.: Vue.component('chartwerk-bar-chart', VueChartwerkBarChartObject)
export const VueChartwerkBarChartObject = {
// alternative to `template: '<div class="chartwerk-bar-chart" :id="id" />'`
render(createElement) {
return createElement(
'div',
{
class: { 'chartwerk-bar-chart': true },
attrs: { id: this.id }
}
)
},
mixins: [VueChartwerkPodMixin],
methods: {
render() {
console.time('bar-render');
const pod = new ChartwerkBarPod(document.getElementById(this.id), this.series, this.options);
pod.render();
console.timeEnd('bar-render');
}
}
};
export {
BarSerie, BarOptions, TimeFormat, AxisFormat,
DiscreteConfig, NonDiscreteConfig,
BarPodType, SizeType, CallbackEvent, Color, Opacity,
ColorFormatter, OpacityFormatter,
Datapoint, ValueX, ValueY, DataItem, DataRow,
};