Scatter Pod
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

79 lines
2.8 KiB

import { ScatterData, PointType, DelaunayDataRow } from '../types';
import { ScatterSeries } from './scatter_series';
import { Delaunay } from 'd3-delaunay';
import * as _ from 'lodash';
import * as d3 from 'd3'; // only types
export class DelaunayDiagram {
private _delaunayData: DelaunayDataRow[];
private _delaunayDiagram: any;
constructor(
protected series: ScatterSeries,
xScale: d3.ScaleLinear<number, number>, yScale: (string) => d3.ScaleLinear<number, number>, // TODO: bad, but idk how to do it better
) {
this._delaunayData = this.getDatapointsForDelaunay();
this.setDelaunayDiagram(xScale, yScale);
}
public get data(): DelaunayDataRow[] | undefined {
if(!this._delaunayData || this._delaunayData.length === 0) {
return undefined;
}
return this._delaunayData;
}
public setDelaunayDiagram(xScale: d3.ScaleLinear<number, number>, yScale: (string) => d3.ScaleLinear<number, number>) {
if(!this._delaunayData) {
console.warn('No data for delaunay initialization');
return;
}
console.time('delaunay-init');
this._delaunayDiagram = Delaunay.from(
this._delaunayData,
(d: DelaunayDataRow) => xScale(d[0]),
(d: DelaunayDataRow) => yScale(this.series.getSerieByTarget(d[4])?.yOrientation)(d[1]),
);
console.timeEnd('delaunay-init');
}
public findPointIndex(eventX: number, eventY: number): number | undefined {
if(!this._delaunayDiagram) {
return undefined;
}
let pointIndex = this._delaunayDiagram.find(eventX, eventY);
if(pointIndex === -1) {
return undefined;
}
// TODO: add search radius via https://github.com/d3/d3-delaunay/issues/45
return pointIndex;
}
public getDataRowByIndex(index: number): DelaunayDataRow | undefined {
if(!this.data) {
return undefined;
}
return this.data[index];
}
private getDatapointsForDelaunay(): DelaunayDataRow[] | undefined {
// here we union all datapoints with point render type(circle or rectangle)
// it means that circles and rectangles will be highlighted(not lines)
// TODO: set Defaults (if pointType === undefined, Circle type will be used futher)
const seriesForPointType = this.series.visibleSeries.filter((serie: ScatterData) => serie.pointType !== PointType.NONE);
if(seriesForPointType.length === 0) {
return undefined; // to avoid ts error
}
return this.concatSeriesDatapoints(seriesForPointType);
}
private concatSeriesDatapoints(series: ScatterData[]): DelaunayDataRow[] {
const datapointsList = _.map(series, serie => {
const datapointsWithOptions = _.map(serie.datapoints, (row, rowIdx) => [row[0], row[1], row[2] || null, rowIdx, serie.target]);
return datapointsWithOptions;
});
return _.union(...datapointsList);
}
}