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, BarData, 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 { barYScale: null | d3.ScaleLinear = 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 mousePositionKey = this.state.xScale.invert(eventX); const keys = _.map(this.dataProcessor.dataRows, (dataRow: DataRow) => dataRow.key); let idx: number; switch(this.options.barType) { case BarPodType.DISCRETE: idx = Math.floor(mousePositionKey); break; case BarPodType.NON_DISCRETE: idx = findClosest(keys, mousePositionKey); break; default: break; } 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: '
'` 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, BarData, ColorFormatter, OpacityFormatter, Datapoint, ValueX, ValueY, DataItem, DataRow, };