basic segments impl #27

Merged
rozetko merged 2 commits from segments-feature-#19 into main 12 months ago
  1. 38
      examples/segments.html
  2. 6
      src/components/markers.ts
  3. 45
      src/components/segments.ts
  4. 7
      src/index.ts
  5. 4
      src/models/segment.ts

38
examples/segments.html

@ -0,0 +1,38 @@
<!DOCTYPE html>
<html>
<head>
<meta content="text/html;charset=utf-8" http-equiv="Content-Type">
<meta content="utf-8" http-equiv="encoding">
<script src="../dist/index.dev.js" type="text/javascript"></script>
</head>
<body>
<div id="chart" style="width: 100%; height: 500px;"></div>
<script type="text/javascript">
const startTime = 1701790172908;
const timeSerieData = [5, 6, 3, 7, 5, 6, 8, 4, 5, 6, 4, 3, 5, 7, 8]
.map((el, idx) => [startTime + idx * 1000, el]);
const segmentsData = [3, 6, 9].map(el => [startTime + el * 1000, startTime + (el + 1) * 1000]);
let options = {
renderLegend: false,
axis: {
y: { range: [0, 10] },
x: { format: 'time' }
},
}
var pod = new LinePod(
document.getElementById('chart'),
[
{ datapoints: timeSerieData, color: 'black' },
],
options,
[],
[
{ data: segmentsData, color:'#FFE545' }
]
);
pod.render();
</script>
</body>
</html>

6
src/components/markers.ts

@ -5,7 +5,7 @@ import { LineTimeSerie, LineOptions } from "../types";
import d3 from "d3"; import d3 from "d3";
export class Markers { export class Markers {
// TODO: more sentic name // TODO: more semantic name
private _d3Holder = null; private _d3Holder = null;
constructor(private _markers: MarkerSerie[], private _state: PodState<LineTimeSerie, LineOptions>) { constructor(private _markers: MarkerSerie[], private _state: PodState<LineTimeSerie, LineOptions>) {
@ -17,11 +17,11 @@ export class Markers {
} }
this._d3Holder = metricContainer.append('g').attr('class', 'markers-layer'); this._d3Holder = metricContainer.append('g').attr('class', 'markers-layer');
for (const ms of this._markers) { for (const ms of this._markers) {
this.renderMarkerSerie(ms); this.renderSerie(ms);
} }
} }
protected renderMarkerSerie(serie: MarkerSerie) { protected renderSerie(serie: MarkerSerie) {
serie.data.forEach((d) => { serie.data.forEach((d) => {
let linePosition = this._state.xScale(d) as number; let linePosition = this._state.xScale(d) as number;
this._d3Holder.append('line') this._d3Holder.append('line')

45
src/components/segments.ts

@ -0,0 +1,45 @@
import { SegmentSerie } from "../models/segment";
import { PodState } from "@chartwerk/core";
import { LineTimeSerie, LineOptions } from "../types";
import d3 from "d3";
export class Segments {
// TODO: more semantic name
private _d3Holder = null;
constructor(private _series: SegmentSerie[], private _state: PodState<LineTimeSerie, LineOptions>) {
}
render(metricContainer: d3.Selection<SVGGElement, unknown, null, undefined>) {
if(this._d3Holder !== null) {
this._d3Holder.remove();
}
this._d3Holder = metricContainer.append('g').attr('class', 'markers-layer');
for (const s of this._series) {
this.renderSerie(s);
}
}
protected renderSerie(serie: SegmentSerie) {
serie.data.forEach((d) => {
// @ts-ignore
const startPositionX = pod.state.xScale(d[0]) as number;
// @ts-ignore
const endPositionX = pod.state.xScale(d[1]) as number;
const width = endPositionX - startPositionX // Math.max(endPositionX - startPositionX, MIMIMUM_SEGMENT_WIDTH);
this._d3Holder.append('rect')
.attr('class', 'segment')
.attr('x', startPositionX)
.attr('y', 0)
.attr('width', width)
// @ts-ignore // TODO: remove ignore but boxParams are protected
.attr('height', this._state.boxParams.height)
.attr('opacity', 0.3)
.style('fill', serie.color)
.style('pointer-events', 'none');
});
}
}

7
src/index.ts

@ -1,6 +1,7 @@
import { ChartwerkPod, VueChartwerkPodMixin, TimeFormat, CrosshairOrientation, BrushOrientation, yAxisOrientation } from '@chartwerk/core'; import { ChartwerkPod, VueChartwerkPodMixin, TimeFormat, CrosshairOrientation, BrushOrientation, yAxisOrientation } from '@chartwerk/core';
import { LineTimeSerie, LineOptions } from './types'; import { LineTimeSerie, LineOptions } from './types';
import { Markers } from './components/markers'; import { Markers } from './components/markers';
import { Segments } from './components/segments';
import { LineSeries } from './models/line_series'; import { LineSeries } from './models/line_series';
@ -19,10 +20,12 @@ export class LinePod extends ChartwerkPod<LineTimeSerie, LineOptions> {
areaGeneratorY1 = null; areaGeneratorY1 = null;
private _markersLayer: Markers = null; private _markersLayer: Markers = null;
private _segmentsLayer: Segments = null;
constructor( constructor(
_el: HTMLElement, _series: LineTimeSerie[] = [], _options: LineOptions = {}, _el: HTMLElement, _series: LineTimeSerie[] = [], _options: LineOptions = {},
private _markerSeries = [] private _markerSeries = [],
private _segmentSeries = [],
) { ) {
super(_el, _series, _options); super(_el, _series, _options);
this.series = new LineSeries(_series); this.series = new LineSeries(_series);
@ -44,6 +47,8 @@ export class LinePod extends ChartwerkPod<LineTimeSerie, LineOptions> {
} }
this._markersLayer = new Markers(this._markerSeries, this.state); this._markersLayer = new Markers(this._markerSeries, this.state);
this._markersLayer.render(this.metricContainer); this._markersLayer.render(this.metricContainer);
this._segmentsLayer = new Segments(this._segmentSeries, this.state);
this._segmentsLayer.render(this.metricContainer);
} }
clearAllMetrics(): void { clearAllMetrics(): void {

4
src/models/segment.ts

@ -0,0 +1,4 @@
export type SegmentSerie = {
color: string;
data: [number, number, any][] // [from, to, payload] payload is any data for tooltip
}
Loading…
Cancel
Save