@oliasoft-open-source/charts-library 5.10.0 → 5.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +4 -4
- package/dist/index.js +712 -106
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1193,16 +1193,16 @@ export { }
|
|
|
1193
1193
|
|
|
1194
1194
|
declare module 'chart.js' {
|
|
1195
1195
|
interface PluginOptionsByType<TType extends ChartType> {
|
|
1196
|
-
|
|
1197
|
-
enableCalloutAnnotation?: boolean;
|
|
1198
|
-
};
|
|
1196
|
+
annotationDraggerPlugin?: AnnotationDraggerPluginOptions;
|
|
1199
1197
|
}
|
|
1200
1198
|
}
|
|
1201
1199
|
|
|
1202
1200
|
|
|
1203
1201
|
declare module 'chart.js' {
|
|
1204
1202
|
interface PluginOptionsByType<TType extends ChartType> {
|
|
1205
|
-
|
|
1203
|
+
calloutConnectorPlugin?: {
|
|
1204
|
+
enableCalloutAnnotation?: boolean;
|
|
1205
|
+
};
|
|
1206
1206
|
}
|
|
1207
1207
|
}
|
|
1208
1208
|
|
package/dist/index.js
CHANGED
|
@@ -14364,7 +14364,7 @@ function isZoomingOrPanning(chart) {
|
|
|
14364
14364
|
const state = getState(chart);
|
|
14365
14365
|
return state.panning || state.dragging;
|
|
14366
14366
|
}
|
|
14367
|
-
var clamp$
|
|
14367
|
+
var clamp$3 = (x, from, to) => Math.min(to, Math.max(from, x));
|
|
14368
14368
|
function removeHandler(chart, type) {
|
|
14369
14369
|
const { handlers } = getState(chart);
|
|
14370
14370
|
const handler = handlers[type];
|
|
@@ -14450,8 +14450,8 @@ function applyAspectRatio({ begin, end }, aspectRatio) {
|
|
|
14450
14450
|
end.y = begin.y + height;
|
|
14451
14451
|
}
|
|
14452
14452
|
function applyMinMaxProps(rect, chartArea, points, { min, max, prop }) {
|
|
14453
|
-
rect[min] = clamp$
|
|
14454
|
-
rect[max] = clamp$
|
|
14453
|
+
rect[min] = clamp$3(Math.min(points.begin[prop], points.end[prop]), chartArea[min], chartArea[max]);
|
|
14454
|
+
rect[max] = clamp$3(Math.max(points.begin[prop], points.end[prop]), chartArea[min], chartArea[max]);
|
|
14455
14455
|
}
|
|
14456
14456
|
function getRelativePoints(chart, pointEvents, maintainAspectRatio) {
|
|
14457
14457
|
const points = {
|
|
@@ -15889,7 +15889,7 @@ var isOlderPart = (act, req) => req > act || act.length > req.length && act.slic
|
|
|
15889
15889
|
* @typedef { import('../../types/element').AnnotationElement } AnnotationElement
|
|
15890
15890
|
*/
|
|
15891
15891
|
var EPSILON = .001;
|
|
15892
|
-
var clamp$
|
|
15892
|
+
var clamp$2 = (x, from, to) => Math.min(to, Math.max(from, x));
|
|
15893
15893
|
/**
|
|
15894
15894
|
* @param {{value: number, start: number, end: number}} limit
|
|
15895
15895
|
* @param {number} hitSize
|
|
@@ -15903,7 +15903,7 @@ var inLimit = (limit, hitSize) => limit.value >= limit.start - hitSize && limit.
|
|
|
15903
15903
|
* @returns {Object}
|
|
15904
15904
|
*/
|
|
15905
15905
|
function clampAll(obj, from, to) {
|
|
15906
|
-
for (const key of Object.keys(obj)) obj[key] = clamp$
|
|
15906
|
+
for (const key of Object.keys(obj)) obj[key] = clamp$2(obj[key], from, to);
|
|
15907
15907
|
return obj;
|
|
15908
15908
|
}
|
|
15909
15909
|
/**
|
|
@@ -15977,7 +15977,7 @@ function requireVersion(pkg, min, ver, strict = true) {
|
|
|
15977
15977
|
}
|
|
15978
15978
|
var isPercentString = (s) => typeof s === "string" && s.endsWith("%");
|
|
15979
15979
|
var toPercent = (s) => parseFloat(s) / 100;
|
|
15980
|
-
var toPositivePercent = (s) => clamp$
|
|
15980
|
+
var toPositivePercent = (s) => clamp$2(toPercent(s), 0, 1);
|
|
15981
15981
|
var boxAppering = (x, y) => ({
|
|
15982
15982
|
x,
|
|
15983
15983
|
y,
|
|
@@ -16472,7 +16472,7 @@ function applyLabelContent(ctx, { x, y }, labels, { fonts, colors }) {
|
|
|
16472
16472
|
}
|
|
16473
16473
|
function getOpacity(value, elementValue) {
|
|
16474
16474
|
const opacity = isNumber$1(value) ? value : elementValue;
|
|
16475
|
-
return isNumber$1(opacity) ? clamp$
|
|
16475
|
+
return isNumber$1(opacity) ? clamp$2(opacity, 0, 1) : 1;
|
|
16476
16476
|
}
|
|
16477
16477
|
var positions = [
|
|
16478
16478
|
"left",
|
|
@@ -17912,7 +17912,7 @@ function calculateTAdjust(lineSize, sizes, label, space) {
|
|
|
17912
17912
|
const lineH = lineSize.h * space.dy;
|
|
17913
17913
|
const x = lineW > 0 && (labelSize.w / 2 + padding.left - space.x) / lineW;
|
|
17914
17914
|
const y = lineH > 0 && (labelSize.h / 2 + padding.top - space.y) / lineH;
|
|
17915
|
-
return clamp$
|
|
17915
|
+
return clamp$2(Math.max(x, y), 0, .25);
|
|
17916
17916
|
}
|
|
17917
17917
|
function spaceAround(properties, chartArea) {
|
|
17918
17918
|
const { x, x2, y, y2 } = properties;
|
|
@@ -20892,87 +20892,590 @@ function addTransparency(input, alpha, out = "rgb") {
|
|
|
20892
20892
|
}
|
|
20893
20893
|
//#endregion
|
|
20894
20894
|
//#region src/components/common/helpers/callout-helpers/callout-helpers.ts
|
|
20895
|
+
var DEFAULT_FONT_SIZE = 12;
|
|
20896
|
+
var DEFAULT_PADDING = 5;
|
|
20897
|
+
var DEFAULT_MARGIN = 8;
|
|
20898
|
+
var DEFAULT_LABEL_GAP = 8;
|
|
20899
|
+
var DEFAULT_MIN_CONNECTOR_LENGTH = 14;
|
|
20900
|
+
var DEFAULT_HORIZONTAL_OFFSET = 18;
|
|
20901
|
+
var DEFAULT_VERTICAL_OFFSET = -18;
|
|
20902
|
+
var DEFAULT_ROW_GAP = 22;
|
|
20903
|
+
var DEFAULT_ITEM_GAP = 8;
|
|
20904
|
+
var DEFAULT_OVERLAP_ONLY_ITEM_GAP = 14;
|
|
20905
|
+
var DEFAULT_LANE_GAP = 12;
|
|
20906
|
+
var clamp$1 = (value, min, max) => {
|
|
20907
|
+
if (Number.isNaN(value)) return min;
|
|
20908
|
+
if (min > max) return min;
|
|
20909
|
+
return Math.min(Math.max(value, min), max);
|
|
20910
|
+
};
|
|
20911
|
+
var clampRelaxed = (value, min, max) => {
|
|
20912
|
+
if (min <= max) return clamp$1(value, min, max);
|
|
20913
|
+
if (value < max) return max;
|
|
20914
|
+
if (value > min) return min;
|
|
20915
|
+
return value;
|
|
20916
|
+
};
|
|
20917
|
+
var getNumericValue = (value, fallback = 0) => {
|
|
20918
|
+
return typeof value === "number" ? value : fallback;
|
|
20919
|
+
};
|
|
20920
|
+
var getCalloutCfg = (annotation) => {
|
|
20921
|
+
return annotation?.labelConfig?.callout ?? {};
|
|
20922
|
+
};
|
|
20923
|
+
var getChartFromCtx$1 = (ctx) => {
|
|
20924
|
+
return ctx?.chart?.chart ?? ctx?.chart;
|
|
20925
|
+
};
|
|
20895
20926
|
var getXScale = (chart, axisId) => {
|
|
20896
20927
|
if (axisId && chart?.scales?.[axisId]) return chart.scales[axisId];
|
|
20897
20928
|
if (chart?.scales?.x) return chart.scales.x;
|
|
20898
|
-
const key = Object.keys(chart?.scales ?? {})?.find((
|
|
20929
|
+
const key = Object.keys(chart?.scales ?? {})?.find((item) => {
|
|
20930
|
+
return item?.toLowerCase()?.includes("x");
|
|
20931
|
+
});
|
|
20899
20932
|
return key ? chart?.scales?.[key] : void 0;
|
|
20900
20933
|
};
|
|
20901
20934
|
var getYScale = (chart, axisId) => {
|
|
20902
20935
|
if (axisId && chart?.scales?.[axisId]) return chart.scales[axisId];
|
|
20903
20936
|
if (chart?.scales?.y) return chart.scales.y;
|
|
20904
|
-
const key = Object.keys(chart?.scales ?? {})?.find((
|
|
20937
|
+
const key = Object.keys(chart?.scales ?? {})?.find((item) => {
|
|
20938
|
+
return item?.toLowerCase()?.includes("y");
|
|
20939
|
+
});
|
|
20905
20940
|
return key ? chart?.scales?.[key] : void 0;
|
|
20906
20941
|
};
|
|
20942
|
+
var resolveFontSize = (font) => {
|
|
20943
|
+
if (typeof font === "string") {
|
|
20944
|
+
const match = font.match(/(\d+(?:\.\d+)?)px/);
|
|
20945
|
+
return match ? Number(match[1]) : DEFAULT_FONT_SIZE;
|
|
20946
|
+
}
|
|
20947
|
+
if (font && typeof font === "object" && "size" in font) {
|
|
20948
|
+
const size = Number(font.size);
|
|
20949
|
+
return Number.isFinite(size) ? size : DEFAULT_FONT_SIZE;
|
|
20950
|
+
}
|
|
20951
|
+
return DEFAULT_FONT_SIZE;
|
|
20952
|
+
};
|
|
20953
|
+
var resolvePadding = (padding) => {
|
|
20954
|
+
if (typeof padding === "number") return {
|
|
20955
|
+
top: padding,
|
|
20956
|
+
right: padding,
|
|
20957
|
+
bottom: padding,
|
|
20958
|
+
left: padding
|
|
20959
|
+
};
|
|
20960
|
+
if (padding && typeof padding === "object") {
|
|
20961
|
+
const typedPadding = padding;
|
|
20962
|
+
return {
|
|
20963
|
+
top: Number(typedPadding.top ?? DEFAULT_PADDING),
|
|
20964
|
+
right: Number(typedPadding.right ?? DEFAULT_PADDING),
|
|
20965
|
+
bottom: Number(typedPadding.bottom ?? DEFAULT_PADDING),
|
|
20966
|
+
left: Number(typedPadding.left ?? DEFAULT_PADDING)
|
|
20967
|
+
};
|
|
20968
|
+
}
|
|
20969
|
+
return {
|
|
20970
|
+
top: DEFAULT_PADDING,
|
|
20971
|
+
right: DEFAULT_PADDING,
|
|
20972
|
+
bottom: DEFAULT_PADDING,
|
|
20973
|
+
left: DEFAULT_PADDING
|
|
20974
|
+
};
|
|
20975
|
+
};
|
|
20976
|
+
var estimateLabelSize = (chart, annotation, calloutCfg) => {
|
|
20977
|
+
const content = `${annotation?.label ?? ""}`;
|
|
20978
|
+
const fontSize = resolveFontSize(calloutCfg?.font);
|
|
20979
|
+
const padding = resolvePadding(calloutCfg?.padding);
|
|
20980
|
+
const lines = content.split("\n");
|
|
20981
|
+
const fallbackWidth = Math.max(...lines.map((line) => line.length), 0) * fontSize * .62;
|
|
20982
|
+
let measuredWidth = fallbackWidth;
|
|
20983
|
+
if (chart?.ctx) {
|
|
20984
|
+
chart.ctx.save();
|
|
20985
|
+
chart.ctx.font = typeof calloutCfg?.font === "string" ? calloutCfg.font : `${fontSize}px sans-serif`;
|
|
20986
|
+
measuredWidth = Math.max(...lines.map((line) => chart.ctx.measureText(line).width), fallbackWidth);
|
|
20987
|
+
chart.ctx.restore();
|
|
20988
|
+
}
|
|
20989
|
+
return {
|
|
20990
|
+
width: measuredWidth + padding.left + padding.right,
|
|
20991
|
+
height: lines.length * fontSize + padding.top + padding.bottom
|
|
20992
|
+
};
|
|
20993
|
+
};
|
|
20994
|
+
var getAxisId = (annotation, axis) => {
|
|
20995
|
+
const axisScaleId = axis === "x" ? annotation?.xScaleID : annotation?.yScaleID;
|
|
20996
|
+
if (axisScaleId) return axisScaleId;
|
|
20997
|
+
if (annotation?.annotationAxis?.startsWith(axis)) return annotation.annotationAxis;
|
|
20998
|
+
};
|
|
20999
|
+
var getAnchorPixel = (chart, annotation, axis, area) => {
|
|
21000
|
+
const scale = axis === "x" ? getXScale(chart, getAxisId(annotation, "x")) : getYScale(chart, getAxisId(annotation, "y"));
|
|
21001
|
+
const directValue = axis === "x" ? annotation?.xValue : annotation?.yValue;
|
|
21002
|
+
if (typeof directValue === "number" && scale) return scale.getPixelForValue(directValue);
|
|
21003
|
+
const minKey = axis === "x" ? "xMin" : "yMin";
|
|
21004
|
+
const maxKey = axis === "x" ? "xMax" : "yMax";
|
|
21005
|
+
const minValue = annotation?.[minKey];
|
|
21006
|
+
const maxValue = annotation?.[maxKey];
|
|
21007
|
+
if (typeof minValue === "number" && typeof maxValue === "number" && scale) return (scale.getPixelForValue(minValue) + scale.getPixelForValue(maxValue)) / 2;
|
|
21008
|
+
if (typeof minValue === "number" && scale) return scale.getPixelForValue(minValue);
|
|
21009
|
+
if (typeof maxValue === "number" && scale) return scale.getPixelForValue(maxValue);
|
|
21010
|
+
return axis === "x" ? (area.left + area.right) / 2 : (area.top + area.bottom) / 2;
|
|
21011
|
+
};
|
|
21012
|
+
var hasAxisAnchor = (annotation, axis) => {
|
|
21013
|
+
if (axis === "x") return typeof annotation?.xValue === "number" || typeof annotation?.xMin === "number" || typeof annotation?.xMax === "number" || annotation?.type === "box" || annotation?.type === "label" || annotation?.type === "ellipse";
|
|
21014
|
+
return typeof annotation?.yValue === "number" || typeof annotation?.yMin === "number" || typeof annotation?.yMax === "number" || annotation?.type === "box" || annotation?.type === "label" || annotation?.type === "ellipse";
|
|
21015
|
+
};
|
|
21016
|
+
var getBoxHalfWidth = (chart, area, annotation) => {
|
|
21017
|
+
const xScale = getXScale(chart, getAxisId(annotation, "x"));
|
|
21018
|
+
if (xScale && typeof annotation?.xMin === "number" && typeof annotation?.xMax === "number") return Math.abs(xScale.getPixelForValue(annotation.xMax) - xScale.getPixelForValue(annotation.xMin)) / 2;
|
|
21019
|
+
if (annotation?.type === "box") return (area.right - area.left) / 2;
|
|
21020
|
+
return annotation?.radius ?? 0;
|
|
21021
|
+
};
|
|
21022
|
+
var getBoxHalfHeight = (chart, annotation) => {
|
|
21023
|
+
const yScale = getYScale(chart, getAxisId(annotation, "y"));
|
|
21024
|
+
if (yScale && typeof annotation?.yMin === "number" && typeof annotation?.yMax === "number") return Math.abs(yScale.getPixelForValue(annotation.yMax) - yScale.getPixelForValue(annotation.yMin)) / 2;
|
|
21025
|
+
return annotation?.radius ?? 0;
|
|
21026
|
+
};
|
|
21027
|
+
var getReferencePoint$1 = (chart, area, annotation) => {
|
|
21028
|
+
const anchorX = getAnchorPixel(chart, annotation, "x", area);
|
|
21029
|
+
const anchorY = getAnchorPixel(chart, annotation, "y", area);
|
|
21030
|
+
const halfWidth = getBoxHalfWidth(chart, area, annotation);
|
|
21031
|
+
const halfHeight = getBoxHalfHeight(chart, annotation);
|
|
21032
|
+
const labelOffsetPx = getNumericValue(annotation?.labelOffsetPx, 14);
|
|
21033
|
+
const xAdjust = getNumericValue(annotation?.labelConfig?.xAdjust, 0);
|
|
21034
|
+
const yAdjust = getNumericValue(annotation?.labelConfig?.yAdjust, 0);
|
|
21035
|
+
const position = annotation?.labelConfig?.position;
|
|
21036
|
+
let x = anchorX;
|
|
21037
|
+
let y = anchorY;
|
|
21038
|
+
let side = anchorX >= (area.left + area.right) / 2 ? "right" : "left";
|
|
21039
|
+
switch (position) {
|
|
21040
|
+
case Position.Left:
|
|
21041
|
+
x -= Math.max(halfWidth, annotation?.radius ?? 0) + labelOffsetPx;
|
|
21042
|
+
side = "left";
|
|
21043
|
+
break;
|
|
21044
|
+
case Position.Right:
|
|
21045
|
+
x += Math.max(halfWidth, annotation?.radius ?? 0) + labelOffsetPx;
|
|
21046
|
+
side = "right";
|
|
21047
|
+
break;
|
|
21048
|
+
case Position.TopLeft:
|
|
21049
|
+
x -= halfWidth;
|
|
21050
|
+
y -= halfHeight;
|
|
21051
|
+
side = "left";
|
|
21052
|
+
break;
|
|
21053
|
+
case Position.TopRight:
|
|
21054
|
+
x += halfWidth;
|
|
21055
|
+
y -= halfHeight;
|
|
21056
|
+
side = "right";
|
|
21057
|
+
break;
|
|
21058
|
+
case Position.BottomLeft:
|
|
21059
|
+
x -= halfWidth;
|
|
21060
|
+
y += halfHeight;
|
|
21061
|
+
side = "left";
|
|
21062
|
+
break;
|
|
21063
|
+
case Position.BottomRight:
|
|
21064
|
+
x += halfWidth;
|
|
21065
|
+
y += halfHeight;
|
|
21066
|
+
side = "right";
|
|
21067
|
+
break;
|
|
21068
|
+
case Position.Bottom:
|
|
21069
|
+
y += Math.max(halfHeight, annotation?.radius ?? 0) + labelOffsetPx;
|
|
21070
|
+
break;
|
|
21071
|
+
case Position.Top:
|
|
21072
|
+
default:
|
|
21073
|
+
y -= Math.max(halfHeight, annotation?.radius ?? 0) + labelOffsetPx;
|
|
21074
|
+
break;
|
|
21075
|
+
}
|
|
21076
|
+
return {
|
|
21077
|
+
x: x + xAdjust,
|
|
21078
|
+
y: y + yAdjust,
|
|
21079
|
+
side
|
|
21080
|
+
};
|
|
21081
|
+
};
|
|
21082
|
+
var getOriginalLabelRect = (chart, area, annotation, index) => {
|
|
21083
|
+
const size = estimateLabelSize(chart, annotation, getCalloutCfg(annotation));
|
|
21084
|
+
const reference = getReferencePoint$1(chart, area, annotation);
|
|
21085
|
+
const direction = reference.side === "right" ? 1 : -1;
|
|
21086
|
+
const centerX = reference.x + direction * (size.width / 2);
|
|
21087
|
+
const centerY = reference.y;
|
|
21088
|
+
return {
|
|
21089
|
+
id: `callout-annotation-${index}`,
|
|
21090
|
+
side: reference.side,
|
|
21091
|
+
left: centerX - size.width / 2,
|
|
21092
|
+
right: centerX + size.width / 2,
|
|
21093
|
+
top: centerY - size.height / 2,
|
|
21094
|
+
bottom: centerY + size.height / 2
|
|
21095
|
+
};
|
|
21096
|
+
};
|
|
21097
|
+
var isRectOverlapping = (left, right) => {
|
|
21098
|
+
return !(left.right <= right.left || right.right <= left.left || left.bottom <= right.top || right.bottom <= left.top);
|
|
21099
|
+
};
|
|
21100
|
+
var getOverlappingCalloutIds = (chart) => {
|
|
21101
|
+
const area = chart?.chartArea;
|
|
21102
|
+
const annotationsData = (chart?.options)?.annotations?.annotationsData ?? [];
|
|
21103
|
+
if (!chart || !area) return /* @__PURE__ */ new Set();
|
|
21104
|
+
const rects = annotationsData.flatMap((annotation, index) => {
|
|
21105
|
+
const calloutCfg = getCalloutCfg(annotation);
|
|
21106
|
+
if (!calloutCfg?.enabled || !calloutCfg?.onlyWhenOverlapping) return [];
|
|
21107
|
+
return [getOriginalLabelRect(chart, area, annotation, index)];
|
|
21108
|
+
});
|
|
21109
|
+
const overlappingIds = /* @__PURE__ */ new Set();
|
|
21110
|
+
rects.forEach((rect, index) => {
|
|
21111
|
+
rects.slice(index + 1).forEach((otherRect) => {
|
|
21112
|
+
if (rect.side !== otherRect.side) return;
|
|
21113
|
+
if (!isRectOverlapping(rect, otherRect)) return;
|
|
21114
|
+
overlappingIds.add(rect.id);
|
|
21115
|
+
overlappingIds.add(otherRect.id);
|
|
21116
|
+
});
|
|
21117
|
+
});
|
|
21118
|
+
return overlappingIds;
|
|
21119
|
+
};
|
|
21120
|
+
var isCalloutOverlapping = (ctx, refAnnotation, index) => {
|
|
21121
|
+
const chart = getChartFromCtx$1(ctx);
|
|
21122
|
+
if (!getCalloutCfg(refAnnotation)?.onlyWhenOverlapping) return true;
|
|
21123
|
+
if (!chart?.chartArea) return false;
|
|
21124
|
+
return getOverlappingCalloutIds(chart).has(`callout-annotation-${index}`);
|
|
21125
|
+
};
|
|
21126
|
+
var getPreferredX = (chart, area, annotation, calloutCfg, width) => {
|
|
21127
|
+
const xScale = getXScale(chart, getAxisId(annotation, "x"));
|
|
21128
|
+
const explicitXValue = typeof calloutCfg?.xValue === "number" ? calloutCfg.xValue : void 0;
|
|
21129
|
+
if (typeof explicitXValue === "number" && xScale) return xScale.getPixelForValue(explicitXValue);
|
|
21130
|
+
const margin = getNumericValue(calloutCfg?.margin, DEFAULT_MARGIN);
|
|
21131
|
+
const halfWidth = width / 2;
|
|
21132
|
+
const reference = getReferencePoint$1(chart, area, annotation);
|
|
21133
|
+
const direction = reference.side === "right" ? 1 : -1;
|
|
21134
|
+
const gap = getNumericValue(calloutCfg?.gapPx, DEFAULT_LABEL_GAP);
|
|
21135
|
+
const minConnectorLength = getNumericValue(calloutCfg?.minConnectorLengthPx, DEFAULT_MIN_CONNECTOR_LENGTH);
|
|
21136
|
+
return clamp$1(reference.x + direction * (halfWidth + gap + minConnectorLength), area.left + margin + halfWidth, area.right - margin - halfWidth);
|
|
21137
|
+
};
|
|
21138
|
+
var getPreferredY = (chart, area, annotation, calloutCfg) => {
|
|
21139
|
+
const yScale = getYScale(chart, getAxisId(annotation, "y"));
|
|
21140
|
+
const explicitYValue = typeof calloutCfg?.yValue === "number" ? calloutCfg.yValue : void 0;
|
|
21141
|
+
if (typeof explicitYValue === "number" && yScale) return yScale.getPixelForValue(explicitYValue);
|
|
21142
|
+
const reference = getReferencePoint$1(chart, area, annotation);
|
|
21143
|
+
const dy = typeof calloutCfg?.yAdjust === "number" ? 0 : DEFAULT_VERTICAL_OFFSET;
|
|
21144
|
+
return reference.y + dy;
|
|
21145
|
+
};
|
|
21146
|
+
var getCalloutItems = (chart, area) => {
|
|
21147
|
+
const overlappingIds = getOverlappingCalloutIds(chart);
|
|
21148
|
+
return ((chart?.options)?.annotations?.annotationsData ?? []).flatMap((annotation, index) => {
|
|
21149
|
+
const calloutCfg = getCalloutCfg(annotation);
|
|
21150
|
+
const id = `callout-annotation-${index}`;
|
|
21151
|
+
if (!calloutCfg?.enabled) return [];
|
|
21152
|
+
const size = estimateLabelSize(chart, annotation, calloutCfg);
|
|
21153
|
+
const xScale = getXScale(chart, getAxisId(annotation, "x"));
|
|
21154
|
+
const yScale = getYScale(chart, getAxisId(annotation, "y"));
|
|
21155
|
+
const reference = getReferencePoint$1(chart, area, annotation);
|
|
21156
|
+
const preferredX = getPreferredX(chart, area, annotation, calloutCfg, size.width);
|
|
21157
|
+
const preferredY = getPreferredY(chart, area, annotation, calloutCfg);
|
|
21158
|
+
const hasStoredX = typeof calloutCfg?.xValue === "number" || !xScale;
|
|
21159
|
+
const hasStoredY = typeof calloutCfg?.yValue === "number" || !yScale;
|
|
21160
|
+
const side = reference.side;
|
|
21161
|
+
const margin = getNumericValue(calloutCfg?.margin, DEFAULT_MARGIN);
|
|
21162
|
+
return [{
|
|
21163
|
+
annotation,
|
|
21164
|
+
calloutCfg,
|
|
21165
|
+
id,
|
|
21166
|
+
index,
|
|
21167
|
+
anchorY: reference.y,
|
|
21168
|
+
preferredX,
|
|
21169
|
+
preferredY,
|
|
21170
|
+
width: size.width,
|
|
21171
|
+
height: size.height,
|
|
21172
|
+
isFixed: hasStoredX && hasStoredY,
|
|
21173
|
+
isOverlapping: overlappingIds.has(id),
|
|
21174
|
+
overlapOnly: Boolean(calloutCfg?.onlyWhenOverlapping),
|
|
21175
|
+
minX: area.left + margin + size.width / 2,
|
|
21176
|
+
maxX: area.right - margin - size.width / 2,
|
|
21177
|
+
minY: area.top + margin + size.height / 2,
|
|
21178
|
+
maxY: area.bottom - margin - size.height / 2,
|
|
21179
|
+
side
|
|
21180
|
+
}];
|
|
21181
|
+
});
|
|
21182
|
+
};
|
|
21183
|
+
var hasVerticalOverlap = (items) => {
|
|
21184
|
+
const sorted = [...items].sort((left, right) => left.preferredY - right.preferredY);
|
|
21185
|
+
for (let index = 1; index < sorted.length; index += 1) {
|
|
21186
|
+
const previous = sorted[index - 1];
|
|
21187
|
+
const current = sorted[index];
|
|
21188
|
+
const gap = previous.height / 2 + current.height / 2 + DEFAULT_ITEM_GAP;
|
|
21189
|
+
if (current.preferredY - previous.preferredY < gap) return true;
|
|
21190
|
+
}
|
|
21191
|
+
return false;
|
|
21192
|
+
};
|
|
21193
|
+
var overlapsOccupiedRect = (centerY, height, occupiedRects) => {
|
|
21194
|
+
const top = centerY - height / 2;
|
|
21195
|
+
const bottom = centerY + height / 2;
|
|
21196
|
+
return occupiedRects.find((rect) => !(bottom <= rect.top || top >= rect.bottom));
|
|
21197
|
+
};
|
|
21198
|
+
var getLayoutGap = (item) => {
|
|
21199
|
+
return item.overlapOnly ? DEFAULT_OVERLAP_ONLY_ITEM_GAP : DEFAULT_ITEM_GAP;
|
|
21200
|
+
};
|
|
21201
|
+
var getLayoutOrderY = (item) => {
|
|
21202
|
+
return item.isFixed ? item.preferredY : item.anchorY;
|
|
21203
|
+
};
|
|
21204
|
+
var intervalsOverlap = (top, bottom, otherTop, otherBottom) => {
|
|
21205
|
+
return !(bottom <= otherTop || top >= otherBottom);
|
|
21206
|
+
};
|
|
21207
|
+
var assignLabelColumns = (items, layout) => {
|
|
21208
|
+
const columns = [];
|
|
21209
|
+
const hasPrimaryColumn = items.some((item) => {
|
|
21210
|
+
return !item.overlapOnly || !item.isOverlapping;
|
|
21211
|
+
});
|
|
21212
|
+
[...items].sort((left, right) => getLayoutOrderY(left) - getLayoutOrderY(right)).forEach((item) => {
|
|
21213
|
+
const current = layout.get(item.id);
|
|
21214
|
+
if (!current) return;
|
|
21215
|
+
const top = current.yValue - item.height / 2 - getLayoutGap(item) / 2;
|
|
21216
|
+
const bottom = current.yValue + item.height / 2 + getLayoutGap(item) / 2;
|
|
21217
|
+
let columnIndex = hasPrimaryColumn && item.overlapOnly && item.isOverlapping ? 1 : 0;
|
|
21218
|
+
while (true) {
|
|
21219
|
+
if (!(columns[columnIndex] ?? []).some((placed) => {
|
|
21220
|
+
return intervalsOverlap(top, bottom, placed.top, placed.bottom);
|
|
21221
|
+
})) {
|
|
21222
|
+
if (!columns[columnIndex]) columns[columnIndex] = [];
|
|
21223
|
+
columns[columnIndex].push({
|
|
21224
|
+
id: item.id,
|
|
21225
|
+
top,
|
|
21226
|
+
bottom,
|
|
21227
|
+
width: item.width
|
|
21228
|
+
});
|
|
21229
|
+
break;
|
|
21230
|
+
}
|
|
21231
|
+
columnIndex += 1;
|
|
21232
|
+
}
|
|
21233
|
+
});
|
|
21234
|
+
return columns;
|
|
21235
|
+
};
|
|
21236
|
+
var applyLaneLayout = (items, layout, occupiedRects) => {
|
|
21237
|
+
if (items.length <= 1) return;
|
|
21238
|
+
const side = items[0]?.side;
|
|
21239
|
+
const columns = assignLabelColumns(items, layout);
|
|
21240
|
+
const getCurrentRect = (item) => {
|
|
21241
|
+
const centerX = layout.get(item.id)?.xValue ?? item.preferredX;
|
|
21242
|
+
return {
|
|
21243
|
+
left: centerX - item.width / 2,
|
|
21244
|
+
right: centerX + item.width / 2
|
|
21245
|
+
};
|
|
21246
|
+
};
|
|
21247
|
+
const referenceItems = items.filter((item) => {
|
|
21248
|
+
return columns[0]?.some((placed) => placed.id === item.id);
|
|
21249
|
+
});
|
|
21250
|
+
const referenceRects = referenceItems.length ? referenceItems : items;
|
|
21251
|
+
const baseEdge = side === "right" ? occupiedRects.length ? Math.min(...occupiedRects.map((rect) => rect.left)) - DEFAULT_LANE_GAP : Math.min(...referenceRects.map((item) => getCurrentRect(item).left)) : occupiedRects.length ? Math.max(...occupiedRects.map((rect) => rect.right)) + DEFAULT_LANE_GAP : Math.max(...referenceRects.map((item) => getCurrentRect(item).right));
|
|
21252
|
+
columns.forEach((column, columnIndex) => {
|
|
21253
|
+
const columnWidth = Math.max(...column.map((placed) => placed.width));
|
|
21254
|
+
column?.forEach((placed) => {
|
|
21255
|
+
const item = items.find((candidate) => candidate.id === placed.id);
|
|
21256
|
+
const current = layout.get(placed.id);
|
|
21257
|
+
if (!item || !current) return;
|
|
21258
|
+
const xValue = side === "right" ? baseEdge - columnIndex * (columnWidth + DEFAULT_LANE_GAP) - item.width / 2 : baseEdge + columnIndex * (columnWidth + DEFAULT_LANE_GAP) + item.width / 2;
|
|
21259
|
+
layout.set(placed.id, {
|
|
21260
|
+
...current,
|
|
21261
|
+
xValue: clamp$1(xValue, item.minX, item.maxX)
|
|
21262
|
+
});
|
|
21263
|
+
});
|
|
21264
|
+
});
|
|
21265
|
+
};
|
|
21266
|
+
var getOrderBounds = (item, occupiedRects) => {
|
|
21267
|
+
const previousRect = [...occupiedRects].filter((rect) => rect.centerY <= item.anchorY).at(-1);
|
|
21268
|
+
const nextRect = occupiedRects.find((rect) => rect.centerY >= item.anchorY);
|
|
21269
|
+
const gap = getLayoutGap(item);
|
|
21270
|
+
return {
|
|
21271
|
+
minCenter: previousRect ? previousRect.bottom + gap + item.height / 2 : item.minY,
|
|
21272
|
+
maxCenter: nextRect ? nextRect.top - gap - item.height / 2 : item.maxY
|
|
21273
|
+
};
|
|
21274
|
+
};
|
|
21275
|
+
var layoutSide = (items, occupiedRects = []) => {
|
|
21276
|
+
const sortedOccupiedRects = [...occupiedRects].sort((left, right) => left.centerY - right.centerY);
|
|
21277
|
+
const sorted = [...items].sort((left, right) => getLayoutOrderY(left) - getLayoutOrderY(right));
|
|
21278
|
+
const result = /* @__PURE__ */ new Map();
|
|
21279
|
+
if (!sorted.filter((item) => !item.isFixed).length) {
|
|
21280
|
+
sorted.forEach((item) => {
|
|
21281
|
+
result.set(item.id, {
|
|
21282
|
+
xValue: item.preferredX,
|
|
21283
|
+
yValue: item.preferredY
|
|
21284
|
+
});
|
|
21285
|
+
});
|
|
21286
|
+
return result;
|
|
21287
|
+
}
|
|
21288
|
+
const shouldReflow = sorted.some((item) => !item.overlapOnly) || hasVerticalOverlap(sorted);
|
|
21289
|
+
sorted.forEach((item) => {
|
|
21290
|
+
result.set(item.id, {
|
|
21291
|
+
xValue: item.preferredX,
|
|
21292
|
+
yValue: clamp$1(item.preferredY, item.minY, item.maxY)
|
|
21293
|
+
});
|
|
21294
|
+
});
|
|
21295
|
+
if (!shouldReflow) return result;
|
|
21296
|
+
let previousBottom = Number.NEGATIVE_INFINITY;
|
|
21297
|
+
sorted.forEach((item) => {
|
|
21298
|
+
if (item.isFixed) {
|
|
21299
|
+
const yValue = clamp$1(item.preferredY, item.minY, item.maxY);
|
|
21300
|
+
result.set(item.id, {
|
|
21301
|
+
xValue: item.preferredX,
|
|
21302
|
+
yValue
|
|
21303
|
+
});
|
|
21304
|
+
previousBottom = yValue + item.height / 2;
|
|
21305
|
+
return;
|
|
21306
|
+
}
|
|
21307
|
+
const orderBounds = getOrderBounds(item, sortedOccupiedRects);
|
|
21308
|
+
const maxCenter = Math.min(item.maxY, orderBounds.maxCenter);
|
|
21309
|
+
const minCenter = Math.max(item.minY, orderBounds.minCenter, previousBottom + item.height / 2 + getLayoutGap(item));
|
|
21310
|
+
let yValue = clampRelaxed(item.preferredY, minCenter, maxCenter);
|
|
21311
|
+
let overlappingRect = overlapsOccupiedRect(yValue, item.height, sortedOccupiedRects);
|
|
21312
|
+
while (overlappingRect) {
|
|
21313
|
+
const nextCandidate = overlappingRect.bottom + getLayoutGap(item) + item.height / 2;
|
|
21314
|
+
if (nextCandidate === yValue) break;
|
|
21315
|
+
yValue = clampRelaxed(nextCandidate, minCenter, maxCenter);
|
|
21316
|
+
overlappingRect = overlapsOccupiedRect(yValue, item.height, sortedOccupiedRects);
|
|
21317
|
+
}
|
|
21318
|
+
result.set(item.id, {
|
|
21319
|
+
xValue: item.preferredX,
|
|
21320
|
+
yValue
|
|
21321
|
+
});
|
|
21322
|
+
previousBottom = yValue + item.height / 2;
|
|
21323
|
+
});
|
|
21324
|
+
let nextTop = Number.POSITIVE_INFINITY;
|
|
21325
|
+
[...sorted].reverse().forEach((item) => {
|
|
21326
|
+
const current = result.get(item.id);
|
|
21327
|
+
if (!current) return;
|
|
21328
|
+
if (item.isFixed) {
|
|
21329
|
+
nextTop = current.yValue - item.height / 2;
|
|
21330
|
+
return;
|
|
21331
|
+
}
|
|
21332
|
+
const orderBounds = getOrderBounds(item, sortedOccupiedRects);
|
|
21333
|
+
const maxCenter = Math.min(item.maxY, orderBounds.maxCenter, nextTop - item.height / 2 - getLayoutGap(item));
|
|
21334
|
+
const minCenter = Math.max(item.minY, orderBounds.minCenter);
|
|
21335
|
+
const yValue = clampRelaxed(current.yValue, minCenter, maxCenter);
|
|
21336
|
+
result.set(item.id, {
|
|
21337
|
+
...current,
|
|
21338
|
+
yValue
|
|
21339
|
+
});
|
|
21340
|
+
nextTop = yValue - item.height / 2;
|
|
21341
|
+
});
|
|
21342
|
+
previousBottom = Number.NEGATIVE_INFINITY;
|
|
21343
|
+
sorted.forEach((item) => {
|
|
21344
|
+
const current = result.get(item.id);
|
|
21345
|
+
if (!current) return;
|
|
21346
|
+
if (item.isFixed) {
|
|
21347
|
+
previousBottom = current.yValue + item.height / 2;
|
|
21348
|
+
return;
|
|
21349
|
+
}
|
|
21350
|
+
const orderBounds = getOrderBounds(item, sortedOccupiedRects);
|
|
21351
|
+
const maxCenter = Math.min(item.maxY, orderBounds.maxCenter);
|
|
21352
|
+
const minCenter = Math.max(item.minY, orderBounds.minCenter, previousBottom + item.height / 2 + getLayoutGap(item));
|
|
21353
|
+
const yValue = clampRelaxed(current.yValue, minCenter, maxCenter);
|
|
21354
|
+
result.set(item.id, {
|
|
21355
|
+
...current,
|
|
21356
|
+
yValue
|
|
21357
|
+
});
|
|
21358
|
+
previousBottom = yValue + item.height / 2;
|
|
21359
|
+
});
|
|
21360
|
+
if (sorted.some((item) => item.overlapOnly)) {
|
|
21361
|
+
const untouchedPrimary = sorted.filter((item) => {
|
|
21362
|
+
return !item.isFixed && item.overlapOnly && !item.isOverlapping;
|
|
21363
|
+
});
|
|
21364
|
+
const secondaryMovable = sorted.filter((item) => {
|
|
21365
|
+
return !item.isFixed && item.overlapOnly && item.isOverlapping;
|
|
21366
|
+
});
|
|
21367
|
+
untouchedPrimary.forEach((item) => {
|
|
21368
|
+
result.set(item.id, {
|
|
21369
|
+
xValue: item.preferredX,
|
|
21370
|
+
yValue: clamp$1(item.preferredY, item.minY, item.maxY)
|
|
21371
|
+
});
|
|
21372
|
+
});
|
|
21373
|
+
if (secondaryMovable.length) applyLaneLayout(secondaryMovable, result, untouchedPrimary.map((item) => {
|
|
21374
|
+
const current = result.get(item.id);
|
|
21375
|
+
const centerX = current?.xValue ?? item.preferredX;
|
|
21376
|
+
const centerY = current?.yValue ?? item.preferredY;
|
|
21377
|
+
return {
|
|
21378
|
+
top: centerY - item.height / 2,
|
|
21379
|
+
bottom: centerY + item.height / 2,
|
|
21380
|
+
centerY,
|
|
21381
|
+
left: centerX - item.width / 2,
|
|
21382
|
+
right: centerX + item.width / 2
|
|
21383
|
+
};
|
|
21384
|
+
}));
|
|
21385
|
+
return result;
|
|
21386
|
+
}
|
|
21387
|
+
applyLaneLayout(sorted.filter((item) => !item.isFixed), result, []);
|
|
21388
|
+
return result;
|
|
21389
|
+
};
|
|
21390
|
+
var getCalloutLayoutPixels = (chart) => {
|
|
21391
|
+
const area = chart?.chartArea;
|
|
21392
|
+
if (!chart || !area) return /* @__PURE__ */ new Map();
|
|
21393
|
+
const grouped = getCalloutItems(chart, area).map((item) => {
|
|
21394
|
+
const xValue = clamp$1(item.preferredX, item.minX, item.maxX);
|
|
21395
|
+
return {
|
|
21396
|
+
...item,
|
|
21397
|
+
preferredX: xValue
|
|
21398
|
+
};
|
|
21399
|
+
}).reduce((accumulator, item) => {
|
|
21400
|
+
accumulator[item.side].push(item);
|
|
21401
|
+
return accumulator;
|
|
21402
|
+
}, {
|
|
21403
|
+
left: [],
|
|
21404
|
+
right: []
|
|
21405
|
+
});
|
|
21406
|
+
const leftLayout = layoutSide(grouped.left, []);
|
|
21407
|
+
const rightLayout = layoutSide(grouped.right, []);
|
|
21408
|
+
return new Map([...leftLayout.entries(), ...rightLayout.entries()]);
|
|
21409
|
+
};
|
|
21410
|
+
var getCalloutLayout = (ctx, refAnnotation, index) => {
|
|
21411
|
+
const chart = getChartFromCtx$1(ctx);
|
|
21412
|
+
const xScale = chart ? getXScale(chart, getAxisId(refAnnotation, "x")) : void 0;
|
|
21413
|
+
const yScale = chart ? getYScale(chart, getAxisId(refAnnotation, "y")) : void 0;
|
|
21414
|
+
if (!chart || !yScale || !chart.chartArea) return null;
|
|
21415
|
+
if (!xScale && hasAxisAnchor(refAnnotation, "x")) return null;
|
|
21416
|
+
if (!xScale) return null;
|
|
21417
|
+
const layout = getCalloutLayoutPixels(chart).get(`callout-annotation-${index}`);
|
|
21418
|
+
if (!layout) return null;
|
|
21419
|
+
return {
|
|
21420
|
+
xValue: xScale.getValueForPixel(layout.xValue),
|
|
21421
|
+
yValue: yScale.getValueForPixel(layout.yValue)
|
|
21422
|
+
};
|
|
21423
|
+
};
|
|
20907
21424
|
var resolveCalloutXValue = (ctx, refAnnotation, calloutCfg, index) => {
|
|
20908
|
-
const
|
|
21425
|
+
const layout = getCalloutLayout(ctx, refAnnotation, index);
|
|
21426
|
+
if (layout) return layout.xValue;
|
|
21427
|
+
const chart = getChartFromCtx$1(ctx);
|
|
20909
21428
|
const xVal = refAnnotation?.xValue;
|
|
20910
21429
|
if (typeof xVal !== "number") return 0;
|
|
20911
21430
|
if (!chart) return xVal;
|
|
20912
|
-
const scale = getXScale(chart, refAnnotation
|
|
21431
|
+
const scale = getXScale(chart, getAxisId(refAnnotation, "x"));
|
|
20913
21432
|
if (!scale) return xVal;
|
|
20914
21433
|
const hasCustomOffset = typeof calloutCfg?.xAdjust === "number";
|
|
20915
21434
|
const side = index % 2 === 0 ? 1 : -1;
|
|
20916
|
-
const dx = hasCustomOffset ? calloutCfg?.xAdjust : side *
|
|
21435
|
+
const dx = hasCustomOffset ? calloutCfg?.xAdjust : side * DEFAULT_HORIZONTAL_OFFSET;
|
|
20917
21436
|
const basePx = scale.getPixelForValue(xVal);
|
|
20918
|
-
const cxBase = basePx + dx;
|
|
20919
21437
|
const area = chart.chartArea;
|
|
20920
|
-
const
|
|
20921
|
-
if (!area || !
|
|
20922
|
-
const margin = calloutCfg?.margin
|
|
20923
|
-
const
|
|
20924
|
-
|
|
20925
|
-
|
|
20926
|
-
if (cx - halfW < area.left + margin) {
|
|
20927
|
-
adjDx += area.left + margin + halfW - cx;
|
|
20928
|
-
cx = basePx + adjDx;
|
|
20929
|
-
} else if (cx + halfW > area.right - margin) {
|
|
20930
|
-
adjDx += area.right - margin - halfW - cx;
|
|
20931
|
-
cx = basePx + adjDx;
|
|
20932
|
-
}
|
|
20933
|
-
return scale.getValueForPixel(cx);
|
|
21438
|
+
const element = ctx?.element;
|
|
21439
|
+
if (!area || !element) return scale.getValueForPixel(basePx + dx);
|
|
21440
|
+
const margin = getNumericValue(calloutCfg?.margin, DEFAULT_MARGIN);
|
|
21441
|
+
const halfWidth = (element?.width ?? 0) / 2;
|
|
21442
|
+
const clampedPx = clamp$1(basePx + dx, area.left + margin + halfWidth, area.right - margin - halfWidth);
|
|
21443
|
+
return scale.getValueForPixel(clampedPx);
|
|
20934
21444
|
};
|
|
20935
21445
|
var resolveCalloutYValue = (ctx, refAnnotation, calloutCfg, index) => {
|
|
20936
|
-
const
|
|
20937
|
-
|
|
21446
|
+
const layout = getCalloutLayout(ctx, refAnnotation, index);
|
|
21447
|
+
if (layout) return layout.yValue;
|
|
21448
|
+
const chart = getChartFromCtx$1(ctx);
|
|
21449
|
+
const yVal = refAnnotation?.yValue;
|
|
20938
21450
|
if (typeof yVal !== "number") return 0;
|
|
20939
21451
|
if (!chart) return yVal;
|
|
20940
|
-
const scale = getYScale(chart, refAnnotation
|
|
21452
|
+
const scale = getYScale(chart, getAxisId(refAnnotation, "y"));
|
|
20941
21453
|
if (!scale) return yVal;
|
|
20942
21454
|
const hasCustomOffset = typeof calloutCfg?.yAdjust === "number";
|
|
20943
21455
|
const row = Math.floor(index / 2);
|
|
20944
|
-
const dy = hasCustomOffset ? calloutCfg?.yAdjust :
|
|
21456
|
+
const dy = hasCustomOffset ? calloutCfg?.yAdjust : DEFAULT_VERTICAL_OFFSET - row * DEFAULT_ROW_GAP;
|
|
20945
21457
|
const basePx = scale.getPixelForValue(yVal);
|
|
20946
|
-
const cyBase = basePx + dy;
|
|
20947
21458
|
const area = chart.chartArea;
|
|
20948
|
-
const
|
|
20949
|
-
if (!area || !
|
|
20950
|
-
const margin = calloutCfg?.margin
|
|
20951
|
-
const
|
|
20952
|
-
|
|
20953
|
-
|
|
20954
|
-
|
|
20955
|
-
|
|
20956
|
-
cy = basePx + adjDy;
|
|
20957
|
-
} else if (cy + halfH > area.bottom - margin) {
|
|
20958
|
-
adjDy += area.bottom - margin - halfH - cy;
|
|
20959
|
-
cy = basePx + adjDy;
|
|
20960
|
-
}
|
|
20961
|
-
return scale.getValueForPixel(cy);
|
|
20962
|
-
};
|
|
20963
|
-
var isInRange = (v, min, max) => v >= min && v <= max;
|
|
21459
|
+
const element = ctx?.element;
|
|
21460
|
+
if (!area || !element) return scale.getValueForPixel(basePx + dy);
|
|
21461
|
+
const margin = getNumericValue(calloutCfg?.margin, DEFAULT_MARGIN);
|
|
21462
|
+
const halfHeight = (element?.height ?? 0) / 2;
|
|
21463
|
+
const clampedPx = clamp$1(basePx + dy, area.top + margin + halfHeight, area.bottom - margin - halfHeight);
|
|
21464
|
+
return scale.getValueForPixel(clampedPx);
|
|
21465
|
+
};
|
|
21466
|
+
var isInRange = (value, min, max) => value >= min && value <= max;
|
|
20964
21467
|
var isCalloutAnchorInChartArea = (ctx, refAnnotation, margin = 0) => {
|
|
20965
|
-
const chart = ctx
|
|
21468
|
+
const chart = getChartFromCtx$1(ctx);
|
|
20966
21469
|
const area = chart?.chartArea;
|
|
20967
21470
|
if (!chart || !area) return true;
|
|
20968
|
-
const xScale = getXScale(chart, refAnnotation
|
|
20969
|
-
const yScale = getYScale(chart, refAnnotation
|
|
20970
|
-
const
|
|
20971
|
-
const
|
|
20972
|
-
if (!xScale || !yScale) return false;
|
|
20973
|
-
if (
|
|
20974
|
-
const x =
|
|
20975
|
-
const y =
|
|
21471
|
+
const xScale = getXScale(chart, getAxisId(refAnnotation, "x"));
|
|
21472
|
+
const yScale = getYScale(chart, getAxisId(refAnnotation, "y"));
|
|
21473
|
+
const hasXValues = hasAxisAnchor(refAnnotation, "x");
|
|
21474
|
+
const hasYValues = hasAxisAnchor(refAnnotation, "y");
|
|
21475
|
+
if (hasXValues && !xScale || hasYValues && !yScale) return false;
|
|
21476
|
+
if (!hasXValues || !hasYValues) return false;
|
|
21477
|
+
const x = getAnchorPixel(chart, refAnnotation, "x", area);
|
|
21478
|
+
const y = getAnchorPixel(chart, refAnnotation, "y", area);
|
|
20976
21479
|
return isInRange(x, area.left + margin, area.right - margin) && isInRange(y, area.top + margin, area.bottom - margin);
|
|
20977
21480
|
};
|
|
20978
21481
|
//#endregion
|
|
@@ -21273,7 +21776,10 @@ var getCalloutAnnotation = (refAnnotation, index) => {
|
|
|
21273
21776
|
const calloutCfg = refAnnotation?.labelConfig?.callout ?? {};
|
|
21274
21777
|
const baseAnnotation = {
|
|
21275
21778
|
...baseRest,
|
|
21276
|
-
label: {
|
|
21779
|
+
label: {
|
|
21780
|
+
...label,
|
|
21781
|
+
display: () => false
|
|
21782
|
+
}
|
|
21277
21783
|
};
|
|
21278
21784
|
const color = calloutCfg?.color ?? "hsl(60, 10.34482759%, 12.5%)";
|
|
21279
21785
|
const font = calloutCfg?.font ?? `12px "Roobert", "Noto Sans", sans-serif`;
|
|
@@ -21281,10 +21787,10 @@ var getCalloutAnnotation = (refAnnotation, index) => {
|
|
|
21281
21787
|
const onCalloutDragStart = typeof calloutCfg?.onDragStart === "function" ? calloutCfg.onDragStart : void 0;
|
|
21282
21788
|
const onCalloutDrag = typeof calloutCfg?.onDrag === "function" ? calloutCfg.onDrag : void 0;
|
|
21283
21789
|
const onCalloutDragEnd = typeof calloutCfg?.onDragEnd === "function" ? calloutCfg.onDragEnd : void 0;
|
|
21284
|
-
const strokeStyle = calloutCfg.strokeStyle ??
|
|
21790
|
+
const strokeStyle = calloutCfg.strokeStyle ?? "rgba(120, 126, 138, 0.9)";
|
|
21285
21791
|
const lineWidth = typeof calloutCfg.lineWidth === "number" ? calloutCfg.lineWidth : 1;
|
|
21286
|
-
const startOffset = typeof calloutCfg.startOffset === "number" ? calloutCfg.startOffset :
|
|
21287
|
-
const endOffset = typeof calloutCfg.endOffset === "number" ? calloutCfg.endOffset :
|
|
21792
|
+
const startOffset = typeof calloutCfg.startOffset === "number" ? calloutCfg.startOffset : 2;
|
|
21793
|
+
const endOffset = typeof calloutCfg.endOffset === "number" ? calloutCfg.endOffset : .5;
|
|
21288
21794
|
const calloutId = `callout-annotation-${index}`;
|
|
21289
21795
|
return [baseAnnotation, {
|
|
21290
21796
|
id: calloutId,
|
|
@@ -21294,14 +21800,18 @@ var getCalloutAnnotation = (refAnnotation, index) => {
|
|
|
21294
21800
|
color: (ctx) => {
|
|
21295
21801
|
const chart = getChartFromCtx(ctx);
|
|
21296
21802
|
if (!chart) return color;
|
|
21297
|
-
if (chart.hoveredAnnotationId === calloutId) return "#DB5B00";
|
|
21803
|
+
if (Boolean(chart?.options?.plugins?.annotationDraggerPlugin?.enabled) && chart.hoveredAnnotationId === calloutId) return "#DB5B00";
|
|
21298
21804
|
return color;
|
|
21299
21805
|
},
|
|
21300
21806
|
font,
|
|
21301
21807
|
borderColor,
|
|
21302
21808
|
borderWidth: BORDER_WIDTH.INITIAL,
|
|
21303
21809
|
padding: 5,
|
|
21304
|
-
display: (ctx) =>
|
|
21810
|
+
display: (ctx) => {
|
|
21811
|
+
if (!(refAnnotation.display ?? true)) return false;
|
|
21812
|
+
if (!isCalloutAnchorInChartArea(ctx, refAnnotation, calloutCfg.margin ?? 0)) return false;
|
|
21813
|
+
return true;
|
|
21814
|
+
},
|
|
21305
21815
|
xValue: (ctx) => {
|
|
21306
21816
|
const persistenceId = getChartFromCtx(ctx)?.options?.persistenceId;
|
|
21307
21817
|
const stored = getAnnotationPosition(persistenceId, `callout-annotation-${index}`);
|
|
@@ -21318,10 +21828,10 @@ var getCalloutAnnotation = (refAnnotation, index) => {
|
|
|
21318
21828
|
displayDragCoordinates: false,
|
|
21319
21829
|
enableDrag: true,
|
|
21320
21830
|
enter: ({ element }, { chart }) => {
|
|
21321
|
-
return handleLabelEnter(element, chart, { enableDrag:
|
|
21831
|
+
return handleLabelEnter(element, chart, { enableDrag: Boolean(chart?.options?.plugins?.annotationDraggerPlugin?.enabled) });
|
|
21322
21832
|
},
|
|
21323
21833
|
leave: ({ element }, { chart }) => {
|
|
21324
|
-
return handleLabelLeave(element, chart, { enableDrag:
|
|
21834
|
+
return handleLabelLeave(element, chart, { enableDrag: Boolean(chart?.options?.plugins?.annotationDraggerPlugin?.enabled) });
|
|
21325
21835
|
},
|
|
21326
21836
|
onDragStart: onCalloutDragStart ? () => (coords) => {
|
|
21327
21837
|
return onCalloutDragStart(coords, refAnnotation);
|
|
@@ -21333,12 +21843,21 @@ var getCalloutAnnotation = (refAnnotation, index) => {
|
|
|
21333
21843
|
return onCalloutDragEnd(coords, refAnnotation);
|
|
21334
21844
|
} : void 0,
|
|
21335
21845
|
calloutConnector: {
|
|
21336
|
-
enabled:
|
|
21846
|
+
enabled: ({ chart }) => {
|
|
21847
|
+
if (!calloutCfg?.onlyWhenOverlapping) return true;
|
|
21848
|
+
return isCalloutOverlapping({ chart }, refAnnotation, index);
|
|
21849
|
+
},
|
|
21337
21850
|
fromId: baseId,
|
|
21338
21851
|
strokeStyle,
|
|
21339
21852
|
lineWidth,
|
|
21340
21853
|
startOffset,
|
|
21341
|
-
endOffset
|
|
21854
|
+
endOffset,
|
|
21855
|
+
anchor: {
|
|
21856
|
+
position: refAnnotation?.labelConfig?.position,
|
|
21857
|
+
xAdjust: refAnnotation?.labelConfig?.xAdjust,
|
|
21858
|
+
yAdjust: refAnnotation?.labelConfig?.yAdjust,
|
|
21859
|
+
labelOffsetPx: refAnnotation?.labelOffsetPx
|
|
21860
|
+
}
|
|
21342
21861
|
}
|
|
21343
21862
|
}];
|
|
21344
21863
|
};
|
|
@@ -22138,52 +22657,126 @@ var annotationDraggerPlugin = {
|
|
|
22138
22657
|
};
|
|
22139
22658
|
//#endregion
|
|
22140
22659
|
//#region src/components/line-chart/plugins/callout-plugin/helpers.ts
|
|
22141
|
-
var
|
|
22142
|
-
|
|
22143
|
-
|
|
22144
|
-
return
|
|
22660
|
+
var getRectangleEdgePoint = (el, targetX, targetY, offset) => {
|
|
22661
|
+
const width = el?.width ?? 0;
|
|
22662
|
+
const height = el?.height ?? 0;
|
|
22663
|
+
if (width <= 0 || height <= 0) return {
|
|
22664
|
+
x: el.centerX,
|
|
22665
|
+
y: el.centerY
|
|
22666
|
+
};
|
|
22667
|
+
const halfWidth = width / 2;
|
|
22668
|
+
const halfHeight = height / 2;
|
|
22669
|
+
const dx = targetX - el.centerX;
|
|
22670
|
+
const dy = targetY - el.centerY;
|
|
22671
|
+
const length = Math.sqrt(dx * dx + dy * dy) || 1;
|
|
22672
|
+
const ux = dx / length;
|
|
22673
|
+
const uy = dy / length;
|
|
22674
|
+
const tx = Math.abs(ux) > 1e-6 ? halfWidth / Math.abs(ux) : Number.POSITIVE_INFINITY;
|
|
22675
|
+
const ty = Math.abs(uy) > 1e-6 ? halfHeight / Math.abs(uy) : Number.POSITIVE_INFINITY;
|
|
22676
|
+
const distance = Math.min(tx, ty) + offset;
|
|
22677
|
+
return {
|
|
22678
|
+
x: el.centerX + ux * distance,
|
|
22679
|
+
y: el.centerY + uy * distance
|
|
22680
|
+
};
|
|
22681
|
+
};
|
|
22682
|
+
var getLabelEdgePoint = (labelEl, startX, endOffset) => {
|
|
22683
|
+
const width = labelEl?.width ?? 0;
|
|
22684
|
+
const height = labelEl?.height ?? 0;
|
|
22685
|
+
if (width <= 0 || height <= 0) return {
|
|
22686
|
+
x: labelEl.centerX,
|
|
22687
|
+
y: labelEl.centerY
|
|
22688
|
+
};
|
|
22689
|
+
const halfWidth = width / 2;
|
|
22690
|
+
const direction = startX <= labelEl.centerX ? -1 : 1;
|
|
22691
|
+
return {
|
|
22692
|
+
x: labelEl.centerX + direction * (halfWidth + endOffset),
|
|
22693
|
+
y: labelEl.centerY
|
|
22694
|
+
};
|
|
22695
|
+
};
|
|
22696
|
+
var getReferencePoint = (fromEl, connector) => {
|
|
22697
|
+
const { anchor } = connector;
|
|
22698
|
+
if (!anchor) return {
|
|
22699
|
+
x: fromEl.centerX,
|
|
22700
|
+
y: fromEl.centerY
|
|
22701
|
+
};
|
|
22702
|
+
const width = fromEl?.width ?? 0;
|
|
22703
|
+
const height = fromEl?.height ?? 0;
|
|
22704
|
+
const radius = fromEl?.options?.radius ?? 0;
|
|
22705
|
+
const halfWidth = width / 2;
|
|
22706
|
+
const halfHeight = height / 2;
|
|
22707
|
+
const labelOffset = anchor?.labelOffsetPx ?? 14;
|
|
22708
|
+
const xAdjust = anchor?.xAdjust ?? 0;
|
|
22709
|
+
const yAdjust = anchor?.yAdjust ?? 0;
|
|
22710
|
+
const position = anchor?.position ?? "top";
|
|
22711
|
+
let x = fromEl.centerX;
|
|
22712
|
+
let y = fromEl.centerY;
|
|
22713
|
+
switch (position) {
|
|
22714
|
+
case "left":
|
|
22715
|
+
x -= Math.max(halfWidth, radius) + labelOffset;
|
|
22716
|
+
break;
|
|
22717
|
+
case "right":
|
|
22718
|
+
x += Math.max(halfWidth, radius) + labelOffset;
|
|
22719
|
+
break;
|
|
22720
|
+
case "bottom":
|
|
22721
|
+
y += Math.max(halfHeight, radius) + labelOffset;
|
|
22722
|
+
break;
|
|
22723
|
+
case "top-left":
|
|
22724
|
+
x -= halfWidth;
|
|
22725
|
+
y -= halfHeight;
|
|
22726
|
+
break;
|
|
22727
|
+
case "top-right":
|
|
22728
|
+
x += halfWidth;
|
|
22729
|
+
y -= halfHeight;
|
|
22730
|
+
break;
|
|
22731
|
+
case "bottom-left":
|
|
22732
|
+
x -= halfWidth;
|
|
22733
|
+
y += halfHeight;
|
|
22734
|
+
break;
|
|
22735
|
+
case "bottom-right":
|
|
22736
|
+
x += halfWidth;
|
|
22737
|
+
y += halfHeight;
|
|
22738
|
+
break;
|
|
22739
|
+
default:
|
|
22740
|
+
y -= Math.max(halfHeight, radius) + labelOffset;
|
|
22741
|
+
break;
|
|
22742
|
+
}
|
|
22743
|
+
return {
|
|
22744
|
+
x: x + xAdjust,
|
|
22745
|
+
y: y + yAdjust
|
|
22746
|
+
};
|
|
22145
22747
|
};
|
|
22146
22748
|
var computeConnectorPoints = (fromEl, labelEl, connector) => {
|
|
22147
22749
|
const x1c = fromEl?.centerX;
|
|
22148
22750
|
const y1c = fromEl?.centerY;
|
|
22149
22751
|
const cx = labelEl?.centerX;
|
|
22150
22752
|
const cy = labelEl?.centerY;
|
|
22151
|
-
const labelWidth = labelEl?.width ?? 0;
|
|
22152
|
-
const labelHeight = labelEl?.height ?? 0;
|
|
22153
22753
|
const ux = cx - x1c;
|
|
22154
22754
|
const uy = cy - y1c;
|
|
22155
22755
|
const len = Math.sqrt(ux * ux + uy * uy) || 1;
|
|
22156
22756
|
const dx = ux / len;
|
|
22157
22757
|
const dy = uy / len;
|
|
22158
|
-
const
|
|
22159
|
-
const
|
|
22160
|
-
const
|
|
22161
|
-
|
|
22162
|
-
|
|
22163
|
-
|
|
22164
|
-
|
|
22165
|
-
|
|
22166
|
-
|
|
22167
|
-
|
|
22168
|
-
|
|
22169
|
-
|
|
22170
|
-
|
|
22171
|
-
const vyn = vy / vlen;
|
|
22172
|
-
const tx = Math.abs(vxn) > 1e-6 ? hw / Math.abs(vxn) : Number.POSITIVE_INFINITY;
|
|
22173
|
-
const ty = Math.abs(vyn) > 1e-6 ? hh / Math.abs(vyn) : Number.POSITIVE_INFINITY;
|
|
22174
|
-
const total = Math.min(tx, ty) + (connector.endOffset ?? 1);
|
|
22175
|
-
endX = cx + vxn * total;
|
|
22176
|
-
endY = cy + vyn * total;
|
|
22177
|
-
} else {
|
|
22178
|
-
const endOffset = connector.endOffset ?? 1;
|
|
22179
|
-
endX = cx - dx * endOffset;
|
|
22180
|
-
endY = cy - dy * endOffset;
|
|
22181
|
-
}
|
|
22758
|
+
const startOffset = connector?.startOffset ?? 6;
|
|
22759
|
+
const isPointAnchor = typeof fromEl?.options?.radius === "number";
|
|
22760
|
+
const referencePoint = connector?.anchor && !isPointAnchor ? getReferencePoint(fromEl, connector) : isPointAnchor ? {
|
|
22761
|
+
x: x1c,
|
|
22762
|
+
y: y1c
|
|
22763
|
+
} : getRectangleEdgePoint(fromEl, cx, cy, startOffset);
|
|
22764
|
+
const endOffset = connector?.endOffset ?? 1;
|
|
22765
|
+
const end = typeof labelEl?.width === "number" && typeof labelEl?.height === "number" ? getLabelEdgePoint(labelEl, referencePoint.x, endOffset) : {
|
|
22766
|
+
x: cx - dx * endOffset,
|
|
22767
|
+
y: cy - dy * endOffset
|
|
22768
|
+
};
|
|
22769
|
+
const tickHalf = isPointAnchor ? 0 : (connector?.anchor?.tickSize ?? 8) / 2;
|
|
22770
|
+
const lineDirection = end.x >= referencePoint.x ? 1 : -1;
|
|
22182
22771
|
return {
|
|
22183
|
-
startX,
|
|
22184
|
-
startY,
|
|
22185
|
-
endX,
|
|
22186
|
-
endY
|
|
22772
|
+
startX: referencePoint.x + lineDirection * tickHalf,
|
|
22773
|
+
startY: referencePoint.y,
|
|
22774
|
+
endX: end.x,
|
|
22775
|
+
endY: end.y,
|
|
22776
|
+
tickStartX: referencePoint.x - tickHalf,
|
|
22777
|
+
tickStartY: referencePoint.y,
|
|
22778
|
+
tickEndX: referencePoint.x + tickHalf,
|
|
22779
|
+
tickEndY: referencePoint.y
|
|
22187
22780
|
};
|
|
22188
22781
|
};
|
|
22189
22782
|
//#endregion
|
|
@@ -22201,22 +22794,35 @@ var calloutConnectorPlugin = {
|
|
|
22201
22794
|
if (!raw) return;
|
|
22202
22795
|
(Array.isArray(raw) ? raw : Object.values(raw)).forEach((opt) => {
|
|
22203
22796
|
const connector = opt?.calloutConnector;
|
|
22204
|
-
if (!connector || !
|
|
22797
|
+
if (!connector || !opt?.id) return;
|
|
22205
22798
|
const labelEl = elements.find((el) => el.options && el.options.id === opt.id);
|
|
22206
22799
|
const fromEl = elements.find((el) => el.options && el.options.id === connector.fromId);
|
|
22207
22800
|
if (!labelEl || !fromEl) return;
|
|
22208
22801
|
if (labelEl.options?.display === false) return;
|
|
22209
|
-
|
|
22802
|
+
if (!(typeof connector.enabled === "function" ? connector.enabled({
|
|
22803
|
+
chart,
|
|
22804
|
+
labelEl,
|
|
22805
|
+
fromEl,
|
|
22806
|
+
option: opt
|
|
22807
|
+
}) : connector.enabled !== false)) return;
|
|
22808
|
+
const { startX, startY, endX, endY, tickStartX, tickStartY, tickEndX, tickEndY } = computeConnectorPoints(fromEl, labelEl, connector) ?? {};
|
|
22210
22809
|
const ctx = chart?.ctx;
|
|
22810
|
+
const strokeStyle = connector?.strokeStyle ?? "rgba(120, 126, 138, 0.9)";
|
|
22211
22811
|
ctx?.save?.();
|
|
22212
22812
|
ctx?.beginPath?.();
|
|
22213
22813
|
ctx?.moveTo?.(startX, startY);
|
|
22214
22814
|
ctx?.lineTo?.(endX, endY);
|
|
22215
22815
|
ctx.lineWidth = connector?.lineWidth ?? 1;
|
|
22216
|
-
ctx.strokeStyle =
|
|
22816
|
+
ctx.strokeStyle = strokeStyle;
|
|
22217
22817
|
if (connector?.lineDash && connector?.lineDash?.length) ctx?.setLineDash?.(connector.lineDash);
|
|
22218
22818
|
ctx.lineCap = "round";
|
|
22219
22819
|
ctx?.stroke?.();
|
|
22820
|
+
ctx?.beginPath?.();
|
|
22821
|
+
ctx?.moveTo?.(tickStartX, tickStartY);
|
|
22822
|
+
ctx?.lineTo?.(tickEndX, tickEndY);
|
|
22823
|
+
ctx.lineWidth = Math.max(connector?.lineWidth ?? 1, 1);
|
|
22824
|
+
ctx.strokeStyle = strokeStyle;
|
|
22825
|
+
ctx?.stroke?.();
|
|
22220
22826
|
ctx?.restore?.();
|
|
22221
22827
|
});
|
|
22222
22828
|
}
|
|
@@ -38649,7 +39255,7 @@ var getGroupedColorScheme = (length, startingColor) => {
|
|
|
38649
39255
|
});
|
|
38650
39256
|
};
|
|
38651
39257
|
//#endregion
|
|
38652
|
-
export { AlignOptions, AnnotationType, AxisType, BarChartWithLegend as BarChart, COLORS, ChartDirection, ChartHoverMode, ChartType, CursorStyle, DragAxis, AnnotationType$1 as DraggableAnnotationType, Events, GradientDirection, Key, LineChartWithLegend as LineChart, PanZoomMode, PieChartWithLegend as PieChart, PointStyle, PointType, Position, ScaleType, ScatterChartWithLegend as ScatterChart, TooltipLabel, getGroupedColorScheme, initializeLineChart };
|
|
39258
|
+
export { AlignOptions, AnnotationType, AxisType, BarChartWithLegend as BarChart, COLORS, ChartDirection, ChartHoverMode, ChartType, CursorStyle, DragAxis, AnnotationType$1 as DraggableAnnotationType, Events, GradientDirection, Key, LineChartWithLegend as LineChart, LineMarkerDirection, LineMarkerLabelPosition, LineMarkerSide, LineMarkerTextAlign, PanZoomMode, PieChartWithLegend as PieChart, PointStyle, PointType, Position, ScaleType, ScatterChartWithLegend as ScatterChart, TooltipLabel, getGroupedColorScheme, initializeLineChart };
|
|
38653
39259
|
(function() {
|
|
38654
39260
|
//#region \0vite/all-css
|
|
38655
39261
|
try {
|
package/package.json
CHANGED