diff --git a/examples/demo.html b/examples/demo.html index 98b8f0f..0c4c3d2 100644 --- a/examples/demo.html +++ b/examples/demo.html @@ -45,11 +45,13 @@ axis: { x: { format: 'numeric', - range: [-100, 300] + range: [-100, 300], + label: 'x' }, y: { invert: true, - range: [-100, 250] + range: [-100, 250], + label: 'y' }, y1: { isActive: true, @@ -70,10 +72,6 @@ orientation: 'both', color: 'gray' }, - labelFormat: { - yAxis: 'y', - xAxis: 'x' - }, eventsCallbacks: { zoomOut: () => { pod.render() } }, diff --git a/package.json b/package.json index 777d299..e83e9ca 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": {}, "author": "CorpGlory", diff --git a/src/index.ts b/src/index.ts index 8fde794..2d5683b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,17 +1,14 @@ -import { ChartwerkPod, VueChartwerkPodMixin, TickOrientation, TimeFormat, yAxisOrientation, CrosshairOrientation } from '@chartwerk/core'; +import { ChartwerkPod, VueChartwerkPodMixin, TimeFormat, yAxisOrientation, CrosshairOrientation } from '@chartwerk/core'; import { ScatterData, ScatterOptions, PointType, LineType } from './types'; -import { DelaunayDiagram } from './delaunay'; +import { DelaunayDiagram } from './models/delaunay'; +import { ScatterSeries } from './models/scatter_series'; import * as d3 from 'd3'; import * as _ from 'lodash'; -// TODO: use pod state with defaults -const DEFAULT_POINT_SIZE = 4; const POINT_HIGHLIGHT_DIAMETER = 4; const CROSSHAIR_BACKGROUND_OPACITY = 0.3; -const DEFAULT_POINT_TYPE = PointType.CIRCLE; -const DEFAULT_LINE_TYPE = LineType.NONE; const DEFAULT_LINE_DASHED_AMOUNT = 4; export class ChartwerkScatterPod extends ChartwerkPod { @@ -20,16 +17,17 @@ export class ChartwerkScatterPod extends ChartwerkPod { - this.appendCrosshairPoint(serieIdx); + this.series.visibleSeries.forEach((serie: ScatterData) => { + this.appendCrosshairPoint(serie.idx, serie.pointType, serie.pointSize); }); } - protected appendCrosshairPoint(serieIdx: number): void { + protected appendCrosshairPoint(serieIdx: number, pointType: PointType, size: number): void { // TODO: add Crosshair type options - const pointType = this.series[serieIdx].pointType || DEFAULT_POINT_TYPE; switch(pointType) { case PointType.NONE: return; case PointType.CIRCLE: this.crosshair.append('circle') .attr('class', `crosshair-point crosshair-point-${serieIdx} crosshair-background`) - .attr('r', this.getCrosshairCircleBackgroundSize(serieIdx)) + .attr('r', this.getCrosshairCircleBackgroundSize(size, pointType)) .attr('clip-path', `url(#${this.rectClipId})`) .style('opacity', CROSSHAIR_BACKGROUND_OPACITY) .style('pointer-events', 'none') @@ -70,8 +67,8 @@ export class ChartwerkScatterPod extends ChartwerkPod { - if(serie.visible === false) { - return; - } - const lineType = serie.lineType || DEFAULT_LINE_TYPE; - this.renderLine(serie.datapoints, lineType, this.getSerieColor(serieIdx), serie.yOrientation); + this.series.visibleSeries.forEach(serie => { + this.renderLine(serie); }); } - renderLine(datapoints: number[][], lineType: LineType, color: string, orientation: yAxisOrientation): void { - if(lineType === LineType.NONE) { + renderLine(serie: ScatterData): void { + if(serie.lineType === LineType.NONE) { return; } let strokeDasharray; // TODO: move to option - if(lineType === LineType.DASHED) { + if(serie.lineType === LineType.DASHED) { strokeDasharray = DEFAULT_LINE_DASHED_AMOUNT; } const lineGenerator = d3.line() - .x((d: [number, number]) => this.xScale(d[0])) - .y((d: [number, number]) => this.getYScale(orientation)(d[1])); + .x((d: [number, number]) => this.state.xScale(d[0])) + .y((d: [number, number]) => this.getYScale(serie.yOrientation)(d[1])); this.metricContainer .append('path') - .datum(datapoints) + .datum(serie.datapoints) .attr('class', 'metric-path') .attr('fill', 'none') .style('pointer-events', 'none') - .attr('stroke', color) + .attr('stroke', serie.color) .attr('stroke-width', 1) .attr('stroke-opacity', 0.7) .attr('stroke-dasharray', strokeDasharray) @@ -127,46 +120,47 @@ export class ChartwerkScatterPod extends ChartwerkPod this.series[_.last(d)].pointType !== PointType.RECTANGLE) + .filter((d: number[]) => this.getSerieByIdx(_.last(d))?.pointType !== PointType.RECTANGLE) .attr('class', (d, i: number) => `metric-element metric-circle point-${i}`) - .attr('r', (d: number[]) => this.series[_.last(d)].pointSize || DEFAULT_POINT_SIZE) + .attr('r', (d: number[]) => this.getSerieByIdx(_.last(d))?.pointSize) .style('fill', (d: number[], i: number) => this.getSeriesColorFromDataRow(d, i)) .style('pointer-events', 'none') - .attr('cx', (d: any[]) => this.xScale(d[0])) - .attr('cy', (d: any[]) => this.getYScale(this.series[_.last(d)].yOrientation)(d[1])); + .attr('cx', (d: any[]) => this.state.xScale(d[0])) + .attr('cy', (d: any[]) => this.getYScale(this.getSerieByIdx(_.last(d))?.yOrientation)(d[1])); this.metricContainer.selectAll(null) .data(this._delaunayDiagram.data) .enter() .append('rect') - .filter((d: number[]) => this.series[_.last(d)].pointType === PointType.RECTANGLE) + .filter((d: number[]) => this.getSerieByIdx(_.last(d))?.pointType === PointType.RECTANGLE) .attr('class', (d, i: number) => `metric-element metric-circle point-${i}`) - .attr('r', (d: number[]) => this.series[_.last(d)].pointSize || DEFAULT_POINT_SIZE) - .style('fill', (d: number[]) => this.getSerieColor(_.last(d))) + .attr('r', (d: number[]) => this.getSerieByIdx(_.last(d))?.pointSize) + .style('fill', (d: number[]) => this.getSerieByIdx(_.last(d))?.color) .style('pointer-events', 'none') - .attr('x', (d: number[]) => this.xScale(d[0]) - (this.series[_.last(d)].pointSize || DEFAULT_POINT_SIZE) / 2) - .attr('y', (d: number[]) => this.getYScale(this.series[_.last(d)].yOrientation)(d[1]) - (this.series[_.last(d)].pointSize || DEFAULT_POINT_SIZE) / 2) - .attr('width', (d: number[]) => this.series[_.last(d)].pointSize || DEFAULT_POINT_SIZE) - .attr('height', (d: number[]) => this.series[_.last(d)].pointSize || DEFAULT_POINT_SIZE); + .attr('x', (d: number[]) => this.state.xScale(d[0]) - this.getSerieByIdx(_.last(d))?.pointSize / 2) + .attr('y', (d: number[]) => this.getYScale(this.getSerieByIdx(_.last(d)).yOrientation)(d[1]) - this.getSerieByIdx(_.last(d))?.pointSize / 2) + .attr('width', (d: number[]) => this.getSerieByIdx(_.last(d))?.pointSize) + .attr('height', (d: number[]) => this.getSerieByIdx(_.last(d))?.pointSize); + } + + getSerieByIdx(idx: number): ScatterData | undefined { + return _.find(this.series.visibleSeries, serie => serie.idx === idx); } getSeriesColorFromDataRow(values: number[], rowIdx: number): string { const seriesIdx = _.last(values); - if(this.series[seriesIdx].colorFormatter) { - return this.series[seriesIdx].colorFormatter(values, rowIdx); + const serie = this.getSerieByIdx(seriesIdx); + if(serie?.colorFormatter) { + return serie.colorFormatter(values, rowIdx); } - return this.getSerieColor(seriesIdx); + return serie.color; } onPanningEnd(): void { this.isPanning = false; this.onMouseOut(); - this._delaunayDiagram.setDelaunayDiagram(this.xScale, this.getYScale.bind(this)); - if(this.options.eventsCallbacks !== undefined && this.options.eventsCallbacks.panningEnd !== undefined) { - this.options.eventsCallbacks.panningEnd([this.state.xValueRange, this.state.yValueRange, this.state.y1ValueRange]); - } else { - console.log('on panning end, but there is no callback'); - } + this._delaunayDiagram.setDelaunayDiagram(this.state.xScale, this.getYScale.bind(this)); + this.options.callbackPanningEnd([this.state.xValueRange, this.state.yValueRange, this.state.y1ValueRange]); } unhighlight(): void { @@ -182,40 +176,33 @@ export class ChartwerkScatterPod extends ChartwerkPod { - if(orientation === undefined || orientation === yAxisOrientation.BOTH) { - return this.yScale; - } switch(orientation) { case yAxisOrientation.LEFT: - return this.yScale; + return this.state.yScale; case yAxisOrientation.RIGHT: - return this.y1Scale; + return this.state.y1Scale; default: throw new Error(`Unknown type of y axis orientation: ${orientation}`) } @@ -287,8 +271,7 @@ export class ChartwerkScatterPod extends ChartwerkPod { - const serieIdx = this.getSerieIdxByTarget(serie.target); - const datapointsWithOptions = _.map(serie.datapoints, row => _.concat(row, serieIdx)); + const datapointsWithOptions = _.map(serie.datapoints, row => _.concat(row, serie.idx)); return datapointsWithOptions; }); return _.union(...datapointsList); } - - private getSerieIdxByTarget(target: string): number { - const idx = _.findIndex(this.series, serie => serie.target === target); - if(idx === -1) { - throw new Error(`Can't find serie with target: ${target}`); - } - return idx; - } } diff --git a/src/models/scatter_series.ts b/src/models/scatter_series.ts new file mode 100644 index 0000000..b173e22 --- /dev/null +++ b/src/models/scatter_series.ts @@ -0,0 +1,23 @@ +import { CoreSeries } from '@chartwerk/core'; +import { ScatterData, PointType, LineType } from '../types'; + + +const DEFAULT_POINT_SIZE = 4; + +const SCATTER_DATA_DEFAULTS = { + pointType: PointType.CIRCLE, + lineType: LineType.NONE, + pointSize: DEFAULT_POINT_SIZE, + colorFormatter: undefined +}; + +export class ScatterSeries extends CoreSeries { + + constructor(series: ScatterData[]) { + super(series); + } + + protected get defaults(): ScatterData { + return { ...this._coreDefaults, ...SCATTER_DATA_DEFAULTS }; + } +} diff --git a/src/types.ts b/src/types.ts index 533c431..e600963 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 ScatterDataParams = { @@ -9,10 +9,8 @@ type ScatterDataParams = { } type ScatterOptionsParams = { voronoiRadius: number; - circleView: boolean; - renderGrid: boolean; } -export type ScatterData = TimeSerie & Partial; +export type ScatterData = Serie & Partial; export type ScatterOptions = Options & Partial; export enum PointType { diff --git a/yarn.lock b/yarn.lock index 656a2aa..fd27b00 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.6.1 + resolution: "@chartwerk/core@npm:0.6.1" dependencies: d3: ^5.7.2 lodash: ^4.14.149 - checksum: 0d686409377d6880f0012db3d9c1e1910cf3660885ac13196dabe93f57eca53984cf52dcf781b2876373fe9efc7b9d0209117cbcd811c50892b1de4f38a4a37f + checksum: 6c57d4d3391a656f743f8459a97102fff8d4bc6f880d1d7e0abc3070dca7eff39edf46feccc7fa0dd36ca38771a63e5045966e49e65b0763404e01fee8ad11c5 languageName: node linkType: hard