From e7248806b0751829db807e46713d4ab2d225a208 Mon Sep 17 00:00:00 2001 From: vargburz Date: Tue, 24 May 2022 15:16:39 +0300 Subject: [PATCH 1/7] models --- package.json | 3 +- src/index.ts | 242 +++++++++++++------------------------- src/models/line-series.ts | 26 ++++ src/types.ts | 4 +- yarn.lock | 6 +- 5 files changed, 118 insertions(+), 163 deletions(-) create mode 100644 src/models/line-series.ts diff --git a/package.json b/package.json index 4f5d0e5..30e7724 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,8 @@ "scripts": { "build": "webpack --config build/webpack.prod.conf.js && webpack --config build/webpack.dev.conf.js", "dev": "webpack --watch --config build/webpack.dev.conf.js", - "test": "echo \"Error: no test specified\" && exit 1" + "test": "echo \"Error: no test specified\" && exit 1", + "update-core": "yarn up @chartwerk/core && yarn up @chartwerk/core@latest" }, "repository": { "type": "git", diff --git a/src/index.ts b/src/index.ts index 97917cf..80688df 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,8 @@ -import { ChartwerkPod, VueChartwerkPodMixin, TickOrientation, TimeFormat, CrosshairOrientation, BrushOrientation } from '@chartwerk/core'; +import { ChartwerkPod, VueChartwerkPodMixin, TimeFormat, CrosshairOrientation, BrushOrientation } from '@chartwerk/core'; import { LineTimeSerie, LineOptions, Mode } from './types'; +import { LineSeries } from './models/line-series'; + import * as d3 from 'd3'; import * as _ from 'lodash'; @@ -15,6 +17,7 @@ export class LinePod extends ChartwerkPod { constructor(_el: HTMLElement, _series: LineTimeSerie[] = [], _options: LineOptions = {}) { super(_el, _series, _options); + this.coreSeries = new LineSeries(_series); } renderMetrics(): void { @@ -24,35 +27,13 @@ export class LinePod extends ChartwerkPod { this.initLineGenerator(); this.initAreaGenerator(); - // TODO: seems that renderMetrics is not correct name - if(this.series.length === 0) { + if(!this.coreSeries.isSeriesAvailable) { this.renderNoDataPointsMessage(); return; } - for(let idx = 0; idx < this.series.length; ++idx) { - if(this.series[idx].visible === false) { - continue; - } - // TODO: use _.defaults same as in core - const confidence = this.series[idx].confidence || 0; - const mode = this.series[idx].mode || Mode.STANDARD; - const target = this.series[idx].target; - const renderDots = this.series[idx].renderDots !== undefined ? this.series[idx].renderDots : false; - const renderLines = this.series[idx].renderLines !== undefined ? this.series[idx].renderLines : true; - - this._renderMetric( - this.series[idx].datapoints, - { - color: this.getSerieColor(idx), - confidence, - target, - mode, - serieIdx: idx, - renderDots, - renderLines, - } - ); + for(const serie of this.coreSeries.visibleSeries) { + this._renderMetric(serie); } } @@ -63,19 +44,18 @@ export class LinePod extends ChartwerkPod { initLineGenerator(): void { this.lineGenerator = d3.line() - .x(d => this.xScale(d[0])) - .y(d => this.yScale(d[1])); + .x(d => this.state.xScale(d[0])) + .y(d => this.state.yScale(d[1])); } initAreaGenerator(): void { this.areaGenerator = d3.area() - .x(d => this.xScale(d[0])) - .y1(d => this.yScale(d[1])) + .x(d => this.state.xScale(d[0])) + .y1(d => this.state.yScale(d[1])) .y0(d => this.height); } - getRenderGenerator(serieIdx: number): any { - const renderArea = this.series[serieIdx].renderArea; + getRenderGenerator(renderArea: boolean): any { if(renderArea) { return this.areaGenerator; } @@ -83,29 +63,26 @@ export class LinePod extends ChartwerkPod { } public appendData(data: [number, number][], shouldRerender = true): void { - for(let idx = 0; idx < this.series.length; ++idx) { - if(this.series[idx].visible === false) { - continue; - } - this.series[idx].datapoints.push(data[idx]); - const maxLength = this.series[idx].maxLength; - if(maxLength !== undefined && this.series[idx].datapoints.length > maxLength) { - this.series[idx].datapoints.shift(); + for(const serie of this.coreSeries.visibleSeries) { + serie.datapoints.push(data[serie.idx]); + const maxLength = serie.maxLength; + if(maxLength !== undefined && serie.datapoints.length > maxLength) { + serie.datapoints.shift(); } } - for(let idx = 0; idx < this.series.length; ++idx) { - this.metricContainer.select(`.metric-path-${idx}`) - .datum(this.series[idx].datapoints) - .attr('d', this.getRenderGenerator(idx)); + for(const serie of this.coreSeries.visibleSeries) { + this.metricContainer.select(`.metric-path-${serie.idx}`) + .datum(serie.datapoints) + .attr('d', this.getRenderGenerator(serie.renderArea)); - if(this.series[idx].renderDots === true) { - this.metricContainer.selectAll(`.metric-circle-${idx}`) - .data(this.series[idx].datapoints) - .attr('cx', d => this.xScale(d[0])) - .attr('cy', d => this.yScale(d[1])); + if(serie.renderDots === true) { + this.metricContainer.selectAll(`.metric-circle-${serie.idx}`) + .data(serie.datapoints) + .attr('cx', d => this.state.xScale(d[0])) + .attr('cy', d => this.state.yScale(d[1])); - this._renderDots([data[idx]], idx); + this._renderDots(serie); } } if(shouldRerender) { @@ -117,67 +94,48 @@ export class LinePod extends ChartwerkPod { } } - _renderDots(datapoints: number[][], serieIdx: number): void { - const customClass = this.series[serieIdx].class || ''; - + _renderDots(serie: LineTimeSerie): void { this.metricContainer.selectAll(null) - .data(datapoints) + .data(serie.datapoints) .enter() .append('circle') - .attr('class', `metric-circle-${serieIdx} metric-el ${customClass}`) - .attr('fill', this.getSerieColor(serieIdx)) + .attr('class', `metric-circle-${serie.idx} metric-el ${serie.class}`) + .attr('fill', serie.color) .attr('r', METRIC_CIRCLE_RADIUS) .style('pointer-events', 'none') - .attr('cx', d => this.xScale(d[0])) - .attr('cy', d => this.yScale(d[1])); + .attr('cx', d => this.state.xScale(d[0])) + .attr('cy', d => this.state.yScale(d[1])); } - _renderLines(datapoints: number[][], serieIdx: number): void { - const dashArray = this.series[serieIdx].dashArray !== undefined ? this.series[serieIdx].dashArray : '0'; - const customClass = this.series[serieIdx].class || ''; - const fillColor = this.series[serieIdx].renderArea ? this.getSerieColor(serieIdx) : 'none'; - const fillOpacity = this.series[serieIdx].renderArea ? 0.5 : 'none'; + _renderLines(serie: LineTimeSerie): void { + const fillColor = serie.renderArea ? serie.color : 'none'; + const fillOpacity = serie.renderArea ? 0.5 : 'none'; this.metricContainer .append('path') - .datum(datapoints) - .attr('class', `metric-path-${serieIdx} metric-el ${customClass}`) + .datum(serie.datapoints) + .attr('class', `metric-path-${serie.idx} metric-el ${serie.class}`) .attr('fill', fillColor) .attr('fill-opacity', fillOpacity) - .attr('stroke', this.getSerieColor(serieIdx)) + .attr('stroke', serie.color) .attr('stroke-width', 1) .attr('stroke-opacity', 0.7) .attr('pointer-events', 'none') - .style('stroke-dasharray', dashArray) - .attr('d', this.getRenderGenerator(serieIdx)); + .style('stroke-dasharray', serie.dashArray) + .attr('d', this.getRenderGenerator(serie.renderArea)); } - _renderMetric( - datapoints: number[][], - metricOptions: { - color: string, - confidence: number, - target: string, - mode: Mode, - serieIdx: number, - renderDots: boolean, - renderLines: boolean, - } - ): void { - if(_.includes(this.seriesTargetsWithBounds, metricOptions.target)) { - return; - } - - if(metricOptions.mode === Mode.CHARGE) { - const dataPairs = d3.pairs(datapoints); + _renderMetric(serie: LineTimeSerie): void { + if(serie.mode === Mode.CHARGE) { + const dataPairs = d3.pairs(serie.datapoints); this.metricContainer.selectAll(null) .data(dataPairs) .enter() .append('line') - .attr('x1', d => this.xScale(d[0][0])) - .attr('x2', d => this.xScale(d[1][0])) - .attr('y1', d => this.yScale(d[0][1])) - .attr('y2', d => this.yScale(d[1][1])) + .attr('x1', d => this.state.xScale(d[0][0])) + .attr('x2', d => this.state.xScale(d[1][0])) + .attr('y1', d => this.state.yScale(d[0][1])) + .attr('y2', d => this.state.yScale(d[1][1])) .attr('stroke-opacity', 0.7) .style('stroke-width', 1) .style('stroke', d => { @@ -192,12 +150,12 @@ export class LinePod extends ChartwerkPod { return; } - if(metricOptions.renderLines === true) { - this._renderLines(datapoints, metricOptions.serieIdx); + if(serie.renderLines === true) { + this._renderLines(serie); } - if(metricOptions.renderDots === true) { - this._renderDots(datapoints, metricOptions.serieIdx); + if(serie.renderDots === true) { + this._renderDots(serie); } } @@ -209,7 +167,7 @@ export class LinePod extends ChartwerkPod { appendCrosshairCircles(): void { // circle for each serie - this.series.forEach((serie: LineTimeSerie, serieIdx: number) => { + this.coreSeries.visibleSeries.forEach((serie: LineTimeSerie, serieIdx: number) => { this.appendCrosshairCircle(serieIdx); }); } @@ -222,7 +180,7 @@ export class LinePod extends ChartwerkPod { .attr('cx', -CROSSHAIR_BACKGROUND_RAIDUS) .attr('cy', -CROSSHAIR_BACKGROUND_RAIDUS) .attr('clip-path', `url(#${this.rectClipId})`) - .attr('fill', this.getSerieColor(serieIdx)) + .attr('fill', this.coreSeries.visibleSeries[serieIdx].color) .style('opacity', CROSSHAIR_BACKGROUND_OPACITY) .style('pointer-events', 'none'); @@ -232,23 +190,19 @@ export class LinePod extends ChartwerkPod { .attr('cy', -CROSSHAIR_CIRCLE_RADIUS) .attr('class', `crosshair-circle-${serieIdx}`) .attr('clip-path', `url(#${this.rectClipId})`) - .attr('fill', this.getSerieColor(serieIdx)) + .attr('fill', this.coreSeries.visibleSeries[serieIdx].color) .attr('r', CROSSHAIR_CIRCLE_RADIUS) .style('pointer-events', 'none'); } public renderSharedCrosshair(values: { x?: number, y?: number }): void { this.onMouseOver(); // TODO: refactor to use it once - const eventX = this.xScale(values.x); - const eventY = this.yScale(values.y); + const eventX = this.state.xScale(values.x); + const eventY = this.state.yScale(values.y); this.moveCrosshairLine(eventX, eventY); const datapoints = this.findAndHighlightDatapoints(values.x, values.y); - if(this.options.eventsCallbacks === undefined || this.options.eventsCallbacks.sharedCrosshairMove === undefined) { - return; - } - - this.options.eventsCallbacks.sharedCrosshairMove({ + this.coreOptions.callbackSharedCrosshairMove({ datapoints: datapoints, eventX, eventY }); @@ -259,7 +213,7 @@ export class LinePod extends ChartwerkPod { } moveCrosshairLine(xPosition: number, yPosition: number): void { - switch(this.options.crosshair.orientation) { + switch(this.coreOptions.crosshair.orientation) { case CrosshairOrientation.VERTICAL: this.crosshair.select('#crosshair-line-x') .attr('x1', xPosition) @@ -279,7 +233,7 @@ export class LinePod extends ChartwerkPod { .attr('y2', yPosition); return; default: - throw new Error(`Unknown type of crosshair orientaion: ${this.options.crosshair.orientation}`); + throw new Error(`Unknown type of crosshair orientaion: ${this.coreOptions.crosshair.orientation}`); } } @@ -307,7 +261,7 @@ export class LinePod extends ChartwerkPod { getClosestIndex(datapoints: [number, number][], xValue: number, yValue: number): number { let columnIdx; // 0 for x value, 1 for y value, let value; // xValue to y Value - switch(this.options.crosshair.orientation) { + switch(this.coreOptions.crosshair.orientation) { case CrosshairOrientation.VERTICAL: columnIdx = 0; value = xValue; @@ -321,7 +275,7 @@ export class LinePod extends ChartwerkPod { columnIdx = 1; value = yValue; default: - throw new Error(`Unknown type of crosshair orientaion: ${this.options.crosshair.orientation}`); + throw new Error(`Unknown type of crosshair orientaion: ${this.coreOptions.crosshair.orientation}`); } // TODO: d3.bisect is not the best way. Use binary search @@ -350,7 +304,7 @@ export class LinePod extends ChartwerkPod { // columnIdx: 1 for y, 0 for x // inverval: x/y value interval between data points // TODO: move it to base/state instead of timeInterval - const intervals = _.map(this.series, serie => { + const intervals = _.map(this.coreSeries.visibleSeries, serie => { if(serie.datapoints.length < 2) { return undefined; } @@ -366,23 +320,15 @@ export class LinePod extends ChartwerkPod { onMouseMove(): void { const eventX = d3.mouse(this.chartContainer.node())[0]; const eventY = d3.mouse(this.chartContainer.node())[1]; - const xValue = this.xScale.invert(eventX); // mouse x position in xScale - const yValue = this.yScale.invert(eventY); - // TODO: isOutOfChart is a hack, use clip path correctly - if(this.isOutOfChart() === true) { - this.crosshair.style('display', 'none'); - return; - } + const xValue = this.state.xScale.invert(eventX); // mouse x position in xScale + const yValue = this.state.yScale.invert(eventY); this.moveCrosshairLine(eventX, eventY); const datapoints = this.findAndHighlightDatapoints(xValue, yValue); - if(this.options.eventsCallbacks === undefined || this.options.eventsCallbacks.mouseMove === undefined) { - return; - } // TDOO: is shift key pressed // TODO: need to refactor this object - this.options.eventsCallbacks.mouseMove({ + this.coreOptions.callbackMouseMove({ x: d3.event.pageX, y: d3.event.pageY, xVal: xValue, @@ -394,31 +340,24 @@ export class LinePod extends ChartwerkPod { } findAndHighlightDatapoints(xValue: number, yValue: number): { value: [number, number], color: string, label: string }[] { - if(this.series === undefined || this.series.length === 0) { + if(!this.coreSeries.isSeriesAvailable) { return []; } let points = []; // datapoints in each metric that is closest to xValue/yValue position - this.series.forEach((serie: LineTimeSerie, serieIdx: number) => { - if( - serie.visible === false || - _.includes(this.seriesTargetsWithBounds, serie.target) - ) { - this.hideCrosshairCircle(serieIdx); - return; - } + this.coreSeries.visibleSeries.forEach((serie: LineTimeSerie) => { const closestDatapoint = this.getClosestDatapoint(serie, xValue, yValue); if(closestDatapoint === undefined || this.isOutOfRange(closestDatapoint, xValue, yValue, serie.useOutOfRange)) { - this.hideCrosshairCircle(serieIdx); + this.hideCrosshairCircle(serie.idx); return; } - const xPosition = this.xScale(closestDatapoint[0]); - const yPosition = this.yScale(closestDatapoint[1]); - this.moveCrosshairCircle(xPosition, yPosition, serieIdx); + const xPosition = this.state.xScale(closestDatapoint[0]); + const yPosition = this.state.yScale(closestDatapoint[1]); + this.moveCrosshairCircle(xPosition, yPosition, serie.idx); points.push({ value: closestDatapoint, - color: this.getSerieColor(serieIdx), + color: serie.color, label: serie.alias || serie.target }); }); @@ -433,7 +372,7 @@ export class LinePod extends ChartwerkPod { } let columnIdx; // 1 for y value, 0 for x value let value; // xValue ot y Value - switch(this.options.crosshair.orientation) { + switch(this.coreOptions.crosshair.orientation) { case CrosshairOrientation.VERTICAL: columnIdx = 0; value = xValue; @@ -447,7 +386,7 @@ export class LinePod extends ChartwerkPod { columnIdx = 1; value = yValue; default: - throw new Error(`Unknown type of crosshair orientaion: ${this.options.crosshair.orientation}`); + throw new Error(`Unknown type of crosshair orientaion: ${this.coreOptions.crosshair.orientation}`); } const range = Math.abs(closestDatapoint[columnIdx] - value); const interval = this.getValueInterval(columnIdx); // interval between points @@ -462,30 +401,21 @@ export class LinePod extends ChartwerkPod { } onMouseOut(): void { - if(this.options.eventsCallbacks !== undefined && this.options.eventsCallbacks.mouseOut !== undefined) { - this.options.eventsCallbacks.mouseOut(); - } + this.coreOptions.callbackMouseOut(); this.crosshair.style('display', 'none'); } isDoubleClickActive(): boolean { - if(this.options.zoomEvents.mouse.doubleClick === undefined) { - return false; - } - return this.options.zoomEvents.mouse.doubleClick.isActive; + return this.coreOptions.doubleClickEvent.isActive; } // methods below rewrite cores, (move more methods here) protected zoomOut(): void { - // TODO: test to remove, seems its depricated - if(this.isOutOfChart() === true) { - return; - } if(d3.event.type === 'dblclick' && !this.isDoubleClickActive()) { return; } // TODO: its not clear, why we use this orientation here. Mb its better to use separate option - const orientation: BrushOrientation = this.options.zoomEvents.mouse.zoom.orientation; + const orientation: BrushOrientation = this.coreOptions.mouseZoomEvent.orientation; const xInterval = this.state.xValueRange[1] - this.state.xValueRange[0]; const yInterval = this.state.yValueRange[1] - this.state.yValueRange[0]; switch(orientation) { @@ -514,15 +444,13 @@ export class LinePod extends ChartwerkPod { this.renderGrid(); this.onMouseOver(); - if(this.options.eventsCallbacks !== undefined && this.options.eventsCallbacks.zoomOut !== undefined) { - let xAxisMiddleValue: number = this.xScale.invert(this.width / 2); - let yAxisMiddleValue: number = this.yScale.invert(this.height / 2); - const centers = { - x: xAxisMiddleValue, - y: yAxisMiddleValue - } - this.options.eventsCallbacks.zoomOut(centers); + let xAxisMiddleValue: number = this.state.xScale.invert(this.width / 2); + let yAxisMiddleValue: number = this.state.yScale.invert(this.height / 2); + const centers = { + x: xAxisMiddleValue, + y: yAxisMiddleValue } + this.coreOptions.callbackZoomOut(centers); } } @@ -557,4 +485,4 @@ export const VueChartwerkLinePod = { } }; -export { LineTimeSerie, LineOptions, Mode, TickOrientation, TimeFormat }; +export { LineTimeSerie, LineOptions, Mode, TimeFormat }; diff --git a/src/models/line-series.ts b/src/models/line-series.ts new file mode 100644 index 0000000..278498e --- /dev/null +++ b/src/models/line-series.ts @@ -0,0 +1,26 @@ +import { CoreSeries } from '@chartwerk/core'; +import { LineTimeSerie, Mode } from 'types'; + + +const LINE_SERIE_DEFAULTS = { + mode: Mode.STANDARD, + maxLength: undefined, + renderDots: false, + renderLines: true, + useOutOfRange: true, //? + dashArray: '0', + class: '', + renderArea: false, +}; + +export class LineSeries extends CoreSeries { + _lineDefaults = LINE_SERIE_DEFAULTS; + + constructor(series: LineTimeSerie[]) { + super(series); + } + + protected get defaults(): LineTimeSerie { + return { ...this._coreDefaults, ...this._lineDefaults }; + } +} diff --git a/src/types.ts b/src/types.ts index 1575cfe..44e44fe 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,4 +1,4 @@ -import { TimeSerie, Options } from '@chartwerk/core'; +import { Serie, Options } from '@chartwerk/core'; type LineTimeSerieParams = { confidence: number, @@ -15,5 +15,5 @@ export enum Mode { STANDARD = 'Standard', CHARGE = 'Charge' } -export type LineTimeSerie = TimeSerie & Partial; +export type LineTimeSerie = Serie & Partial; export type LineOptions = Options; diff --git a/yarn.lock b/yarn.lock index 167871d..edf1642 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6,12 +6,12 @@ __metadata: cacheKey: 8 "@chartwerk/core@npm:latest": - version: 0.5.4 - resolution: "@chartwerk/core@npm:0.5.4" + version: 0.5.8 + resolution: "@chartwerk/core@npm:0.5.8" dependencies: d3: ^5.7.2 lodash: ^4.14.149 - checksum: 0d686409377d6880f0012db3d9c1e1910cf3660885ac13196dabe93f57eca53984cf52dcf781b2876373fe9efc7b9d0209117cbcd811c50892b1de4f38a4a37f + checksum: 24b403af2703cc99ef3dee4793318ed71f4b02ed50bee6940774ccb392b8fbb53bb5353e91903b2c1ec815a8d2b830f2a2a2925d8e4380c64895ee2002b2baed languageName: node linkType: hard From f593206a985370c83db9612edc0abd0d7165accb Mon Sep 17 00:00:00 2001 From: vargburz Date: Tue, 24 May 2022 15:17:20 +0300 Subject: [PATCH 2/7] fix type --- src/models/line-series.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/models/line-series.ts b/src/models/line-series.ts index 278498e..4b4f8f2 100644 --- a/src/models/line-series.ts +++ b/src/models/line-series.ts @@ -1,5 +1,5 @@ import { CoreSeries } from '@chartwerk/core'; -import { LineTimeSerie, Mode } from 'types'; +import { LineTimeSerie, Mode } from '../types'; const LINE_SERIE_DEFAULTS = { From 463bce47c687b607a9c1d6e78ddf2f59c9e3909d Mon Sep 17 00:00:00 2001 From: vargburz Date: Tue, 24 May 2022 15:47:16 +0300 Subject: [PATCH 3/7] fix defaults --- src/index.ts | 3 +++ src/models/line-series.ts | 3 +-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/index.ts b/src/index.ts index 80688df..e03acf7 100644 --- a/src/index.ts +++ b/src/index.ts @@ -17,7 +17,9 @@ export class LinePod extends ChartwerkPod { constructor(_el: HTMLElement, _series: LineTimeSerie[] = [], _options: LineOptions = {}) { super(_el, _series, _options); + console.log('coreSeries', this.coreSeries); this.coreSeries = new LineSeries(_series); + console.log('lineseries', this.coreSeries); } renderMetrics(): void { @@ -32,6 +34,7 @@ export class LinePod extends ChartwerkPod { return; } + console.log('series', this.coreSeries.visibleSeries) for(const serie of this.coreSeries.visibleSeries) { this._renderMetric(serie); } diff --git a/src/models/line-series.ts b/src/models/line-series.ts index 4b4f8f2..b14a3a0 100644 --- a/src/models/line-series.ts +++ b/src/models/line-series.ts @@ -14,13 +14,12 @@ const LINE_SERIE_DEFAULTS = { }; export class LineSeries extends CoreSeries { - _lineDefaults = LINE_SERIE_DEFAULTS; constructor(series: LineTimeSerie[]) { super(series); } protected get defaults(): LineTimeSerie { - return { ...this._coreDefaults, ...this._lineDefaults }; + return { ...this._coreDefaults, ...LINE_SERIE_DEFAULTS }; } } From f9d505fd9289dd19e83006be0ad2c86ff5e3744c Mon Sep 17 00:00:00 2001 From: vargburz Date: Tue, 24 May 2022 15:55:18 +0300 Subject: [PATCH 4/7] remove strange options --- src/index.ts | 63 ++------------------------------------- src/models/line-series.ts | 4 +-- src/types.ts | 8 +---- 3 files changed, 5 insertions(+), 70 deletions(-) diff --git a/src/index.ts b/src/index.ts index e03acf7..5a8797f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,5 @@ import { ChartwerkPod, VueChartwerkPodMixin, TimeFormat, CrosshairOrientation, BrushOrientation } from '@chartwerk/core'; -import { LineTimeSerie, LineOptions, Mode } from './types'; +import { LineTimeSerie, LineOptions } from './types'; import { LineSeries } from './models/line-series'; @@ -17,9 +17,7 @@ export class LinePod extends ChartwerkPod { constructor(_el: HTMLElement, _series: LineTimeSerie[] = [], _options: LineOptions = {}) { super(_el, _series, _options); - console.log('coreSeries', this.coreSeries); this.coreSeries = new LineSeries(_series); - console.log('lineseries', this.coreSeries); } renderMetrics(): void { @@ -34,7 +32,6 @@ export class LinePod extends ChartwerkPod { return; } - console.log('series', this.coreSeries.visibleSeries) for(const serie of this.coreSeries.visibleSeries) { this._renderMetric(serie); } @@ -129,30 +126,6 @@ export class LinePod extends ChartwerkPod { } _renderMetric(serie: LineTimeSerie): void { - if(serie.mode === Mode.CHARGE) { - const dataPairs = d3.pairs(serie.datapoints); - this.metricContainer.selectAll(null) - .data(dataPairs) - .enter() - .append('line') - .attr('x1', d => this.state.xScale(d[0][0])) - .attr('x2', d => this.state.xScale(d[1][0])) - .attr('y1', d => this.state.yScale(d[0][1])) - .attr('y2', d => this.state.yScale(d[1][1])) - .attr('stroke-opacity', 0.7) - .style('stroke-width', 1) - .style('stroke', d => { - if(d[1][0] > d[0][0]) { - return 'green'; - } else if (d[1][0] < d[0][0]) { - return 'red'; - } else { - return 'gray'; - } - }); - return; - } - if(serie.renderLines === true) { this._renderLines(serie); } @@ -349,7 +322,7 @@ export class LinePod extends ChartwerkPod { let points = []; // datapoints in each metric that is closest to xValue/yValue position this.coreSeries.visibleSeries.forEach((serie: LineTimeSerie) => { const closestDatapoint = this.getClosestDatapoint(serie, xValue, yValue); - if(closestDatapoint === undefined || this.isOutOfRange(closestDatapoint, xValue, yValue, serie.useOutOfRange)) { + if(closestDatapoint === undefined) { this.hideCrosshairCircle(serie.idx); return; } @@ -367,36 +340,6 @@ export class LinePod extends ChartwerkPod { return points; } - isOutOfRange(closestDatapoint: [number, number], xValue: number, yValue: number, useOutOfRange = true): boolean { - // find is mouse position more than xRange/yRange from closest point - // TODO: refactor getValueInterval to remove this! - if(useOutOfRange === false) { - return false; - } - let columnIdx; // 1 for y value, 0 for x value - let value; // xValue ot y Value - switch(this.coreOptions.crosshair.orientation) { - case CrosshairOrientation.VERTICAL: - columnIdx = 0; - value = xValue; - break; - case CrosshairOrientation.HORIZONTAL: - columnIdx = 1; - value = yValue; - break; - case CrosshairOrientation.BOTH: - // TODO: maybe use voronoi - columnIdx = 1; - value = yValue; - default: - throw new Error(`Unknown type of crosshair orientaion: ${this.coreOptions.crosshair.orientation}`); - } - const range = Math.abs(closestDatapoint[columnIdx] - value); - const interval = this.getValueInterval(columnIdx); // interval between points - // do not move crosshair circles, it mouse to far from closest point - return interval === undefined || range > interval / 2; - } - onMouseOver(): void { this.crosshair.style('display', null); this.crosshair.selectAll('.crosshair-circle') @@ -488,4 +431,4 @@ export const VueChartwerkLinePod = { } }; -export { LineTimeSerie, LineOptions, Mode, TimeFormat }; +export { LineTimeSerie, LineOptions, TimeFormat }; diff --git a/src/models/line-series.ts b/src/models/line-series.ts index b14a3a0..0b779dd 100644 --- a/src/models/line-series.ts +++ b/src/models/line-series.ts @@ -1,13 +1,11 @@ import { CoreSeries } from '@chartwerk/core'; -import { LineTimeSerie, Mode } from '../types'; +import { LineTimeSerie } from '../types'; const LINE_SERIE_DEFAULTS = { - mode: Mode.STANDARD, maxLength: undefined, renderDots: false, renderLines: true, - useOutOfRange: true, //? dashArray: '0', class: '', renderArea: false, diff --git a/src/types.ts b/src/types.ts index 44e44fe..5924894 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,19 +1,13 @@ import { Serie, Options } from '@chartwerk/core'; type LineTimeSerieParams = { - confidence: number, - mode: Mode, maxLength: number, renderDots: boolean, renderLines: boolean, // TODO: refactor same as scatter-pod - useOutOfRange: boolean, // It's temporary hack. Need to refactor getValueInterval() method dashArray: string; // dasharray attr, only for lines class: string; // option to add custom class to each serie element renderArea: boolean; // TODO: move to render type } -export enum Mode { - STANDARD = 'Standard', - CHARGE = 'Charge' -} + export type LineTimeSerie = Serie & Partial; export type LineOptions = Options; From ca3dc0b8f165906431eecf39fe99b5188660729c Mon Sep 17 00:00:00 2001 From: vargburz Date: Tue, 24 May 2022 15:56:01 +0300 Subject: [PATCH 5/7] remame --- src/index.ts | 2 +- src/models/{line-series.ts => line_series.ts} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename src/models/{line-series.ts => line_series.ts} (100%) diff --git a/src/index.ts b/src/index.ts index 5a8797f..1651166 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,7 +1,7 @@ import { ChartwerkPod, VueChartwerkPodMixin, TimeFormat, CrosshairOrientation, BrushOrientation } from '@chartwerk/core'; import { LineTimeSerie, LineOptions } from './types'; -import { LineSeries } from './models/line-series'; +import { LineSeries } from './models/line_series'; import * as d3 from 'd3'; import * as _ from 'lodash'; diff --git a/src/models/line-series.ts b/src/models/line_series.ts similarity index 100% rename from src/models/line-series.ts rename to src/models/line_series.ts From 70966b323f85bc61c955910428711dc7190c657f Mon Sep 17 00:00:00 2001 From: vargburz Date: Tue, 24 May 2022 16:14:47 +0300 Subject: [PATCH 6/7] fix live demo --- examples/demo_live.html | 16 ++++++++++++---- src/index.ts | 32 -------------------------------- 2 files changed, 12 insertions(+), 36 deletions(-) diff --git a/examples/demo_live.html b/examples/demo_live.html index a8f80dd..072a77c 100755 --- a/examples/demo_live.html +++ b/examples/demo_live.html @@ -15,9 +15,9 @@ const startTime = 1590590148; const arrayLength = 100; this.isZoomed = false; // TODO: temporary hack to have zoomin|zoomout with `appendData`. It will be moved to Pod. - const data1 = Array.from({ length: arrayLength }, (el, idx) => [startTime + idx * 10000, Math.floor(Math.random() * 40)]); - const data2 = Array.from({ length: arrayLength }, (el, idx) => [startTime + idx * 10000, Math.floor(Math.random() * 100)]); - const data3 = Array.from({ length: arrayLength }, (el, idx) => [startTime + idx * 10000, Math.floor(Math.random() * 20) + 90]); + var data1 = Array.from({ length: arrayLength }, (el, idx) => [startTime + idx * 10000, Math.floor(Math.random() * 40)]); + var data2 = Array.from({ length: arrayLength }, (el, idx) => [startTime + idx * 10000, Math.floor(Math.random() * 100)]); + var data3 = Array.from({ length: arrayLength }, (el, idx) => [startTime + idx * 10000, Math.floor(Math.random() * 20) + 90]); const zoomIn = (ranges) => { const xRange = ranges[0]; options.axis.x.range = xRange; pod.updateData(undefined, options); this.isZoomed = true } const zoomOut = (ranges) => { options.axis.x.range = undefined; pod.updateData(undefined, options); this.isZoomed = false } let options = { renderLegend: false, axis: { y: { invert: false, range: [0, 350] }, x: { format: 'time' } }, eventsCallbacks: { zoomIn: zoomIn, zoomOut } }; @@ -37,9 +37,17 @@ const d1 = [startTime + rerenderIdx * 10000, Math.floor(Math.random() * 20) + 90]; const d2 = [startTime + rerenderIdx * 10000, Math.floor(Math.random() * 100)]; const d3 = [startTime + rerenderIdx * 10000, Math.floor(Math.random() * 20) + 90]; + console.log('d1', data1) const shouldRerender = !this.isZoomed; console.time('rerender'); - pod.appendData([d1, d2, d3], shouldRerender); + data1.push(d1); + data2.push(d2); + data3.push(d3); + pod.updateData([ + { target: 'test1', datapoints: data1, color: 'green', maxLength: arrayLength + 30, renderDots: false }, + { target: 'test2', datapoints: data2, color: 'blue', maxLength: arrayLength + 30, renderDots: false }, + { target: 'test3', datapoints: data3, color: 'orange', maxLength: arrayLength + 30, renderDots: false }, + ]); console.timeEnd('rerender'); if(rerenderIdx > arrayLength + 100) { clearInterval(test); diff --git a/src/index.ts b/src/index.ts index 1651166..b1e8dd2 100644 --- a/src/index.ts +++ b/src/index.ts @@ -62,38 +62,6 @@ export class LinePod extends ChartwerkPod { return this.lineGenerator; } - public appendData(data: [number, number][], shouldRerender = true): void { - for(const serie of this.coreSeries.visibleSeries) { - serie.datapoints.push(data[serie.idx]); - const maxLength = serie.maxLength; - if(maxLength !== undefined && serie.datapoints.length > maxLength) { - serie.datapoints.shift(); - } - } - - for(const serie of this.coreSeries.visibleSeries) { - this.metricContainer.select(`.metric-path-${serie.idx}`) - .datum(serie.datapoints) - .attr('d', this.getRenderGenerator(serie.renderArea)); - - if(serie.renderDots === true) { - this.metricContainer.selectAll(`.metric-circle-${serie.idx}`) - .data(serie.datapoints) - .attr('cx', d => this.state.xScale(d[0])) - .attr('cy', d => this.state.yScale(d[1])); - - this._renderDots(serie); - } - } - if(shouldRerender) { - const rightBorder = _.last(data)[0]; - this.state.xValueRange = [this.state.getMinValueX(), rightBorder]; - this.renderXAxis(); - this.renderYAxis(); - this.renderGrid(); - } - } - _renderDots(serie: LineTimeSerie): void { this.metricContainer.selectAll(null) .data(serie.datapoints) From b65b04c5742847b58d5e8a985ab29daf91ba00cf Mon Sep 17 00:00:00 2001 From: vargburz Date: Tue, 24 May 2022 16:41:07 +0300 Subject: [PATCH 7/7] use core 060 --- src/index.ts | 40 ++++++++++++++++++++-------------------- yarn.lock | 6 +++--- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/index.ts b/src/index.ts index b1e8dd2..70ec9c5 100644 --- a/src/index.ts +++ b/src/index.ts @@ -17,7 +17,7 @@ export class LinePod extends ChartwerkPod { constructor(_el: HTMLElement, _series: LineTimeSerie[] = [], _options: LineOptions = {}) { super(_el, _series, _options); - this.coreSeries = new LineSeries(_series); + this.series = new LineSeries(_series); } renderMetrics(): void { @@ -27,12 +27,12 @@ export class LinePod extends ChartwerkPod { this.initLineGenerator(); this.initAreaGenerator(); - if(!this.coreSeries.isSeriesAvailable) { + if(!this.series.isSeriesAvailable) { this.renderNoDataPointsMessage(); return; } - for(const serie of this.coreSeries.visibleSeries) { + for(const serie of this.series.visibleSeries) { this._renderMetric(serie); } } @@ -111,7 +111,7 @@ export class LinePod extends ChartwerkPod { appendCrosshairCircles(): void { // circle for each serie - this.coreSeries.visibleSeries.forEach((serie: LineTimeSerie, serieIdx: number) => { + this.series.visibleSeries.forEach((serie: LineTimeSerie, serieIdx: number) => { this.appendCrosshairCircle(serieIdx); }); } @@ -124,7 +124,7 @@ export class LinePod extends ChartwerkPod { .attr('cx', -CROSSHAIR_BACKGROUND_RAIDUS) .attr('cy', -CROSSHAIR_BACKGROUND_RAIDUS) .attr('clip-path', `url(#${this.rectClipId})`) - .attr('fill', this.coreSeries.visibleSeries[serieIdx].color) + .attr('fill', this.series.visibleSeries[serieIdx].color) .style('opacity', CROSSHAIR_BACKGROUND_OPACITY) .style('pointer-events', 'none'); @@ -134,7 +134,7 @@ export class LinePod extends ChartwerkPod { .attr('cy', -CROSSHAIR_CIRCLE_RADIUS) .attr('class', `crosshair-circle-${serieIdx}`) .attr('clip-path', `url(#${this.rectClipId})`) - .attr('fill', this.coreSeries.visibleSeries[serieIdx].color) + .attr('fill', this.series.visibleSeries[serieIdx].color) .attr('r', CROSSHAIR_CIRCLE_RADIUS) .style('pointer-events', 'none'); } @@ -146,7 +146,7 @@ export class LinePod extends ChartwerkPod { this.moveCrosshairLine(eventX, eventY); const datapoints = this.findAndHighlightDatapoints(values.x, values.y); - this.coreOptions.callbackSharedCrosshairMove({ + this.options.callbackSharedCrosshairMove({ datapoints: datapoints, eventX, eventY }); @@ -157,7 +157,7 @@ export class LinePod extends ChartwerkPod { } moveCrosshairLine(xPosition: number, yPosition: number): void { - switch(this.coreOptions.crosshair.orientation) { + switch(this.options.crosshair.orientation) { case CrosshairOrientation.VERTICAL: this.crosshair.select('#crosshair-line-x') .attr('x1', xPosition) @@ -177,7 +177,7 @@ export class LinePod extends ChartwerkPod { .attr('y2', yPosition); return; default: - throw new Error(`Unknown type of crosshair orientaion: ${this.coreOptions.crosshair.orientation}`); + throw new Error(`Unknown type of crosshair orientaion: ${this.options.crosshair.orientation}`); } } @@ -205,7 +205,7 @@ export class LinePod extends ChartwerkPod { getClosestIndex(datapoints: [number, number][], xValue: number, yValue: number): number { let columnIdx; // 0 for x value, 1 for y value, let value; // xValue to y Value - switch(this.coreOptions.crosshair.orientation) { + switch(this.options.crosshair.orientation) { case CrosshairOrientation.VERTICAL: columnIdx = 0; value = xValue; @@ -219,7 +219,7 @@ export class LinePod extends ChartwerkPod { columnIdx = 1; value = yValue; default: - throw new Error(`Unknown type of crosshair orientaion: ${this.coreOptions.crosshair.orientation}`); + throw new Error(`Unknown type of crosshair orientaion: ${this.options.crosshair.orientation}`); } // TODO: d3.bisect is not the best way. Use binary search @@ -248,7 +248,7 @@ export class LinePod extends ChartwerkPod { // columnIdx: 1 for y, 0 for x // inverval: x/y value interval between data points // TODO: move it to base/state instead of timeInterval - const intervals = _.map(this.coreSeries.visibleSeries, serie => { + const intervals = _.map(this.series.visibleSeries, serie => { if(serie.datapoints.length < 2) { return undefined; } @@ -272,7 +272,7 @@ export class LinePod extends ChartwerkPod { // TDOO: is shift key pressed // TODO: need to refactor this object - this.coreOptions.callbackMouseMove({ + this.options.callbackMouseMove({ x: d3.event.pageX, y: d3.event.pageY, xVal: xValue, @@ -284,11 +284,11 @@ export class LinePod extends ChartwerkPod { } findAndHighlightDatapoints(xValue: number, yValue: number): { value: [number, number], color: string, label: string }[] { - if(!this.coreSeries.isSeriesAvailable) { + if(!this.series.isSeriesAvailable) { return []; } let points = []; // datapoints in each metric that is closest to xValue/yValue position - this.coreSeries.visibleSeries.forEach((serie: LineTimeSerie) => { + this.series.visibleSeries.forEach((serie: LineTimeSerie) => { const closestDatapoint = this.getClosestDatapoint(serie, xValue, yValue); if(closestDatapoint === undefined) { this.hideCrosshairCircle(serie.idx); @@ -315,21 +315,21 @@ export class LinePod extends ChartwerkPod { } onMouseOut(): void { - this.coreOptions.callbackMouseOut(); + this.options.callbackMouseOut(); this.crosshair.style('display', 'none'); } isDoubleClickActive(): boolean { - return this.coreOptions.doubleClickEvent.isActive; + return this.options.doubleClickEvent.isActive; } - // methods below rewrite cores, (move more methods here) + // methods below rewrite s, (move more methods here) protected zoomOut(): void { if(d3.event.type === 'dblclick' && !this.isDoubleClickActive()) { return; } // TODO: its not clear, why we use this orientation here. Mb its better to use separate option - const orientation: BrushOrientation = this.coreOptions.mouseZoomEvent.orientation; + const orientation: BrushOrientation = this.options.mouseZoomEvent.orientation; const xInterval = this.state.xValueRange[1] - this.state.xValueRange[0]; const yInterval = this.state.yValueRange[1] - this.state.yValueRange[0]; switch(orientation) { @@ -364,7 +364,7 @@ export class LinePod extends ChartwerkPod { x: xAxisMiddleValue, y: yAxisMiddleValue } - this.coreOptions.callbackZoomOut(centers); + this.options.callbackZoomOut(centers); } } diff --git a/yarn.lock b/yarn.lock index edf1642..4aec6d8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6,12 +6,12 @@ __metadata: cacheKey: 8 "@chartwerk/core@npm:latest": - version: 0.5.8 - resolution: "@chartwerk/core@npm:0.5.8" + version: 0.6.0 + resolution: "@chartwerk/core@npm:0.6.0" dependencies: d3: ^5.7.2 lodash: ^4.14.149 - checksum: 24b403af2703cc99ef3dee4793318ed71f4b02ed50bee6940774ccb392b8fbb53bb5353e91903b2c1ec815a8d2b830f2a2a2925d8e4380c64895ee2002b2baed + checksum: db368ea1ba1f9b48583c3da953998206329ea552eaff4e9f13cb02b25e0289464eca268baa86f045d62552a0859fc3ee2ccf70e7df95b58327bba217f9888169 languageName: node linkType: hard