@oliasoft-open-source/charts-library 5.9.1 → 5.10.0-beta-2
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 +625 -103
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1171,15 +1171,15 @@ declare module 'chart.js' {
|
|
|
1171
1171
|
|
|
1172
1172
|
declare module 'chart.js' {
|
|
1173
1173
|
interface PluginOptionsByType<TType extends ChartType> {
|
|
1174
|
-
|
|
1174
|
+
calloutConnectorPlugin?: {
|
|
1175
|
+
enableCalloutAnnotation?: boolean;
|
|
1176
|
+
};
|
|
1175
1177
|
}
|
|
1176
1178
|
}
|
|
1177
1179
|
|
|
1178
1180
|
|
|
1179
1181
|
declare module 'chart.js' {
|
|
1180
1182
|
interface PluginOptionsByType<TType extends ChartType> {
|
|
1181
|
-
|
|
1182
|
-
enableCalloutAnnotation?: boolean;
|
|
1183
|
-
};
|
|
1183
|
+
annotationDraggerPlugin?: AnnotationDraggerPluginOptions;
|
|
1184
1184
|
}
|
|
1185
1185
|
}
|
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;
|
|
@@ -20879,87 +20879,511 @@ function addTransparency(input, alpha, out = "rgb") {
|
|
|
20879
20879
|
}
|
|
20880
20880
|
//#endregion
|
|
20881
20881
|
//#region src/components/common/helpers/callout-helpers/callout-helpers.ts
|
|
20882
|
+
var DEFAULT_FONT_SIZE = 12;
|
|
20883
|
+
var DEFAULT_PADDING = 5;
|
|
20884
|
+
var DEFAULT_MARGIN = 8;
|
|
20885
|
+
var DEFAULT_LABEL_GAP = 8;
|
|
20886
|
+
var DEFAULT_MIN_CONNECTOR_LENGTH = 14;
|
|
20887
|
+
var DEFAULT_HORIZONTAL_OFFSET = 18;
|
|
20888
|
+
var DEFAULT_VERTICAL_OFFSET = -18;
|
|
20889
|
+
var DEFAULT_ROW_GAP = 22;
|
|
20890
|
+
var DEFAULT_ITEM_GAP = 8;
|
|
20891
|
+
var DEFAULT_OVERLAP_ONLY_ITEM_GAP = 14;
|
|
20892
|
+
var DEFAULT_SIDE_SPREAD_STEP = 12;
|
|
20893
|
+
var DEFAULT_SIDE_SPREAD_MAX = 48;
|
|
20894
|
+
var clamp$1 = (value, min, max) => {
|
|
20895
|
+
if (Number.isNaN(value)) return min;
|
|
20896
|
+
if (min > max) return min;
|
|
20897
|
+
return Math.min(Math.max(value, min), max);
|
|
20898
|
+
};
|
|
20899
|
+
var getNumericValue = (value, fallback = 0) => {
|
|
20900
|
+
return typeof value === "number" ? value : fallback;
|
|
20901
|
+
};
|
|
20902
|
+
var getCalloutCfg = (annotation) => {
|
|
20903
|
+
return annotation?.labelConfig?.callout ?? {};
|
|
20904
|
+
};
|
|
20905
|
+
var getChartFromCtx$1 = (ctx) => {
|
|
20906
|
+
return ctx?.chart?.chart ?? ctx?.chart;
|
|
20907
|
+
};
|
|
20882
20908
|
var getXScale = (chart, axisId) => {
|
|
20883
20909
|
if (axisId && chart?.scales?.[axisId]) return chart.scales[axisId];
|
|
20884
20910
|
if (chart?.scales?.x) return chart.scales.x;
|
|
20885
|
-
const key = Object.keys(chart?.scales ?? {})?.find((
|
|
20911
|
+
const key = Object.keys(chart?.scales ?? {})?.find((item) => {
|
|
20912
|
+
return item?.toLowerCase()?.includes("x");
|
|
20913
|
+
});
|
|
20886
20914
|
return key ? chart?.scales?.[key] : void 0;
|
|
20887
20915
|
};
|
|
20888
20916
|
var getYScale = (chart, axisId) => {
|
|
20889
20917
|
if (axisId && chart?.scales?.[axisId]) return chart.scales[axisId];
|
|
20890
20918
|
if (chart?.scales?.y) return chart.scales.y;
|
|
20891
|
-
const key = Object.keys(chart?.scales ?? {})?.find((
|
|
20919
|
+
const key = Object.keys(chart?.scales ?? {})?.find((item) => {
|
|
20920
|
+
return item?.toLowerCase()?.includes("y");
|
|
20921
|
+
});
|
|
20892
20922
|
return key ? chart?.scales?.[key] : void 0;
|
|
20893
20923
|
};
|
|
20924
|
+
var resolveFontSize = (font) => {
|
|
20925
|
+
if (typeof font === "string") {
|
|
20926
|
+
const match = font.match(/(\d+(?:\.\d+)?)px/);
|
|
20927
|
+
return match ? Number(match[1]) : DEFAULT_FONT_SIZE;
|
|
20928
|
+
}
|
|
20929
|
+
if (font && typeof font === "object" && "size" in font) {
|
|
20930
|
+
const size = Number(font.size);
|
|
20931
|
+
return Number.isFinite(size) ? size : DEFAULT_FONT_SIZE;
|
|
20932
|
+
}
|
|
20933
|
+
return DEFAULT_FONT_SIZE;
|
|
20934
|
+
};
|
|
20935
|
+
var resolvePadding = (padding) => {
|
|
20936
|
+
if (typeof padding === "number") return {
|
|
20937
|
+
top: padding,
|
|
20938
|
+
right: padding,
|
|
20939
|
+
bottom: padding,
|
|
20940
|
+
left: padding
|
|
20941
|
+
};
|
|
20942
|
+
if (padding && typeof padding === "object") {
|
|
20943
|
+
const typedPadding = padding;
|
|
20944
|
+
return {
|
|
20945
|
+
top: Number(typedPadding.top ?? DEFAULT_PADDING),
|
|
20946
|
+
right: Number(typedPadding.right ?? DEFAULT_PADDING),
|
|
20947
|
+
bottom: Number(typedPadding.bottom ?? DEFAULT_PADDING),
|
|
20948
|
+
left: Number(typedPadding.left ?? DEFAULT_PADDING)
|
|
20949
|
+
};
|
|
20950
|
+
}
|
|
20951
|
+
return {
|
|
20952
|
+
top: DEFAULT_PADDING,
|
|
20953
|
+
right: DEFAULT_PADDING,
|
|
20954
|
+
bottom: DEFAULT_PADDING,
|
|
20955
|
+
left: DEFAULT_PADDING
|
|
20956
|
+
};
|
|
20957
|
+
};
|
|
20958
|
+
var estimateLabelSize = (chart, annotation, calloutCfg) => {
|
|
20959
|
+
const content = `${annotation?.label ?? ""}`;
|
|
20960
|
+
const fontSize = resolveFontSize(calloutCfg?.font);
|
|
20961
|
+
const padding = resolvePadding(calloutCfg?.padding);
|
|
20962
|
+
const lines = content.split("\n");
|
|
20963
|
+
const fallbackWidth = Math.max(...lines.map((line) => line.length), 0) * fontSize * .62;
|
|
20964
|
+
let measuredWidth = fallbackWidth;
|
|
20965
|
+
if (chart?.ctx) {
|
|
20966
|
+
chart.ctx.save();
|
|
20967
|
+
chart.ctx.font = typeof calloutCfg?.font === "string" ? calloutCfg.font : `${fontSize}px sans-serif`;
|
|
20968
|
+
measuredWidth = Math.max(...lines.map((line) => chart.ctx.measureText(line).width), fallbackWidth);
|
|
20969
|
+
chart.ctx.restore();
|
|
20970
|
+
}
|
|
20971
|
+
return {
|
|
20972
|
+
width: measuredWidth + padding.left + padding.right,
|
|
20973
|
+
height: lines.length * fontSize + padding.top + padding.bottom
|
|
20974
|
+
};
|
|
20975
|
+
};
|
|
20976
|
+
var getAxisId = (annotation, axis) => {
|
|
20977
|
+
const axisScaleId = axis === "x" ? annotation?.xScaleID : annotation?.yScaleID;
|
|
20978
|
+
if (axisScaleId) return axisScaleId;
|
|
20979
|
+
if (annotation?.annotationAxis?.startsWith(axis)) return annotation.annotationAxis;
|
|
20980
|
+
};
|
|
20981
|
+
var getAnchorPixel = (chart, annotation, axis, area) => {
|
|
20982
|
+
const scale = axis === "x" ? getXScale(chart, getAxisId(annotation, "x")) : getYScale(chart, getAxisId(annotation, "y"));
|
|
20983
|
+
const directValue = axis === "x" ? annotation?.xValue : annotation?.yValue;
|
|
20984
|
+
if (typeof directValue === "number" && scale) return scale.getPixelForValue(directValue);
|
|
20985
|
+
const minKey = axis === "x" ? "xMin" : "yMin";
|
|
20986
|
+
const maxKey = axis === "x" ? "xMax" : "yMax";
|
|
20987
|
+
const minValue = annotation?.[minKey];
|
|
20988
|
+
const maxValue = annotation?.[maxKey];
|
|
20989
|
+
if (typeof minValue === "number" && typeof maxValue === "number" && scale) return (scale.getPixelForValue(minValue) + scale.getPixelForValue(maxValue)) / 2;
|
|
20990
|
+
if (typeof minValue === "number" && scale) return scale.getPixelForValue(minValue);
|
|
20991
|
+
if (typeof maxValue === "number" && scale) return scale.getPixelForValue(maxValue);
|
|
20992
|
+
return axis === "x" ? (area.left + area.right) / 2 : (area.top + area.bottom) / 2;
|
|
20993
|
+
};
|
|
20994
|
+
var hasAxisAnchor = (annotation, axis) => {
|
|
20995
|
+
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";
|
|
20996
|
+
return typeof annotation?.yValue === "number" || typeof annotation?.yMin === "number" || typeof annotation?.yMax === "number" || annotation?.type === "box" || annotation?.type === "label" || annotation?.type === "ellipse";
|
|
20997
|
+
};
|
|
20998
|
+
var getBoxHalfWidth = (chart, area, annotation) => {
|
|
20999
|
+
const xScale = getXScale(chart, getAxisId(annotation, "x"));
|
|
21000
|
+
if (xScale && typeof annotation?.xMin === "number" && typeof annotation?.xMax === "number") return Math.abs(xScale.getPixelForValue(annotation.xMax) - xScale.getPixelForValue(annotation.xMin)) / 2;
|
|
21001
|
+
if (annotation?.type === "box") return (area.right - area.left) / 2;
|
|
21002
|
+
return annotation?.radius ?? 0;
|
|
21003
|
+
};
|
|
21004
|
+
var getBoxHalfHeight = (chart, annotation) => {
|
|
21005
|
+
const yScale = getYScale(chart, getAxisId(annotation, "y"));
|
|
21006
|
+
if (yScale && typeof annotation?.yMin === "number" && typeof annotation?.yMax === "number") return Math.abs(yScale.getPixelForValue(annotation.yMax) - yScale.getPixelForValue(annotation.yMin)) / 2;
|
|
21007
|
+
return annotation?.radius ?? 0;
|
|
21008
|
+
};
|
|
21009
|
+
var getReferencePoint$1 = (chart, area, annotation) => {
|
|
21010
|
+
const anchorX = getAnchorPixel(chart, annotation, "x", area);
|
|
21011
|
+
const anchorY = getAnchorPixel(chart, annotation, "y", area);
|
|
21012
|
+
const halfWidth = getBoxHalfWidth(chart, area, annotation);
|
|
21013
|
+
const halfHeight = getBoxHalfHeight(chart, annotation);
|
|
21014
|
+
const labelOffsetPx = getNumericValue(annotation?.labelOffsetPx, 14);
|
|
21015
|
+
const xAdjust = getNumericValue(annotation?.labelConfig?.xAdjust, 0);
|
|
21016
|
+
const yAdjust = getNumericValue(annotation?.labelConfig?.yAdjust, 0);
|
|
21017
|
+
const position = annotation?.labelConfig?.position;
|
|
21018
|
+
let x = anchorX;
|
|
21019
|
+
let y = anchorY;
|
|
21020
|
+
let side = anchorX >= (area.left + area.right) / 2 ? "right" : "left";
|
|
21021
|
+
switch (position) {
|
|
21022
|
+
case Position.Left:
|
|
21023
|
+
x -= Math.max(halfWidth, annotation?.radius ?? 0) + labelOffsetPx;
|
|
21024
|
+
side = "left";
|
|
21025
|
+
break;
|
|
21026
|
+
case Position.Right:
|
|
21027
|
+
x += Math.max(halfWidth, annotation?.radius ?? 0) + labelOffsetPx;
|
|
21028
|
+
side = "right";
|
|
21029
|
+
break;
|
|
21030
|
+
case Position.TopLeft:
|
|
21031
|
+
x -= halfWidth;
|
|
21032
|
+
y -= halfHeight;
|
|
21033
|
+
side = "left";
|
|
21034
|
+
break;
|
|
21035
|
+
case Position.TopRight:
|
|
21036
|
+
x += halfWidth;
|
|
21037
|
+
y -= halfHeight;
|
|
21038
|
+
side = "right";
|
|
21039
|
+
break;
|
|
21040
|
+
case Position.BottomLeft:
|
|
21041
|
+
x -= halfWidth;
|
|
21042
|
+
y += halfHeight;
|
|
21043
|
+
side = "left";
|
|
21044
|
+
break;
|
|
21045
|
+
case Position.BottomRight:
|
|
21046
|
+
x += halfWidth;
|
|
21047
|
+
y += halfHeight;
|
|
21048
|
+
side = "right";
|
|
21049
|
+
break;
|
|
21050
|
+
case Position.Bottom:
|
|
21051
|
+
y += Math.max(halfHeight, annotation?.radius ?? 0) + labelOffsetPx;
|
|
21052
|
+
break;
|
|
21053
|
+
case Position.Top:
|
|
21054
|
+
default:
|
|
21055
|
+
y -= Math.max(halfHeight, annotation?.radius ?? 0) + labelOffsetPx;
|
|
21056
|
+
break;
|
|
21057
|
+
}
|
|
21058
|
+
return {
|
|
21059
|
+
x: x + xAdjust,
|
|
21060
|
+
y: y + yAdjust,
|
|
21061
|
+
side
|
|
21062
|
+
};
|
|
21063
|
+
};
|
|
21064
|
+
var getOriginalLabelRect = (chart, area, annotation, index) => {
|
|
21065
|
+
const size = estimateLabelSize(chart, annotation, getCalloutCfg(annotation));
|
|
21066
|
+
const reference = getReferencePoint$1(chart, area, annotation);
|
|
21067
|
+
const direction = reference.side === "right" ? 1 : -1;
|
|
21068
|
+
const centerX = reference.x + direction * (size.width / 2);
|
|
21069
|
+
const centerY = reference.y;
|
|
21070
|
+
return {
|
|
21071
|
+
id: `callout-annotation-${index}`,
|
|
21072
|
+
side: reference.side,
|
|
21073
|
+
left: centerX - size.width / 2,
|
|
21074
|
+
right: centerX + size.width / 2,
|
|
21075
|
+
top: centerY - size.height / 2,
|
|
21076
|
+
bottom: centerY + size.height / 2
|
|
21077
|
+
};
|
|
21078
|
+
};
|
|
21079
|
+
var isRectOverlapping = (left, right) => {
|
|
21080
|
+
return !(left.right <= right.left || right.right <= left.left || left.bottom <= right.top || right.bottom <= left.top);
|
|
21081
|
+
};
|
|
21082
|
+
var getOverlappingCalloutIds = (chart) => {
|
|
21083
|
+
const area = chart?.chartArea;
|
|
21084
|
+
const annotationsData = (chart?.options)?.annotations?.annotationsData ?? [];
|
|
21085
|
+
if (!chart || !area) return /* @__PURE__ */ new Set();
|
|
21086
|
+
const rects = annotationsData.flatMap((annotation, index) => {
|
|
21087
|
+
const calloutCfg = getCalloutCfg(annotation);
|
|
21088
|
+
if (!calloutCfg?.enabled || !calloutCfg?.onlyWhenOverlapping) return [];
|
|
21089
|
+
return [getOriginalLabelRect(chart, area, annotation, index)];
|
|
21090
|
+
});
|
|
21091
|
+
const overlappingIds = /* @__PURE__ */ new Set();
|
|
21092
|
+
rects.forEach((rect, index) => {
|
|
21093
|
+
rects.slice(index + 1).forEach((otherRect) => {
|
|
21094
|
+
if (rect.side !== otherRect.side) return;
|
|
21095
|
+
if (!isRectOverlapping(rect, otherRect)) return;
|
|
21096
|
+
overlappingIds.add(rect.id);
|
|
21097
|
+
overlappingIds.add(otherRect.id);
|
|
21098
|
+
});
|
|
21099
|
+
});
|
|
21100
|
+
return overlappingIds;
|
|
21101
|
+
};
|
|
21102
|
+
var getOccupiedOriginalLabelRects = (chart, area, overlappingIds) => {
|
|
21103
|
+
return ((chart?.options)?.annotations?.annotationsData ?? []).flatMap((annotation, index) => {
|
|
21104
|
+
const calloutCfg = getCalloutCfg(annotation);
|
|
21105
|
+
const id = `callout-annotation-${index}`;
|
|
21106
|
+
if (!calloutCfg?.enabled || !calloutCfg?.onlyWhenOverlapping) return [];
|
|
21107
|
+
if (overlappingIds.has(id)) return [];
|
|
21108
|
+
return [getOriginalLabelRect(chart, area, annotation, index)];
|
|
21109
|
+
});
|
|
21110
|
+
};
|
|
21111
|
+
var isCalloutOverlapping = (ctx, refAnnotation, index) => {
|
|
21112
|
+
const chart = getChartFromCtx$1(ctx);
|
|
21113
|
+
if (!getCalloutCfg(refAnnotation)?.onlyWhenOverlapping) return true;
|
|
21114
|
+
if (!chart?.chartArea) return false;
|
|
21115
|
+
return getOverlappingCalloutIds(chart).has(`callout-annotation-${index}`);
|
|
21116
|
+
};
|
|
21117
|
+
var getPreferredX = (chart, area, annotation, calloutCfg, width) => {
|
|
21118
|
+
const xScale = getXScale(chart, getAxisId(annotation, "x"));
|
|
21119
|
+
const explicitXValue = typeof calloutCfg?.xValue === "number" ? calloutCfg.xValue : void 0;
|
|
21120
|
+
if (typeof explicitXValue === "number" && xScale) return xScale.getPixelForValue(explicitXValue);
|
|
21121
|
+
const margin = getNumericValue(calloutCfg?.margin, DEFAULT_MARGIN);
|
|
21122
|
+
const halfWidth = width / 2;
|
|
21123
|
+
const reference = getReferencePoint$1(chart, area, annotation);
|
|
21124
|
+
const direction = reference.side === "right" ? 1 : -1;
|
|
21125
|
+
const gap = getNumericValue(calloutCfg?.gapPx, DEFAULT_LABEL_GAP);
|
|
21126
|
+
const minConnectorLength = getNumericValue(calloutCfg?.minConnectorLengthPx, DEFAULT_MIN_CONNECTOR_LENGTH);
|
|
21127
|
+
return clamp$1(reference.x + direction * (halfWidth + gap + minConnectorLength), area.left + margin + halfWidth, area.right - margin - halfWidth);
|
|
21128
|
+
};
|
|
21129
|
+
var getPreferredY = (chart, area, annotation, calloutCfg) => {
|
|
21130
|
+
const yScale = getYScale(chart, getAxisId(annotation, "y"));
|
|
21131
|
+
const explicitYValue = typeof calloutCfg?.yValue === "number" ? calloutCfg.yValue : void 0;
|
|
21132
|
+
if (typeof explicitYValue === "number" && yScale) return yScale.getPixelForValue(explicitYValue);
|
|
21133
|
+
const reference = getReferencePoint$1(chart, area, annotation);
|
|
21134
|
+
const dy = typeof calloutCfg?.yAdjust === "number" ? 0 : DEFAULT_VERTICAL_OFFSET;
|
|
21135
|
+
return reference.y + dy;
|
|
21136
|
+
};
|
|
21137
|
+
var getCalloutItems = (chart, area) => {
|
|
21138
|
+
const overlappingIds = getOverlappingCalloutIds(chart);
|
|
21139
|
+
return ((chart?.options)?.annotations?.annotationsData ?? []).flatMap((annotation, index) => {
|
|
21140
|
+
const calloutCfg = getCalloutCfg(annotation);
|
|
21141
|
+
const id = `callout-annotation-${index}`;
|
|
21142
|
+
if (!calloutCfg?.enabled) return [];
|
|
21143
|
+
if (calloutCfg?.onlyWhenOverlapping && !overlappingIds.has(id)) return [];
|
|
21144
|
+
const size = estimateLabelSize(chart, annotation, calloutCfg);
|
|
21145
|
+
const xScale = getXScale(chart, getAxisId(annotation, "x"));
|
|
21146
|
+
const yScale = getYScale(chart, getAxisId(annotation, "y"));
|
|
21147
|
+
const reference = getReferencePoint$1(chart, area, annotation);
|
|
21148
|
+
const preferredX = getPreferredX(chart, area, annotation, calloutCfg, size.width);
|
|
21149
|
+
const preferredY = getPreferredY(chart, area, annotation, calloutCfg);
|
|
21150
|
+
const hasStoredX = typeof calloutCfg?.xValue === "number" || !xScale;
|
|
21151
|
+
const hasStoredY = typeof calloutCfg?.yValue === "number" || !yScale;
|
|
21152
|
+
const side = reference.side;
|
|
21153
|
+
const margin = getNumericValue(calloutCfg?.margin, DEFAULT_MARGIN);
|
|
21154
|
+
return [{
|
|
21155
|
+
annotation,
|
|
21156
|
+
calloutCfg,
|
|
21157
|
+
id,
|
|
21158
|
+
index,
|
|
21159
|
+
anchorY: reference.y,
|
|
21160
|
+
preferredX,
|
|
21161
|
+
preferredY,
|
|
21162
|
+
width: size.width,
|
|
21163
|
+
height: size.height,
|
|
21164
|
+
isFixed: hasStoredX && hasStoredY,
|
|
21165
|
+
overlapOnly: Boolean(calloutCfg?.onlyWhenOverlapping),
|
|
21166
|
+
minX: area.left + margin + size.width / 2,
|
|
21167
|
+
maxX: area.right - margin - size.width / 2,
|
|
21168
|
+
minY: area.top + margin + size.height / 2,
|
|
21169
|
+
maxY: area.bottom - margin - size.height / 2,
|
|
21170
|
+
side
|
|
21171
|
+
}];
|
|
21172
|
+
});
|
|
21173
|
+
};
|
|
21174
|
+
var hasVerticalOverlap = (items) => {
|
|
21175
|
+
const sorted = [...items].sort((left, right) => left.preferredY - right.preferredY);
|
|
21176
|
+
for (let index = 1; index < sorted.length; index += 1) {
|
|
21177
|
+
const previous = sorted[index - 1];
|
|
21178
|
+
const current = sorted[index];
|
|
21179
|
+
const gap = previous.height / 2 + current.height / 2 + DEFAULT_ITEM_GAP;
|
|
21180
|
+
if (current.preferredY - previous.preferredY < gap) return true;
|
|
21181
|
+
}
|
|
21182
|
+
return false;
|
|
21183
|
+
};
|
|
21184
|
+
var overlapsOccupiedRect = (centerY, height, occupiedRects) => {
|
|
21185
|
+
const top = centerY - height / 2;
|
|
21186
|
+
const bottom = centerY + height / 2;
|
|
21187
|
+
return occupiedRects.find((rect) => !(bottom <= rect.top || top >= rect.bottom));
|
|
21188
|
+
};
|
|
21189
|
+
var getLayoutGap = (item) => {
|
|
21190
|
+
return item.overlapOnly ? DEFAULT_OVERLAP_ONLY_ITEM_GAP : DEFAULT_ITEM_GAP;
|
|
21191
|
+
};
|
|
21192
|
+
var getLayoutOrderY = (item) => {
|
|
21193
|
+
return item.isFixed ? item.preferredY : item.anchorY;
|
|
21194
|
+
};
|
|
21195
|
+
var layoutSide = (items, occupiedRects = []) => {
|
|
21196
|
+
const sorted = [...items].sort((left, right) => getLayoutOrderY(left) - getLayoutOrderY(right));
|
|
21197
|
+
const result = /* @__PURE__ */ new Map();
|
|
21198
|
+
if (!sorted.filter((item) => !item.isFixed).length) {
|
|
21199
|
+
sorted.forEach((item) => {
|
|
21200
|
+
result.set(item.id, {
|
|
21201
|
+
xValue: item.preferredX,
|
|
21202
|
+
yValue: item.preferredY
|
|
21203
|
+
});
|
|
21204
|
+
});
|
|
21205
|
+
return result;
|
|
21206
|
+
}
|
|
21207
|
+
const shouldReflow = sorted.some((item) => !item.overlapOnly) || hasVerticalOverlap(sorted);
|
|
21208
|
+
sorted.forEach((item) => {
|
|
21209
|
+
result.set(item.id, {
|
|
21210
|
+
xValue: item.preferredX,
|
|
21211
|
+
yValue: clamp$1(item.preferredY, item.minY, item.maxY)
|
|
21212
|
+
});
|
|
21213
|
+
});
|
|
21214
|
+
if (!shouldReflow) return result;
|
|
21215
|
+
let previousBottom = Number.NEGATIVE_INFINITY;
|
|
21216
|
+
sorted.forEach((item) => {
|
|
21217
|
+
if (item.isFixed) {
|
|
21218
|
+
const yValue = clamp$1(item.preferredY, item.minY, item.maxY);
|
|
21219
|
+
result.set(item.id, {
|
|
21220
|
+
xValue: item.preferredX,
|
|
21221
|
+
yValue
|
|
21222
|
+
});
|
|
21223
|
+
previousBottom = yValue + item.height / 2;
|
|
21224
|
+
return;
|
|
21225
|
+
}
|
|
21226
|
+
const minCenter = Math.max(item.minY, previousBottom + item.height / 2 + getLayoutGap(item));
|
|
21227
|
+
let yValue = clamp$1(item.preferredY, minCenter, item.maxY);
|
|
21228
|
+
let overlappingRect = overlapsOccupiedRect(yValue, item.height, occupiedRects);
|
|
21229
|
+
while (overlappingRect) {
|
|
21230
|
+
yValue = clamp$1(overlappingRect.bottom + getLayoutGap(item) + item.height / 2, item.minY, item.maxY);
|
|
21231
|
+
overlappingRect = overlapsOccupiedRect(yValue, item.height, occupiedRects);
|
|
21232
|
+
}
|
|
21233
|
+
result.set(item.id, {
|
|
21234
|
+
xValue: item.preferredX,
|
|
21235
|
+
yValue
|
|
21236
|
+
});
|
|
21237
|
+
previousBottom = yValue + item.height / 2;
|
|
21238
|
+
});
|
|
21239
|
+
let nextTop = Number.POSITIVE_INFINITY;
|
|
21240
|
+
[...sorted].reverse().forEach((item) => {
|
|
21241
|
+
const current = result.get(item.id);
|
|
21242
|
+
if (!current) return;
|
|
21243
|
+
if (item.isFixed) {
|
|
21244
|
+
nextTop = current.yValue - item.height / 2;
|
|
21245
|
+
return;
|
|
21246
|
+
}
|
|
21247
|
+
const maxCenter = Math.min(item.maxY, nextTop - item.height / 2 - getLayoutGap(item));
|
|
21248
|
+
const yValue = clamp$1(current.yValue, item.minY, maxCenter);
|
|
21249
|
+
result.set(item.id, {
|
|
21250
|
+
...current,
|
|
21251
|
+
yValue
|
|
21252
|
+
});
|
|
21253
|
+
nextTop = yValue - item.height / 2;
|
|
21254
|
+
});
|
|
21255
|
+
const overlapOnlyMovable = sorted.filter((item) => {
|
|
21256
|
+
return item.overlapOnly && !item.isFixed;
|
|
21257
|
+
});
|
|
21258
|
+
if (overlapOnlyMovable.length > 1) {
|
|
21259
|
+
const sortedOverlapOnlyMovable = [...overlapOnlyMovable].sort((left, right) => getLayoutOrderY(left) - getLayoutOrderY(right));
|
|
21260
|
+
const sharedOuterEdge = sortedOverlapOnlyMovable[0]?.side === "right" ? Math.max(...sortedOverlapOnlyMovable.map((item) => {
|
|
21261
|
+
return (result.get(item.id)?.xValue ?? item.preferredX) + item.width / 2;
|
|
21262
|
+
})) : Math.min(...sortedOverlapOnlyMovable.map((item) => {
|
|
21263
|
+
return (result.get(item.id)?.xValue ?? item.preferredX) - item.width / 2;
|
|
21264
|
+
}));
|
|
21265
|
+
sortedOverlapOnlyMovable.forEach((item, index) => {
|
|
21266
|
+
const current = result.get(item.id);
|
|
21267
|
+
if (!current) return;
|
|
21268
|
+
const spreadOffset = Math.min(index * DEFAULT_SIDE_SPREAD_STEP, DEFAULT_SIDE_SPREAD_MAX);
|
|
21269
|
+
const direction = item.side === "right" ? -1 : 1;
|
|
21270
|
+
const alignedXValue = item.side === "right" ? sharedOuterEdge - item.width / 2 : sharedOuterEdge + item.width / 2;
|
|
21271
|
+
result.set(item.id, {
|
|
21272
|
+
...current,
|
|
21273
|
+
xValue: clamp$1(alignedXValue + direction * spreadOffset, item.minX, item.maxX)
|
|
21274
|
+
});
|
|
21275
|
+
});
|
|
21276
|
+
return result;
|
|
21277
|
+
}
|
|
21278
|
+
sorted.forEach((item, index) => {
|
|
21279
|
+
const current = result.get(item.id);
|
|
21280
|
+
if (!current || item.isFixed) return;
|
|
21281
|
+
const spreadOffset = Math.min(index * DEFAULT_SIDE_SPREAD_STEP, DEFAULT_SIDE_SPREAD_MAX);
|
|
21282
|
+
const direction = item.side === "right" ? -1 : 1;
|
|
21283
|
+
const xValue = clamp$1(current.xValue + direction * spreadOffset, item.minX, item.maxX);
|
|
21284
|
+
result.set(item.id, {
|
|
21285
|
+
...current,
|
|
21286
|
+
xValue
|
|
21287
|
+
});
|
|
21288
|
+
});
|
|
21289
|
+
return result;
|
|
21290
|
+
};
|
|
21291
|
+
var getCalloutLayoutPixels = (chart) => {
|
|
21292
|
+
const area = chart?.chartArea;
|
|
21293
|
+
if (!chart || !area) return /* @__PURE__ */ new Map();
|
|
21294
|
+
const occupiedRects = getOccupiedOriginalLabelRects(chart, area, getOverlappingCalloutIds(chart));
|
|
21295
|
+
const grouped = getCalloutItems(chart, area).map((item) => {
|
|
21296
|
+
const xValue = clamp$1(item.preferredX, item.minX, item.maxX);
|
|
21297
|
+
return {
|
|
21298
|
+
...item,
|
|
21299
|
+
preferredX: xValue
|
|
21300
|
+
};
|
|
21301
|
+
}).reduce((accumulator, item) => {
|
|
21302
|
+
accumulator[item.side].push(item);
|
|
21303
|
+
return accumulator;
|
|
21304
|
+
}, {
|
|
21305
|
+
left: [],
|
|
21306
|
+
right: []
|
|
21307
|
+
});
|
|
21308
|
+
const leftLayout = layoutSide(grouped.left, occupiedRects.filter((rect) => rect.side === "left").map((rect) => ({
|
|
21309
|
+
top: rect.top,
|
|
21310
|
+
bottom: rect.bottom
|
|
21311
|
+
})));
|
|
21312
|
+
const rightLayout = layoutSide(grouped.right, occupiedRects.filter((rect) => rect.side === "right").map((rect) => ({
|
|
21313
|
+
top: rect.top,
|
|
21314
|
+
bottom: rect.bottom
|
|
21315
|
+
})));
|
|
21316
|
+
return new Map([...leftLayout.entries(), ...rightLayout.entries()]);
|
|
21317
|
+
};
|
|
21318
|
+
var getCalloutLayout = (ctx, refAnnotation, index) => {
|
|
21319
|
+
const chart = getChartFromCtx$1(ctx);
|
|
21320
|
+
const xScale = chart ? getXScale(chart, getAxisId(refAnnotation, "x")) : void 0;
|
|
21321
|
+
const yScale = chart ? getYScale(chart, getAxisId(refAnnotation, "y")) : void 0;
|
|
21322
|
+
if (!chart || !yScale || !chart.chartArea) return null;
|
|
21323
|
+
if (!xScale && hasAxisAnchor(refAnnotation, "x")) return null;
|
|
21324
|
+
if (!xScale) return null;
|
|
21325
|
+
const layout = getCalloutLayoutPixels(chart).get(`callout-annotation-${index}`);
|
|
21326
|
+
if (!layout) return null;
|
|
21327
|
+
return {
|
|
21328
|
+
xValue: xScale.getValueForPixel(layout.xValue),
|
|
21329
|
+
yValue: yScale.getValueForPixel(layout.yValue)
|
|
21330
|
+
};
|
|
21331
|
+
};
|
|
20894
21332
|
var resolveCalloutXValue = (ctx, refAnnotation, calloutCfg, index) => {
|
|
20895
|
-
const
|
|
21333
|
+
const layout = getCalloutLayout(ctx, refAnnotation, index);
|
|
21334
|
+
if (layout) return layout.xValue;
|
|
21335
|
+
const chart = getChartFromCtx$1(ctx);
|
|
20896
21336
|
const xVal = refAnnotation?.xValue;
|
|
20897
21337
|
if (typeof xVal !== "number") return 0;
|
|
20898
21338
|
if (!chart) return xVal;
|
|
20899
|
-
const scale = getXScale(chart, refAnnotation
|
|
21339
|
+
const scale = getXScale(chart, getAxisId(refAnnotation, "x"));
|
|
20900
21340
|
if (!scale) return xVal;
|
|
20901
21341
|
const hasCustomOffset = typeof calloutCfg?.xAdjust === "number";
|
|
20902
21342
|
const side = index % 2 === 0 ? 1 : -1;
|
|
20903
|
-
const dx = hasCustomOffset ? calloutCfg?.xAdjust : side *
|
|
21343
|
+
const dx = hasCustomOffset ? calloutCfg?.xAdjust : side * DEFAULT_HORIZONTAL_OFFSET;
|
|
20904
21344
|
const basePx = scale.getPixelForValue(xVal);
|
|
20905
|
-
const cxBase = basePx + dx;
|
|
20906
21345
|
const area = chart.chartArea;
|
|
20907
|
-
const
|
|
20908
|
-
if (!area || !
|
|
20909
|
-
const margin = calloutCfg?.margin
|
|
20910
|
-
const
|
|
20911
|
-
|
|
20912
|
-
|
|
20913
|
-
if (cx - halfW < area.left + margin) {
|
|
20914
|
-
adjDx += area.left + margin + halfW - cx;
|
|
20915
|
-
cx = basePx + adjDx;
|
|
20916
|
-
} else if (cx + halfW > area.right - margin) {
|
|
20917
|
-
adjDx += area.right - margin - halfW - cx;
|
|
20918
|
-
cx = basePx + adjDx;
|
|
20919
|
-
}
|
|
20920
|
-
return scale.getValueForPixel(cx);
|
|
21346
|
+
const element = ctx?.element;
|
|
21347
|
+
if (!area || !element) return scale.getValueForPixel(basePx + dx);
|
|
21348
|
+
const margin = getNumericValue(calloutCfg?.margin, DEFAULT_MARGIN);
|
|
21349
|
+
const halfWidth = (element?.width ?? 0) / 2;
|
|
21350
|
+
const clampedPx = clamp$1(basePx + dx, area.left + margin + halfWidth, area.right - margin - halfWidth);
|
|
21351
|
+
return scale.getValueForPixel(clampedPx);
|
|
20921
21352
|
};
|
|
20922
21353
|
var resolveCalloutYValue = (ctx, refAnnotation, calloutCfg, index) => {
|
|
20923
|
-
const
|
|
20924
|
-
|
|
21354
|
+
const layout = getCalloutLayout(ctx, refAnnotation, index);
|
|
21355
|
+
if (layout) return layout.yValue;
|
|
21356
|
+
const chart = getChartFromCtx$1(ctx);
|
|
21357
|
+
const yVal = refAnnotation?.yValue;
|
|
20925
21358
|
if (typeof yVal !== "number") return 0;
|
|
20926
21359
|
if (!chart) return yVal;
|
|
20927
|
-
const scale = getYScale(chart, refAnnotation
|
|
21360
|
+
const scale = getYScale(chart, getAxisId(refAnnotation, "y"));
|
|
20928
21361
|
if (!scale) return yVal;
|
|
20929
21362
|
const hasCustomOffset = typeof calloutCfg?.yAdjust === "number";
|
|
20930
21363
|
const row = Math.floor(index / 2);
|
|
20931
|
-
const dy = hasCustomOffset ? calloutCfg?.yAdjust :
|
|
21364
|
+
const dy = hasCustomOffset ? calloutCfg?.yAdjust : DEFAULT_VERTICAL_OFFSET - row * DEFAULT_ROW_GAP;
|
|
20932
21365
|
const basePx = scale.getPixelForValue(yVal);
|
|
20933
|
-
const cyBase = basePx + dy;
|
|
20934
21366
|
const area = chart.chartArea;
|
|
20935
|
-
const
|
|
20936
|
-
if (!area || !
|
|
20937
|
-
const margin = calloutCfg?.margin
|
|
20938
|
-
const
|
|
20939
|
-
|
|
20940
|
-
|
|
20941
|
-
|
|
20942
|
-
|
|
20943
|
-
cy = basePx + adjDy;
|
|
20944
|
-
} else if (cy + halfH > area.bottom - margin) {
|
|
20945
|
-
adjDy += area.bottom - margin - halfH - cy;
|
|
20946
|
-
cy = basePx + adjDy;
|
|
20947
|
-
}
|
|
20948
|
-
return scale.getValueForPixel(cy);
|
|
20949
|
-
};
|
|
20950
|
-
var isInRange = (v, min, max) => v >= min && v <= max;
|
|
21367
|
+
const element = ctx?.element;
|
|
21368
|
+
if (!area || !element) return scale.getValueForPixel(basePx + dy);
|
|
21369
|
+
const margin = getNumericValue(calloutCfg?.margin, DEFAULT_MARGIN);
|
|
21370
|
+
const halfHeight = (element?.height ?? 0) / 2;
|
|
21371
|
+
const clampedPx = clamp$1(basePx + dy, area.top + margin + halfHeight, area.bottom - margin - halfHeight);
|
|
21372
|
+
return scale.getValueForPixel(clampedPx);
|
|
21373
|
+
};
|
|
21374
|
+
var isInRange = (value, min, max) => value >= min && value <= max;
|
|
20951
21375
|
var isCalloutAnchorInChartArea = (ctx, refAnnotation, margin = 0) => {
|
|
20952
|
-
const chart = ctx
|
|
21376
|
+
const chart = getChartFromCtx$1(ctx);
|
|
20953
21377
|
const area = chart?.chartArea;
|
|
20954
21378
|
if (!chart || !area) return true;
|
|
20955
|
-
const xScale = getXScale(chart, refAnnotation
|
|
20956
|
-
const yScale = getYScale(chart, refAnnotation
|
|
20957
|
-
const
|
|
20958
|
-
const
|
|
20959
|
-
if (!xScale || !yScale) return false;
|
|
20960
|
-
if (
|
|
20961
|
-
const x =
|
|
20962
|
-
const y =
|
|
21379
|
+
const xScale = getXScale(chart, getAxisId(refAnnotation, "x"));
|
|
21380
|
+
const yScale = getYScale(chart, getAxisId(refAnnotation, "y"));
|
|
21381
|
+
const hasXValues = hasAxisAnchor(refAnnotation, "x");
|
|
21382
|
+
const hasYValues = hasAxisAnchor(refAnnotation, "y");
|
|
21383
|
+
if (hasXValues && !xScale || hasYValues && !yScale) return false;
|
|
21384
|
+
if (!hasXValues || !hasYValues) return false;
|
|
21385
|
+
const x = getAnchorPixel(chart, refAnnotation, "x", area);
|
|
21386
|
+
const y = getAnchorPixel(chart, refAnnotation, "y", area);
|
|
20963
21387
|
return isInRange(x, area.left + margin, area.right - margin) && isInRange(y, area.top + margin, area.bottom - margin);
|
|
20964
21388
|
};
|
|
20965
21389
|
//#endregion
|
|
@@ -21260,7 +21684,14 @@ var getCalloutAnnotation = (refAnnotation, index) => {
|
|
|
21260
21684
|
const calloutCfg = refAnnotation?.labelConfig?.callout ?? {};
|
|
21261
21685
|
const baseAnnotation = {
|
|
21262
21686
|
...baseRest,
|
|
21263
|
-
label: {
|
|
21687
|
+
label: {
|
|
21688
|
+
...label,
|
|
21689
|
+
display: (ctx) => {
|
|
21690
|
+
if (!(refAnnotation.display ?? true)) return false;
|
|
21691
|
+
if (!calloutCfg?.onlyWhenOverlapping) return false;
|
|
21692
|
+
return !isCalloutOverlapping(ctx, refAnnotation, index);
|
|
21693
|
+
}
|
|
21694
|
+
}
|
|
21264
21695
|
};
|
|
21265
21696
|
const color = calloutCfg?.color ?? "hsl(60, 10.34482759%, 12.5%)";
|
|
21266
21697
|
const font = calloutCfg?.font ?? `12px "Roobert", "Noto Sans", sans-serif`;
|
|
@@ -21268,10 +21699,10 @@ var getCalloutAnnotation = (refAnnotation, index) => {
|
|
|
21268
21699
|
const onCalloutDragStart = typeof calloutCfg?.onDragStart === "function" ? calloutCfg.onDragStart : void 0;
|
|
21269
21700
|
const onCalloutDrag = typeof calloutCfg?.onDrag === "function" ? calloutCfg.onDrag : void 0;
|
|
21270
21701
|
const onCalloutDragEnd = typeof calloutCfg?.onDragEnd === "function" ? calloutCfg.onDragEnd : void 0;
|
|
21271
|
-
const strokeStyle = calloutCfg.strokeStyle ??
|
|
21702
|
+
const strokeStyle = calloutCfg.strokeStyle ?? "rgba(120, 126, 138, 0.9)";
|
|
21272
21703
|
const lineWidth = typeof calloutCfg.lineWidth === "number" ? calloutCfg.lineWidth : 1;
|
|
21273
|
-
const startOffset = typeof calloutCfg.startOffset === "number" ? calloutCfg.startOffset :
|
|
21274
|
-
const endOffset = typeof calloutCfg.endOffset === "number" ? calloutCfg.endOffset :
|
|
21704
|
+
const startOffset = typeof calloutCfg.startOffset === "number" ? calloutCfg.startOffset : 2;
|
|
21705
|
+
const endOffset = typeof calloutCfg.endOffset === "number" ? calloutCfg.endOffset : .5;
|
|
21275
21706
|
const calloutId = `callout-annotation-${index}`;
|
|
21276
21707
|
return [baseAnnotation, {
|
|
21277
21708
|
id: calloutId,
|
|
@@ -21281,14 +21712,18 @@ var getCalloutAnnotation = (refAnnotation, index) => {
|
|
|
21281
21712
|
color: (ctx) => {
|
|
21282
21713
|
const chart = getChartFromCtx(ctx);
|
|
21283
21714
|
if (!chart) return color;
|
|
21284
|
-
if (chart.hoveredAnnotationId === calloutId) return "#DB5B00";
|
|
21715
|
+
if (Boolean(chart?.options?.plugins?.annotationDraggerPlugin?.enabled) && chart.hoveredAnnotationId === calloutId) return "#DB5B00";
|
|
21285
21716
|
return color;
|
|
21286
21717
|
},
|
|
21287
21718
|
font,
|
|
21288
21719
|
borderColor,
|
|
21289
21720
|
borderWidth: BORDER_WIDTH.INITIAL,
|
|
21290
21721
|
padding: 5,
|
|
21291
|
-
display: (ctx) =>
|
|
21722
|
+
display: (ctx) => {
|
|
21723
|
+
if (!(refAnnotation.display ?? true)) return false;
|
|
21724
|
+
if (!isCalloutAnchorInChartArea(ctx, refAnnotation, calloutCfg.margin ?? 0)) return false;
|
|
21725
|
+
return isCalloutOverlapping(ctx, refAnnotation, index);
|
|
21726
|
+
},
|
|
21292
21727
|
xValue: (ctx) => {
|
|
21293
21728
|
const persistenceId = getChartFromCtx(ctx)?.options?.persistenceId;
|
|
21294
21729
|
const stored = getAnnotationPosition(persistenceId, `callout-annotation-${index}`);
|
|
@@ -21305,10 +21740,10 @@ var getCalloutAnnotation = (refAnnotation, index) => {
|
|
|
21305
21740
|
displayDragCoordinates: false,
|
|
21306
21741
|
enableDrag: true,
|
|
21307
21742
|
enter: ({ element }, { chart }) => {
|
|
21308
|
-
return handleLabelEnter(element, chart, { enableDrag:
|
|
21743
|
+
return handleLabelEnter(element, chart, { enableDrag: Boolean(chart?.options?.plugins?.annotationDraggerPlugin?.enabled) });
|
|
21309
21744
|
},
|
|
21310
21745
|
leave: ({ element }, { chart }) => {
|
|
21311
|
-
return handleLabelLeave(element, chart, { enableDrag:
|
|
21746
|
+
return handleLabelLeave(element, chart, { enableDrag: Boolean(chart?.options?.plugins?.annotationDraggerPlugin?.enabled) });
|
|
21312
21747
|
},
|
|
21313
21748
|
onDragStart: onCalloutDragStart ? () => (coords) => {
|
|
21314
21749
|
return onCalloutDragStart(coords, refAnnotation);
|
|
@@ -21325,7 +21760,13 @@ var getCalloutAnnotation = (refAnnotation, index) => {
|
|
|
21325
21760
|
strokeStyle,
|
|
21326
21761
|
lineWidth,
|
|
21327
21762
|
startOffset,
|
|
21328
|
-
endOffset
|
|
21763
|
+
endOffset,
|
|
21764
|
+
anchor: {
|
|
21765
|
+
position: refAnnotation?.labelConfig?.position,
|
|
21766
|
+
xAdjust: refAnnotation?.labelConfig?.xAdjust,
|
|
21767
|
+
yAdjust: refAnnotation?.labelConfig?.yAdjust,
|
|
21768
|
+
labelOffsetPx: refAnnotation?.labelOffsetPx
|
|
21769
|
+
}
|
|
21329
21770
|
}
|
|
21330
21771
|
}];
|
|
21331
21772
|
};
|
|
@@ -22146,52 +22587,126 @@ var annotationDraggerPlugin = {
|
|
|
22146
22587
|
};
|
|
22147
22588
|
//#endregion
|
|
22148
22589
|
//#region src/components/line-chart/plugins/callout-plugin/helpers.ts
|
|
22149
|
-
var
|
|
22150
|
-
|
|
22151
|
-
|
|
22152
|
-
return
|
|
22590
|
+
var getRectangleEdgePoint = (el, targetX, targetY, offset) => {
|
|
22591
|
+
const width = el?.width ?? 0;
|
|
22592
|
+
const height = el?.height ?? 0;
|
|
22593
|
+
if (width <= 0 || height <= 0) return {
|
|
22594
|
+
x: el.centerX,
|
|
22595
|
+
y: el.centerY
|
|
22596
|
+
};
|
|
22597
|
+
const halfWidth = width / 2;
|
|
22598
|
+
const halfHeight = height / 2;
|
|
22599
|
+
const dx = targetX - el.centerX;
|
|
22600
|
+
const dy = targetY - el.centerY;
|
|
22601
|
+
const length = Math.sqrt(dx * dx + dy * dy) || 1;
|
|
22602
|
+
const ux = dx / length;
|
|
22603
|
+
const uy = dy / length;
|
|
22604
|
+
const tx = Math.abs(ux) > 1e-6 ? halfWidth / Math.abs(ux) : Number.POSITIVE_INFINITY;
|
|
22605
|
+
const ty = Math.abs(uy) > 1e-6 ? halfHeight / Math.abs(uy) : Number.POSITIVE_INFINITY;
|
|
22606
|
+
const distance = Math.min(tx, ty) + offset;
|
|
22607
|
+
return {
|
|
22608
|
+
x: el.centerX + ux * distance,
|
|
22609
|
+
y: el.centerY + uy * distance
|
|
22610
|
+
};
|
|
22611
|
+
};
|
|
22612
|
+
var getLabelEdgePoint = (labelEl, startX, endOffset) => {
|
|
22613
|
+
const width = labelEl?.width ?? 0;
|
|
22614
|
+
const height = labelEl?.height ?? 0;
|
|
22615
|
+
if (width <= 0 || height <= 0) return {
|
|
22616
|
+
x: labelEl.centerX,
|
|
22617
|
+
y: labelEl.centerY
|
|
22618
|
+
};
|
|
22619
|
+
const halfWidth = width / 2;
|
|
22620
|
+
const direction = startX <= labelEl.centerX ? -1 : 1;
|
|
22621
|
+
return {
|
|
22622
|
+
x: labelEl.centerX + direction * (halfWidth + endOffset),
|
|
22623
|
+
y: labelEl.centerY
|
|
22624
|
+
};
|
|
22625
|
+
};
|
|
22626
|
+
var getReferencePoint = (fromEl, connector) => {
|
|
22627
|
+
const { anchor } = connector;
|
|
22628
|
+
if (!anchor) return {
|
|
22629
|
+
x: fromEl.centerX,
|
|
22630
|
+
y: fromEl.centerY
|
|
22631
|
+
};
|
|
22632
|
+
const width = fromEl?.width ?? 0;
|
|
22633
|
+
const height = fromEl?.height ?? 0;
|
|
22634
|
+
const radius = fromEl?.options?.radius ?? 0;
|
|
22635
|
+
const halfWidth = width / 2;
|
|
22636
|
+
const halfHeight = height / 2;
|
|
22637
|
+
const labelOffset = anchor?.labelOffsetPx ?? 14;
|
|
22638
|
+
const xAdjust = anchor?.xAdjust ?? 0;
|
|
22639
|
+
const yAdjust = anchor?.yAdjust ?? 0;
|
|
22640
|
+
const position = anchor?.position ?? "top";
|
|
22641
|
+
let x = fromEl.centerX;
|
|
22642
|
+
let y = fromEl.centerY;
|
|
22643
|
+
switch (position) {
|
|
22644
|
+
case "left":
|
|
22645
|
+
x -= Math.max(halfWidth, radius) + labelOffset;
|
|
22646
|
+
break;
|
|
22647
|
+
case "right":
|
|
22648
|
+
x += Math.max(halfWidth, radius) + labelOffset;
|
|
22649
|
+
break;
|
|
22650
|
+
case "bottom":
|
|
22651
|
+
y += Math.max(halfHeight, radius) + labelOffset;
|
|
22652
|
+
break;
|
|
22653
|
+
case "top-left":
|
|
22654
|
+
x -= halfWidth;
|
|
22655
|
+
y -= halfHeight;
|
|
22656
|
+
break;
|
|
22657
|
+
case "top-right":
|
|
22658
|
+
x += halfWidth;
|
|
22659
|
+
y -= halfHeight;
|
|
22660
|
+
break;
|
|
22661
|
+
case "bottom-left":
|
|
22662
|
+
x -= halfWidth;
|
|
22663
|
+
y += halfHeight;
|
|
22664
|
+
break;
|
|
22665
|
+
case "bottom-right":
|
|
22666
|
+
x += halfWidth;
|
|
22667
|
+
y += halfHeight;
|
|
22668
|
+
break;
|
|
22669
|
+
default:
|
|
22670
|
+
y -= Math.max(halfHeight, radius) + labelOffset;
|
|
22671
|
+
break;
|
|
22672
|
+
}
|
|
22673
|
+
return {
|
|
22674
|
+
x: x + xAdjust,
|
|
22675
|
+
y: y + yAdjust
|
|
22676
|
+
};
|
|
22153
22677
|
};
|
|
22154
22678
|
var computeConnectorPoints = (fromEl, labelEl, connector) => {
|
|
22155
22679
|
const x1c = fromEl?.centerX;
|
|
22156
22680
|
const y1c = fromEl?.centerY;
|
|
22157
22681
|
const cx = labelEl?.centerX;
|
|
22158
22682
|
const cy = labelEl?.centerY;
|
|
22159
|
-
const labelWidth = labelEl?.width ?? 0;
|
|
22160
|
-
const labelHeight = labelEl?.height ?? 0;
|
|
22161
22683
|
const ux = cx - x1c;
|
|
22162
22684
|
const uy = cy - y1c;
|
|
22163
22685
|
const len = Math.sqrt(ux * ux + uy * uy) || 1;
|
|
22164
22686
|
const dx = ux / len;
|
|
22165
22687
|
const dy = uy / len;
|
|
22166
|
-
const
|
|
22167
|
-
const
|
|
22168
|
-
const
|
|
22169
|
-
|
|
22170
|
-
|
|
22171
|
-
|
|
22172
|
-
|
|
22173
|
-
|
|
22174
|
-
|
|
22175
|
-
|
|
22176
|
-
|
|
22177
|
-
|
|
22178
|
-
|
|
22179
|
-
const vyn = vy / vlen;
|
|
22180
|
-
const tx = Math.abs(vxn) > 1e-6 ? hw / Math.abs(vxn) : Number.POSITIVE_INFINITY;
|
|
22181
|
-
const ty = Math.abs(vyn) > 1e-6 ? hh / Math.abs(vyn) : Number.POSITIVE_INFINITY;
|
|
22182
|
-
const total = Math.min(tx, ty) + (connector.endOffset ?? 1);
|
|
22183
|
-
endX = cx + vxn * total;
|
|
22184
|
-
endY = cy + vyn * total;
|
|
22185
|
-
} else {
|
|
22186
|
-
const endOffset = connector.endOffset ?? 1;
|
|
22187
|
-
endX = cx - dx * endOffset;
|
|
22188
|
-
endY = cy - dy * endOffset;
|
|
22189
|
-
}
|
|
22688
|
+
const startOffset = connector?.startOffset ?? 6;
|
|
22689
|
+
const isPointAnchor = typeof fromEl?.options?.radius === "number";
|
|
22690
|
+
const referencePoint = connector?.anchor && !isPointAnchor ? getReferencePoint(fromEl, connector) : isPointAnchor ? {
|
|
22691
|
+
x: x1c,
|
|
22692
|
+
y: y1c
|
|
22693
|
+
} : getRectangleEdgePoint(fromEl, cx, cy, startOffset);
|
|
22694
|
+
const endOffset = connector?.endOffset ?? 1;
|
|
22695
|
+
const end = typeof labelEl?.width === "number" && typeof labelEl?.height === "number" ? getLabelEdgePoint(labelEl, referencePoint.x, endOffset) : {
|
|
22696
|
+
x: cx - dx * endOffset,
|
|
22697
|
+
y: cy - dy * endOffset
|
|
22698
|
+
};
|
|
22699
|
+
const tickHalf = isPointAnchor ? 0 : (connector?.anchor?.tickSize ?? 8) / 2;
|
|
22700
|
+
const lineDirection = end.x >= referencePoint.x ? 1 : -1;
|
|
22190
22701
|
return {
|
|
22191
|
-
startX,
|
|
22192
|
-
startY,
|
|
22193
|
-
endX,
|
|
22194
|
-
endY
|
|
22702
|
+
startX: referencePoint.x + lineDirection * tickHalf,
|
|
22703
|
+
startY: referencePoint.y,
|
|
22704
|
+
endX: end.x,
|
|
22705
|
+
endY: end.y,
|
|
22706
|
+
tickStartX: referencePoint.x - tickHalf,
|
|
22707
|
+
tickStartY: referencePoint.y,
|
|
22708
|
+
tickEndX: referencePoint.x + tickHalf,
|
|
22709
|
+
tickEndY: referencePoint.y
|
|
22195
22710
|
};
|
|
22196
22711
|
};
|
|
22197
22712
|
//#endregion
|
|
@@ -22214,17 +22729,24 @@ var calloutConnectorPlugin = {
|
|
|
22214
22729
|
const fromEl = elements.find((el) => el.options && el.options.id === connector.fromId);
|
|
22215
22730
|
if (!labelEl || !fromEl) return;
|
|
22216
22731
|
if (labelEl.options?.display === false) return;
|
|
22217
|
-
const { startX, startY, endX, endY } = computeConnectorPoints(fromEl, labelEl, connector) ?? {};
|
|
22732
|
+
const { startX, startY, endX, endY, tickStartX, tickStartY, tickEndX, tickEndY } = computeConnectorPoints(fromEl, labelEl, connector) ?? {};
|
|
22218
22733
|
const ctx = chart?.ctx;
|
|
22734
|
+
const strokeStyle = connector?.strokeStyle ?? "rgba(120, 126, 138, 0.9)";
|
|
22219
22735
|
ctx?.save?.();
|
|
22220
22736
|
ctx?.beginPath?.();
|
|
22221
22737
|
ctx?.moveTo?.(startX, startY);
|
|
22222
22738
|
ctx?.lineTo?.(endX, endY);
|
|
22223
22739
|
ctx.lineWidth = connector?.lineWidth ?? 1;
|
|
22224
|
-
ctx.strokeStyle =
|
|
22740
|
+
ctx.strokeStyle = strokeStyle;
|
|
22225
22741
|
if (connector?.lineDash && connector?.lineDash?.length) ctx?.setLineDash?.(connector.lineDash);
|
|
22226
22742
|
ctx.lineCap = "round";
|
|
22227
22743
|
ctx?.stroke?.();
|
|
22744
|
+
ctx?.beginPath?.();
|
|
22745
|
+
ctx?.moveTo?.(tickStartX, tickStartY);
|
|
22746
|
+
ctx?.lineTo?.(tickEndX, tickEndY);
|
|
22747
|
+
ctx.lineWidth = Math.max(connector?.lineWidth ?? 1, 1);
|
|
22748
|
+
ctx.strokeStyle = strokeStyle;
|
|
22749
|
+
ctx?.stroke?.();
|
|
22228
22750
|
ctx?.restore?.();
|
|
22229
22751
|
});
|
|
22230
22752
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oliasoft-open-source/charts-library",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.10.0-beta-2",
|
|
4
4
|
"description": "React Chart Library (based on Chart.js and react-chart-js-2)",
|
|
5
5
|
"homepage": "https://gitlab.com/oliasoft-open-source/charts-library",
|
|
6
6
|
"bugs": {
|