UNPKG

@future-grid/fgp-graph

Version:

fgp-graph is a chart lib based on Dygraphs

156 lines (124 loc) 4.88 kB
import Dygraph from "dygraphs"; export default class RectSelection { private g?: Dygraph; private readonly canvas: HTMLCanvasElement; private drawable = false; private mousePosition: { x: number, y: number, startX: number, startY: number }; /** * rect selection plugin * @param onSelect callback func */ constructor(public onSelect?: (series: Array<string>) => void) { this.canvas = document.createElement("canvas"); // init mouse position var this.mousePosition = { x: 0, y: 0, startX: 0, startY: 0 }; } activate = (graph: Dygraph) => { const dygraph: any = this.g = graph; this.canvas.width = dygraph.graphDiv?.clientWidth; this.canvas.height = dygraph.graphDiv?.clientHeight; this.canvas.setAttribute("style", `position:absolute;`); this.canvas.style.display = "none"; // add canvas to graphDiv dygraph.graphDiv?.appendChild(this.canvas); console.log(`${this.canvas.width} ${this.canvas.height}`); // init mouse event listener const ctx = this.canvas.getContext("2d"); if (ctx) { this.interactions(this.canvas, dygraph, ctx); } }; private interactions = (canvas: HTMLCanvasElement, g: any, ctx: CanvasRenderingContext2D) => { // mousedown canvas.addEventListener("mousedown", (e: MouseEvent) => { this.drawable = true; // set draw position this.mousePosition = { x: e.offsetX, y: e.offsetY, startX: e.offsetX, startY: e.offsetY }; // canvas.style.cursor = "crosshair"; // clean draw area ctx?.clearRect(0, 0, g.width_, g.height_); }); // mousemove canvas.addEventListener("mousemove", (e: MouseEvent) => { if (this.drawable) { this.mousePosition.x = e.offsetX; this.mousePosition.y = e.offsetY; ctx.strokeStyle = "#FF0000"; ctx.lineWidth = 1; ctx.setLineDash([5, 10]); ctx.clearRect(0, 0, g.width_, g.height_); // draw rect ctx.strokeRect(this.mousePosition.startX, this.mousePosition.startY, this.mousePosition.x - this.mousePosition.startX, this.mousePosition.y - this.mousePosition.startY); } }); // mouseup canvas.addEventListener("mouseup", (e: MouseEvent) => { this.drawable = false; this.canvas.style.cursor = "default"; const rect = this.mousePosition; // reset start end const startX = rect.startX <= rect.x ? rect.startX : rect.x; const endX = rect.startX > rect.x ? rect.startX : rect.x; const startY = rect.startY <= rect.y ? rect.startY : rect.y; const endY = rect.startY > rect.y ? rect.startY : rect.y; const minDate = g.toDataXCoord(startX); const maxDate = g.toDataXCoord(endX); const maxY = g.toDataYCoord(startY); const minY = g.toDataYCoord(endY); const graphData = g.file_; const labels = g.getLabels(); const visibility = g.getOption('visibility'); const chosenSeries: Array<string> = []; // get points graphData.forEach((_d: any) => { // check date range if (_d[0] instanceof Date && _d[0] >= minDate && _d[0] <= maxDate) { for (let i = 1; i < _d.length; i++) { if (_d[i] >= minY && _d[i] <= maxY && chosenSeries.indexOf(labels[i]) == -1) { if (visibility[i - 1]) { chosenSeries.push(labels[i]); } } } } }); // call callback if (this.onSelect && chosenSeries.length > 0) { this.onSelect(chosenSeries); } }); }; /** * dynamic set callback func * @param onSelect */ public setCallback = (onSelect?: (series: Array<string>) => void) => { onSelect ? this.onSelect = onSelect : null; }; enable = () => { this.canvas.style.display = ""; }; disable = () => { const ctx = this.canvas.getContext("2d"); ctx?.clearRect(0, 0, this.canvas.width, this.canvas.height); this.canvas.style.display = "none"; }; clear = () => { const ctx = this.canvas.getContext("2d"); ctx?.clearRect(0, 0, this.canvas.width, this.canvas.height); }; destroy = () => { this.canvas.remove(); }; }