mirror of https://github.com/buster-so/buster.git
Update chartjs-plugin-trendlines.ts
This commit is contained in:
parent
d5a37ccbcd
commit
7c99f4ad7d
|
@ -306,7 +306,7 @@ class MedianFitter extends BaseFitter {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create appropriate fitter based on options
|
// Create appropriate fitter based on options
|
||||||
function createFitter(opts: TrendlineOptions): BaseFitter {
|
const createFitter = (opts: TrendlineOptions): BaseFitter => {
|
||||||
switch (opts.type) {
|
switch (opts.type) {
|
||||||
case 'polynomial_regression':
|
case 'polynomial_regression':
|
||||||
return new PolynomialFitter(opts.polynomialOrder ?? 2);
|
return new PolynomialFitter(opts.polynomialOrder ?? 2);
|
||||||
|
@ -326,15 +326,15 @@ function createFitter(opts: TrendlineOptions): BaseFitter {
|
||||||
default:
|
default:
|
||||||
return new LinearFitter();
|
return new LinearFitter();
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
// Process padding options
|
// Process padding options
|
||||||
function processPadding(
|
const processPadding = (
|
||||||
labelPadding:
|
labelPadding:
|
||||||
| number
|
| number
|
||||||
| { top?: number; bottom?: number; left?: number; right?: number }
|
| { top?: number; bottom?: number; left?: number; right?: number }
|
||||||
| undefined
|
| undefined
|
||||||
): { top: number; right: number; bottom: number; left: number } {
|
): { top: number; right: number; bottom: number; left: number } => {
|
||||||
const defaultPadding = defaultLabelOptionConfig.padding;
|
const defaultPadding = defaultLabelOptionConfig.padding;
|
||||||
|
|
||||||
if (typeof labelPadding === 'number') {
|
if (typeof labelPadding === 'number') {
|
||||||
|
@ -354,10 +354,10 @@ function processPadding(
|
||||||
bottom: defaultPadding.bottom,
|
bottom: defaultPadding.bottom,
|
||||||
left: defaultPadding.left
|
left: defaultPadding.left
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
// Set line style based on options
|
// Set line style based on options
|
||||||
function setLineStyle(ctx: CanvasRenderingContext2D, lineStyle?: string, lineWidth: number = 2) {
|
const setLineStyle = (ctx: CanvasRenderingContext2D, lineStyle?: string, lineWidth: number = 2) => {
|
||||||
ctx.lineWidth = lineWidth;
|
ctx.lineWidth = lineWidth;
|
||||||
|
|
||||||
switch (lineStyle) {
|
switch (lineStyle) {
|
||||||
|
@ -373,16 +373,16 @@ function setLineStyle(ctx: CanvasRenderingContext2D, lineStyle?: string, lineWid
|
||||||
default:
|
default:
|
||||||
ctx.setLineDash([]);
|
ctx.setLineDash([]);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
// Draw a label with background
|
// Draw a label with background
|
||||||
function drawLabel(
|
const drawLabel = (
|
||||||
ctx: CanvasRenderingContext2D,
|
ctx: CanvasRenderingContext2D,
|
||||||
text: string,
|
text: string,
|
||||||
x: number,
|
x: number,
|
||||||
y: number,
|
y: number,
|
||||||
options: TrendlineLabelOptions
|
options: TrendlineLabelOptions
|
||||||
) {
|
) => {
|
||||||
// Apply defaults from defaultLabelOptionConfig
|
// Apply defaults from defaultLabelOptionConfig
|
||||||
const fontSize = options.font?.size ?? defaultLabelOptionConfig.font.size;
|
const fontSize = options.font?.size ?? defaultLabelOptionConfig.font.size;
|
||||||
const fontFamily = options.font?.family ?? 'sans-serif';
|
const fontFamily = options.font?.family ?? 'sans-serif';
|
||||||
|
@ -455,10 +455,10 @@ function drawLabel(
|
||||||
|
|
||||||
ctx.fillText(text, textX, textY);
|
ctx.fillText(text, textX, textY);
|
||||||
ctx.restore();
|
ctx.restore();
|
||||||
}
|
};
|
||||||
|
|
||||||
// Draw curved or straight line path
|
// Draw curved or straight line path
|
||||||
function drawLinePath(
|
const drawLinePath = (
|
||||||
ctx: CanvasRenderingContext2D,
|
ctx: CanvasRenderingContext2D,
|
||||||
xScale: any,
|
xScale: any,
|
||||||
yScale: any,
|
yScale: any,
|
||||||
|
@ -466,7 +466,7 @@ function drawLinePath(
|
||||||
minX: number,
|
minX: number,
|
||||||
maxX: number,
|
maxX: number,
|
||||||
lineType: TrendlineType
|
lineType: TrendlineType
|
||||||
) {
|
) => {
|
||||||
const x1 = xScale.getPixelForValue(minX);
|
const x1 = xScale.getPixelForValue(minX);
|
||||||
const y1 = yScale.getPixelForValue(fitter.f(minX));
|
const y1 = yScale.getPixelForValue(fitter.f(minX));
|
||||||
|
|
||||||
|
@ -501,10 +501,10 @@ function drawLinePath(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
// Fill area under the trendline
|
// Fill area under the trendline
|
||||||
function fillUnderLine(
|
const fillUnderLine = (
|
||||||
ctx: CanvasRenderingContext2D,
|
ctx: CanvasRenderingContext2D,
|
||||||
xScale: any,
|
xScale: any,
|
||||||
yScale: any,
|
yScale: any,
|
||||||
|
@ -514,7 +514,7 @@ function fillUnderLine(
|
||||||
lineType: TrendlineType,
|
lineType: TrendlineType,
|
||||||
fillStyle: string,
|
fillStyle: string,
|
||||||
chartBottom: number
|
chartBottom: number
|
||||||
) {
|
) => {
|
||||||
ctx.fillStyle = fillStyle;
|
ctx.fillStyle = fillStyle;
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
|
|
||||||
|
@ -528,10 +528,10 @@ function fillUnderLine(
|
||||||
ctx.lineTo(x1, chartBottom);
|
ctx.lineTo(x1, chartBottom);
|
||||||
ctx.closePath();
|
ctx.closePath();
|
||||||
ctx.fill();
|
ctx.fill();
|
||||||
}
|
};
|
||||||
|
|
||||||
// Process data points from a dataset
|
// Process data points from a dataset
|
||||||
function addDataPointsToFitter(dataset: any, fitter: BaseFitter, yAxisID?: string) {
|
const addDataPointsToFitter = (dataset: any, fitter: BaseFitter, yAxisID?: string) => {
|
||||||
dataset.data.forEach((point: any, i: number) => {
|
dataset.data.forEach((point: any, i: number) => {
|
||||||
const x = point['x'] ?? i;
|
const x = point['x'] ?? i;
|
||||||
const y = point[yAxisID ?? dataset.yAxisID ?? 'y'] ?? point;
|
const y = point[yAxisID ?? dataset.yAxisID ?? 'y'] ?? point;
|
||||||
|
@ -539,7 +539,7 @@ function addDataPointsToFitter(dataset: any, fitter: BaseFitter, yAxisID?: strin
|
||||||
fitter.add(x, y);
|
fitter.add(x, y);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
const trendlinePlugin: Plugin<'line'> = {
|
const trendlinePlugin: Plugin<'line'> = {
|
||||||
id: 'chartjs-plugin-trendline-ts',
|
id: 'chartjs-plugin-trendline-ts',
|
||||||
|
@ -690,20 +690,20 @@ const trendlinePlugin: Plugin<'line'> = {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Helper function to check if two rectangles overlap
|
// Helper function to check if two rectangles overlap
|
||||||
function doRectsOverlap(
|
const doRectsOverlap = (
|
||||||
rect1: { x: number; y: number; width: number; height: number },
|
rect1: { x: number; y: number; width: number; height: number },
|
||||||
rect2: { x: number; y: number; width: number; height: number }
|
rect2: { x: number; y: number; width: number; height: number }
|
||||||
): boolean {
|
): boolean => {
|
||||||
return (
|
return (
|
||||||
rect1.x < rect2.x + rect2.width &&
|
rect1.x < rect2.x + rect2.width &&
|
||||||
rect1.x + rect1.width > rect2.x &&
|
rect1.x + rect1.width > rect2.x &&
|
||||||
rect1.y < rect2.y + rect2.height &&
|
rect1.y < rect2.y + rect2.height &&
|
||||||
rect1.y + rect1.height > rect2.y
|
rect1.y + rect1.height > rect2.y
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
// Helper function to queue a label for later drawing
|
// Helper function to queue a label for later drawing
|
||||||
function queueTrendlineLabel(
|
const queueTrendlineLabel = (
|
||||||
ctx: CanvasRenderingContext2D,
|
ctx: CanvasRenderingContext2D,
|
||||||
xScale: any,
|
xScale: any,
|
||||||
yScale: any,
|
yScale: any,
|
||||||
|
@ -718,7 +718,7 @@ function queueTrendlineLabel(
|
||||||
opts: TrendlineLabelOptions;
|
opts: TrendlineLabelOptions;
|
||||||
}>,
|
}>,
|
||||||
labelIndices?: { datasetIndex: number; trendlineIndex: number }
|
labelIndices?: { datasetIndex: number; trendlineIndex: number }
|
||||||
) {
|
) => {
|
||||||
if (!opts.label?.display) return;
|
if (!opts.label?.display) return;
|
||||||
|
|
||||||
let minX = opts.projection ? (xScale.min as number) : fitter.minx;
|
let minX = opts.projection ? (xScale.min as number) : fitter.minx;
|
||||||
|
@ -820,10 +820,10 @@ function queueTrendlineLabel(
|
||||||
y: finalY,
|
y: finalY,
|
||||||
opts: lbl
|
opts: lbl
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
// Helper function to draw just the trendline path (without labels)
|
// Helper function to draw just the trendline path (without labels)
|
||||||
function drawTrendlinePath(
|
const drawTrendlinePath = (
|
||||||
ctx: CanvasRenderingContext2D,
|
ctx: CanvasRenderingContext2D,
|
||||||
chartArea: { bottom: number },
|
chartArea: { bottom: number },
|
||||||
xScale: any,
|
xScale: any,
|
||||||
|
@ -831,7 +831,7 @@ function drawTrendlinePath(
|
||||||
fitter: BaseFitter,
|
fitter: BaseFitter,
|
||||||
opts: TrendlineOptions,
|
opts: TrendlineOptions,
|
||||||
defaultColor: string
|
defaultColor: string
|
||||||
) {
|
) => {
|
||||||
// project if requested
|
// project if requested
|
||||||
let minX = opts.projection ? (xScale.min as number) : fitter.minx;
|
let minX = opts.projection ? (xScale.min as number) : fitter.minx;
|
||||||
const maxX = opts.projection ? (xScale.max as number) : fitter.maxx;
|
const maxX = opts.projection ? (xScale.max as number) : fitter.maxx;
|
||||||
|
@ -881,6 +881,6 @@ function drawTrendlinePath(
|
||||||
|
|
||||||
// cleanup
|
// cleanup
|
||||||
ctx.restore();
|
ctx.restore();
|
||||||
}
|
};
|
||||||
|
|
||||||
export default trendlinePlugin;
|
export default trendlinePlugin;
|
||||||
|
|
Loading…
Reference in New Issue