@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 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
- annotationDraggerPlugin?: AnnotationDraggerPluginOptions;
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
- calloutConnectorPlugin?: {
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$2 = (x, from, to) => Math.min(to, Math.max(from, x));
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$2(Math.min(points.begin[prop], points.end[prop]), chartArea[min], chartArea[max]);
14454
- rect[max] = clamp$2(Math.max(points.begin[prop], points.end[prop]), chartArea[min], chartArea[max]);
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$1 = (x, from, to) => Math.min(to, Math.max(from, x));
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$1(obj[key], from, to);
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$1(toPercent(s), 0, 1);
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$1(opacity, 0, 1) : 1;
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$1(Math.max(x, y), 0, .25);
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((k) => k?.toLowerCase()?.includes("x"));
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((k) => k?.toLowerCase()?.includes("y"));
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 chart = ctx?.chart;
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?.annotationAxis);
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 * 60;
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 el = ctx?.element;
20908
- if (!area || !el) return scale.getValueForPixel(cxBase);
20909
- const margin = calloutCfg?.margin ?? 8;
20910
- const halfW = (el?.width ?? 0) / 2;
20911
- let cx = cxBase;
20912
- let adjDx = dx;
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 chart = ctx?.chart;
20924
- const yVal = refAnnotation.yValue;
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?.annotationAxis);
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 : -40 - row * 22;
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 el = ctx?.element;
20936
- if (!area || !el) return scale.getValueForPixel(cyBase);
20937
- const margin = calloutCfg?.margin ?? 8;
20938
- const halfH = (el?.height ?? 0) / 2;
20939
- let cy = cyBase;
20940
- let adjDy = dy;
20941
- if (cy - halfH < area.top + margin) {
20942
- adjDy += area.top + margin + halfH - cy;
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?.chart;
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.annotationAxis);
20956
- const yScale = getYScale(chart, refAnnotation.annotationAxis);
20957
- const xVal = refAnnotation.xValue;
20958
- const yVal = refAnnotation.yValue;
20959
- if (!xScale || !yScale) return false;
20960
- if (typeof xVal !== "number" || typeof yVal !== "number") return false;
20961
- const x = xScale.getPixelForValue(xVal);
20962
- const y = yScale.getPixelForValue(yVal);
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: { display: false }
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 ?? baseAnnotation.borderColor;
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 : 6;
21274
- const endOffset = typeof calloutCfg.endOffset === "number" ? calloutCfg.endOffset : 1;
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) => (refAnnotation.display ?? true) && isCalloutAnchorInChartArea(ctx, refAnnotation, calloutCfg.margin ?? 0),
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: true });
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: true });
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 getRadius = (el) => {
22150
- if (typeof el.options?.radius === "number") return el.options.radius;
22151
- if (typeof el.width === "number" && typeof el.height === "number") return Math.min(el.width, el.height) / 2;
22152
- return 0;
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 fromRadius = getRadius(fromEl);
22167
- const startOffset = (connector?.startOffset ?? 6) + fromRadius;
22168
- const startX = x1c + dx * startOffset;
22169
- const startY = y1c + dy * startOffset;
22170
- let endX = cx;
22171
- let endY = cy;
22172
- if (labelWidth > 0 && labelHeight > 0) {
22173
- const hw = labelWidth / 2;
22174
- const hh = labelHeight / 2;
22175
- const vx = x1c - cx;
22176
- const vy = y1c - cy;
22177
- const vlen = Math.sqrt(vx * vx + vy * vy) || 1;
22178
- const vxn = vx / vlen;
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 = connector?.strokeStyle ?? "rgba(120,120,120,0.9)";
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.9.1",
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": {