diff --git a/examples/markers.html b/examples/markers.html new file mode 100644 index 0000000..5c1521f --- /dev/null +++ b/examples/markers.html @@ -0,0 +1,39 @@ + + + + + + + + + +
+ + + + diff --git a/src/components/markers.ts b/src/components/markers.ts new file mode 100644 index 0000000..4b8c806 --- /dev/null +++ b/src/components/markers.ts @@ -0,0 +1,51 @@ +import { MarkerSerie } from "../models/marker"; +import { PodState } from "@chartwerk/core"; +import { LineTimeSerie, LineOptions } from "../types"; + +import d3 from "d3"; + +export class Markers { + // TODO: more sentic name + private _d3Holder = null; + + constructor(private _markers: MarkerSerie[], private _state: PodState) { + } + + render(metricContainer: d3.Selection) { + if(this._d3Holder !== null) { + this._d3Holder.remove(); + } + this._d3Holder = metricContainer.append('g').attr('class', 'markers-layer'); + for (const ms of this._markers) { + this.renderMarkerSerie(ms); + } + } + + protected renderMarkerSerie(serie: MarkerSerie) { + serie.data.forEach((d) => { + let linePosition = this._state.xScale(d) as number; + this._d3Holder.append('line') + .attr('class', 'gap-line') + .attr('stroke', serie.color) + .attr('stroke-width', '1px') + .attr('stroke-opacity', '0.3') + .attr('stroke-dasharray', '4') + .attr('x1', linePosition) + .attr('x2', linePosition) + .attr('y1', 0) + // @ts-ignore // TODO: remove ignore but boxParams are protected + .attr('y2', this._state.boxParams.height) + .attr('pointer-events', 'none'); + this._d3Holder.append('circle') + .attr('class', 'gap-circle') + .attr('stroke', serie.color) + .attr('stroke-width', '2px') + .attr('r', 4) + .attr('cx', linePosition) + .attr('cy', 5) + .attr('pointer-events', 'none') // TODO: make all on implementation of Events + .style('cursor', 'pointer') + }); + + } +} \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index ca82f37..67db165 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,6 @@ import { ChartwerkPod, VueChartwerkPodMixin, TimeFormat, CrosshairOrientation, BrushOrientation, yAxisOrientation } from '@chartwerk/core'; import { LineTimeSerie, LineOptions } from './types'; +import { Markers } from './components/markers'; import { LineSeries } from './models/line_series'; @@ -17,12 +18,17 @@ export class LinePod extends ChartwerkPod { lineGeneratorY1 = null; areaGeneratorY1 = null; - constructor(_el: HTMLElement, _series: LineTimeSerie[] = [], _options: LineOptions = {}) { + private _markersLayer: Markers = null; + + constructor( + _el: HTMLElement, _series: LineTimeSerie[] = [], _options: LineOptions = {}, + private _markerSeries = [] + ) { super(_el, _series, _options); this.series = new LineSeries(_series); } - renderMetrics(): void { + override renderMetrics(): void { this.clearAllMetrics(); this.updateCrosshair(); @@ -36,6 +42,8 @@ export class LinePod extends ChartwerkPod { for(const serie of this.series.visibleSeries) { this._renderMetric(serie); } + this._markersLayer = new Markers(this._markerSeries, this.state); + this._markersLayer.render(this.metricContainer); } clearAllMetrics(): void { @@ -386,6 +394,7 @@ export class LinePod extends ChartwerkPod { } } +// TODO: it should be moved to VUE folder // it is used with Vue.component, e.g.: Vue.component('chartwerk-line-pod', VueChartwerkLinePod) export const VueChartwerkLinePod = { // alternative to `template: '
'` diff --git a/src/models/line_series.ts b/src/models/line_series.ts index dd9039e..d75cf07 100644 --- a/src/models/line_series.ts +++ b/src/models/line_series.ts @@ -15,7 +15,6 @@ const LINE_SERIE_DEFAULTS = { }; export class LineSeries extends CoreSeries { - constructor(series: LineTimeSerie[]) { super(series, _.clone(LINE_SERIE_DEFAULTS)); } diff --git a/src/models/marker.ts b/src/models/marker.ts new file mode 100644 index 0000000..7253729 --- /dev/null +++ b/src/models/marker.ts @@ -0,0 +1,4 @@ +export type MarkerSerie = { + color: string; + data: [number, number, any][] // [x, y, payload] payload is any data for tooltip +}