@oliasoft-open-source/charts-library 5.8.0 → 5.9.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.
Files changed (36) hide show
  1. package/dist/assets/{Color-6BZIO3FS-C124yz2l.js → Color-6BZIO3FS-BdmyW5fF.js} +1 -1
  2. package/dist/assets/{DocsRenderer-LL677BLK-D4qKUuBB.js → DocsRenderer-LL677BLK-Dmh2MbD-.js} +4 -4
  3. package/dist/assets/{WithTooltip-65CFNBJE-CtWnqLza.js → WithTooltip-65CFNBJE-B1vNinkY.js} +1 -1
  4. package/dist/assets/{bar-chart.stories-C3SMcQsP.js → bar-chart.stories-Ch0i7N0G.js} +2 -2
  5. package/dist/assets/{chunk-YKABRMAI-Ahx4OkN7.js → chunk-YKABRMAI-nN4IfCIz.js} +1 -1
  6. package/dist/assets/{components-DIpk8W7G.js → components-s5a1V3CD.js} +4 -4
  7. package/dist/assets/formatter-EIJCOSYU-Bo0DMj3p.js +1 -0
  8. package/dist/assets/{get-draggableData-w1LT3_ff.js → get-draggableData-mCkevOrC.js} +1 -1
  9. package/dist/assets/{iframe-DApKJtpy.js → iframe-B7buKd6W.js} +3 -3
  10. package/dist/assets/{legend-BIh7BsGA.js → legend-Cem_14IV.js} +39 -39
  11. package/dist/assets/{legend-context-CQKzSsRL.js → legend-context-D1oEf-Th.js} +3 -3
  12. package/dist/assets/line-chart-BDauhYk8.js +1 -0
  13. package/dist/assets/{line-chart.stories-BI9cuT6Z.js → line-chart.stories-T04m8x5t.js} +7 -3
  14. package/dist/assets/{line-chart.test-case.stories-BxTEBLo3.js → line-chart.test-case.stories-BcA_QlE1.js} +127 -4
  15. package/dist/assets/{pie-chart.stories-BHZXRphh.js → pie-chart.stories-D2G6WnUw.js} +1 -1
  16. package/dist/assets/{react-18-JAuqV3gQ.js → react-18-DQODWq5X.js} +1 -1
  17. package/dist/assets/{react-DPAuT4W0.js → react-CwUuogrH.js} +1 -1
  18. package/dist/assets/{react-dom-CWw972ZY.js → react-dom-O1LTTn3X.js} +1 -1
  19. package/dist/assets/{scatter-chart.stories-DQLyCWVA.js → scatter-chart.stories-DJ3Z3dsB.js} +1 -1
  20. package/dist/assets/{syntaxhighlighter-ED5Y7EFY-CxhX_a0D.js → syntaxhighlighter-ED5Y7EFY-DYFKPQ-I.js} +1 -1
  21. package/dist/assets/{theming-BGumyAJ5.js → theming-DpsViFyv.js} +1 -1
  22. package/dist/common/common.interface.d.ts +7 -0
  23. package/dist/common/helpers/callout-helpers/callout-overlap-helpers.d.ts +9 -0
  24. package/dist/common/helpers/get-chart-annotation.d.ts +48 -6
  25. package/dist/iframe.html +1 -1
  26. package/dist/index.js +367 -57
  27. package/dist/index.json +1 -1
  28. package/dist/line-chart/plugins/vertical-markers-plugin/draw.d.ts +24 -0
  29. package/dist/line-chart/plugins/vertical-markers-plugin/types.d.ts +42 -0
  30. package/dist/line-chart/plugins/vertical-markers-plugin/utils.d.ts +23 -0
  31. package/dist/line-chart/plugins/vertical-markers-plugin/vertical-markers-plugin.d.ts +54 -0
  32. package/dist/project.json +1 -1
  33. package/dist/src/components/common/helpers/callout-helpers/callout-overlap-helpers.d.ts +9 -0
  34. package/package.json +1 -1
  35. package/dist/assets/formatter-EIJCOSYU-B8p8ny5o.js +0 -1
  36. package/dist/assets/line-chart-CcOicjlw.js +0 -1
package/dist/index.js CHANGED
@@ -802,7 +802,7 @@ function _factorize(value) {
802
802
  function isNonPrimitive(n) {
803
803
  return typeof n === "symbol" || typeof n === "object" && n !== null && !(Symbol.toPrimitive in n || "toString" in n || "valueOf" in n);
804
804
  }
805
- function isNumber$1(n) {
805
+ function isNumber$2(n) {
806
806
  return !isNonPrimitive(n) && !isNaN(parseFloat(n)) && isFinite(n);
807
807
  }
808
808
  function almostWhole(x, epsilon) {
@@ -4352,7 +4352,7 @@ var LineController = class extends DatasetController {
4352
4352
  const iAxis = iScale.axis;
4353
4353
  const vAxis = vScale.axis;
4354
4354
  const { spanGaps, segment } = this.options;
4355
- const maxGapLength = isNumber$1(spanGaps) ? spanGaps : Number.POSITIVE_INFINITY;
4355
+ const maxGapLength = isNumber$2(spanGaps) ? spanGaps : Number.POSITIVE_INFINITY;
4356
4356
  const directUpdate = this.chart._animationsDisabled || reset || mode === "none";
4357
4357
  const end = start + count;
4358
4358
  const pointsCount = points.length;
@@ -4475,7 +4475,7 @@ var ScatterController = class extends DatasetController {
4475
4475
  const iAxis = iScale.axis;
4476
4476
  const vAxis = vScale.axis;
4477
4477
  const { spanGaps, segment } = this.options;
4478
- const maxGapLength = isNumber$1(spanGaps) ? spanGaps : Number.POSITIVE_INFINITY;
4478
+ const maxGapLength = isNumber$2(spanGaps) ? spanGaps : Number.POSITIVE_INFINITY;
4479
4479
  const directUpdate = this.chart._animationsDisabled || reset || mode === "none";
4480
4480
  let prevParsed = start > 0 && this.getParsed(start - 1);
4481
4481
  for (let i = start; i < start + count; ++i) {
@@ -5281,7 +5281,7 @@ var Element = class {
5281
5281
  };
5282
5282
  }
5283
5283
  hasValue() {
5284
- return isNumber$1(this.x) && isNumber$1(this.y);
5284
+ return isNumber$2(this.x) && isNumber$2(this.y);
5285
5285
  }
5286
5286
  getProps(props, final) {
5287
5287
  const anims = this.$animations;
@@ -11390,7 +11390,7 @@ function parse(scale, input) {
11390
11390
  if (typeof parser === "function") value = parser(value);
11391
11391
  if (!isNumberFinite(value)) value = typeof parser === "string" ? adapter.parse(value, parser) : adapter.parse(value);
11392
11392
  if (value === null) return null;
11393
- if (round) value = round === "week" && (isNumber$1(isoWeekday) || isoWeekday === true) ? adapter.startOf(value, "isoWeek", isoWeekday) : adapter.startOf(value, round);
11393
+ if (round) value = round === "week" && (isNumber$2(isoWeekday) || isoWeekday === true) ? adapter.startOf(value, "isoWeek", isoWeekday) : adapter.startOf(value, round);
11394
11394
  return +value;
11395
11395
  }
11396
11396
  function determineUnitForAutoTicks(minUnit, min, max, capacity) {
@@ -11585,7 +11585,7 @@ var TimeScale = class extends Scale {
11585
11585
  const minor = timeOpts.unit || determineUnitForAutoTicks(timeOpts.minUnit, min, max, this._getLabelCapacity(min));
11586
11586
  const stepSize = valueOrDefault(options.ticks.stepSize, 1);
11587
11587
  const weekday = minor === "week" ? timeOpts.isoWeekday : false;
11588
- const hasWeekday = isNumber$1(weekday) || weekday === true;
11588
+ const hasWeekday = isNumber$2(weekday) || weekday === true;
11589
11589
  const ticks = {};
11590
11590
  let first = min;
11591
11591
  let time, count;
@@ -15499,8 +15499,8 @@ function applyLabelContent(ctx, { x, y }, labels, { fonts, colors }) {
15499
15499
  });
15500
15500
  }
15501
15501
  function getOpacity(value, elementValue) {
15502
- const opacity = isNumber$1(value) ? value : elementValue;
15503
- return isNumber$1(opacity) ? clamp$1(opacity, 0, 1) : 1;
15502
+ const opacity = isNumber$2(value) ? value : elementValue;
15503
+ return isNumber$2(opacity) ? clamp$1(opacity, 0, 1) : 1;
15504
15504
  }
15505
15505
  var positions = [
15506
15506
  "left",
@@ -17595,6 +17595,7 @@ const BORDER_COLOR = "rgba(0,0,0,0.1)";
17595
17595
  const ANNOTATION_DASH = [10, 2];
17596
17596
  const DEFAULT_FONT_FAMILY = "\"Roobert\", \"Noto Sans\", sans-serif";
17597
17597
  const DEFAULT_COLOR = "hsl(60, 10.34482759%, 12.5%)";
17598
+ const TRANSPARENT = "transparent";
17598
17599
  const LOGARITHMIC_STEPS = [
17599
17600
  1,
17600
17601
  10,
@@ -19404,23 +19405,85 @@ var getYScale = (chart, axisId) => {
19404
19405
  const key = Object.keys(chart?.scales ?? {})?.find((k) => k?.toLowerCase()?.includes("y"));
19405
19406
  return key ? chart?.scales?.[key] : void 0;
19406
19407
  };
19408
+ var isNumber$1 = (value) => {
19409
+ return typeof value === "number" && Number.isFinite(value);
19410
+ };
19411
+ var looksLikeXAxis = (axisId) => {
19412
+ return !!axisId && axisId.toLowerCase().includes("x");
19413
+ };
19414
+ var looksLikeYAxis = (axisId) => {
19415
+ return !!axisId && axisId.toLowerCase().includes("y");
19416
+ };
19417
+ var resolveXScale = (chart, refAnnotation) => {
19418
+ return getXScale(chart, refAnnotation?.xScaleID) ?? getXScale(chart, looksLikeXAxis(refAnnotation?.annotationAxis) ? refAnnotation?.annotationAxis : void 0) ?? getXScale(chart, refAnnotation?.annotationAxis);
19419
+ };
19420
+ var resolveYScale = (chart, refAnnotation) => {
19421
+ return getYScale(chart, refAnnotation?.yScaleID) ?? getYScale(chart, looksLikeYAxis(refAnnotation?.annotationAxis) ? refAnnotation?.annotationAxis : void 0) ?? getYScale(chart, refAnnotation?.annotationAxis);
19422
+ };
19423
+ var getAxisAlignedValue = (refAnnotation, axis) => {
19424
+ if (!isNumber$1(refAnnotation?.value)) return;
19425
+ const annAxis = refAnnotation?.annotationAxis;
19426
+ if (axis === "x" && looksLikeXAxis(annAxis)) return refAnnotation.value;
19427
+ if (axis === "y" && looksLikeYAxis(annAxis)) return refAnnotation.value;
19428
+ };
19429
+ var resolveAnchorX = (chart, refAnnotation) => {
19430
+ if (isNumber$1(refAnnotation?.xValue)) return refAnnotation.xValue;
19431
+ if (isNumber$1(refAnnotation?.xMin) && isNumber$1(refAnnotation?.xMax)) return (refAnnotation.xMin + refAnnotation.xMax) / 2;
19432
+ const axisValue = getAxisAlignedValue(refAnnotation, "x");
19433
+ if (isNumber$1(axisValue)) return axisValue;
19434
+ if (!chart) return 0;
19435
+ const xScale = resolveXScale(chart, refAnnotation);
19436
+ const area = chart.chartArea;
19437
+ if (!xScale || !area) return 0;
19438
+ return xScale.getValueForPixel((area.left + area.right) / 2);
19439
+ };
19440
+ var resolveAnchorY = (chart, refAnnotation) => {
19441
+ if (isNumber$1(refAnnotation?.yValue)) return refAnnotation.yValue;
19442
+ if (isNumber$1(refAnnotation?.yMin) && isNumber$1(refAnnotation?.yMax)) return (refAnnotation.yMin + refAnnotation.yMax) / 2;
19443
+ const axisValue = getAxisAlignedValue(refAnnotation, "y");
19444
+ if (isNumber$1(axisValue)) return axisValue;
19445
+ if (!chart) return 0;
19446
+ const yScale = resolveYScale(chart, refAnnotation);
19447
+ const area = chart.chartArea;
19448
+ if (!yScale || !area) return 0;
19449
+ return yScale.getValueForPixel((area.top + area.bottom) / 2);
19450
+ };
19451
+ var getDefaultXDirection = (refAnnotation, index) => {
19452
+ switch (refAnnotation?.labelConfig?.position) {
19453
+ case "left":
19454
+ case "top-left":
19455
+ case "bottom-left": return -1;
19456
+ case "right":
19457
+ case "top-right":
19458
+ case "bottom-right": return 1;
19459
+ default: return index % 2 === 0 ? 1 : -1;
19460
+ }
19461
+ };
19462
+ var getCalloutLayoutState = (chart, index) => {
19463
+ const c = chart;
19464
+ if (!c.__calloutLayoutState || index === 0) c.__calloutLayoutState = {
19465
+ byIndex: {},
19466
+ leftLastPx: Number.NEGATIVE_INFINITY,
19467
+ rightLastPx: Number.NEGATIVE_INFINITY
19468
+ };
19469
+ return c.__calloutLayoutState;
19470
+ };
19407
19471
  const resolveCalloutXValue = (ctx, refAnnotation, calloutCfg, index) => {
19408
19472
  const chart = ctx?.chart;
19409
- const xVal = refAnnotation?.xValue;
19410
- if (typeof xVal !== "number") return 0;
19473
+ const xVal = resolveAnchorX(chart, refAnnotation);
19411
19474
  if (!chart) return xVal;
19412
- const scale = getXScale(chart, refAnnotation?.annotationAxis);
19475
+ const scale = resolveXScale(chart, refAnnotation);
19413
19476
  if (!scale) return xVal;
19414
19477
  const hasCustomOffset = typeof calloutCfg?.xAdjust === "number";
19415
- const side = index % 2 === 0 ? 1 : -1;
19478
+ const side = getDefaultXDirection(refAnnotation, index);
19416
19479
  const dx = hasCustomOffset ? calloutCfg?.xAdjust : side * 60;
19480
+ if (!isNumber$1(xVal)) return xVal;
19417
19481
  const basePx = scale.getPixelForValue(xVal);
19418
19482
  const cxBase = basePx + dx;
19419
19483
  const area = chart.chartArea;
19420
- const el = ctx?.element;
19421
- if (!area || !el) return scale.getValueForPixel(cxBase);
19484
+ if (!area) return scale.getValueForPixel(cxBase);
19422
19485
  const margin = calloutCfg?.margin ?? 8;
19423
- const halfW = (el?.width ?? 0) / 2;
19486
+ const halfW = 160 / 2;
19424
19487
  let cx = cxBase;
19425
19488
  let adjDx = dx;
19426
19489
  if (cx - halfW < area.left + margin) {
@@ -19434,23 +19497,41 @@ const resolveCalloutXValue = (ctx, refAnnotation, calloutCfg, index) => {
19434
19497
  };
19435
19498
  const resolveCalloutYValue = (ctx, refAnnotation, calloutCfg, index) => {
19436
19499
  const chart = ctx?.chart;
19437
- const yVal = refAnnotation.yValue;
19438
- if (typeof yVal !== "number") return 0;
19500
+ const yVal = resolveAnchorY(chart, refAnnotation);
19439
19501
  if (!chart) return yVal;
19440
- const scale = getYScale(chart, refAnnotation?.annotationAxis);
19502
+ const scale = resolveYScale(chart, refAnnotation);
19441
19503
  if (!scale) return yVal;
19442
19504
  const hasCustomOffset = typeof calloutCfg?.yAdjust === "number";
19443
- const row = Math.floor(index / 2);
19505
+ const layoutIndex = typeof calloutCfg?.layoutIndex === "number" ? calloutCfg.layoutIndex : index;
19506
+ const row = Math.floor(layoutIndex / 2);
19444
19507
  const dy = hasCustomOffset ? calloutCfg?.yAdjust : -40 - row * 22;
19508
+ if (!isNumber$1(yVal)) return yVal;
19445
19509
  const basePx = scale.getPixelForValue(yVal);
19446
- const cyBase = basePx + dy;
19510
+ const laneBaseOffset = -24;
19511
+ let cyBase = !hasCustomOffset ? basePx + laneBaseOffset : basePx + dy;
19447
19512
  const area = chart.chartArea;
19448
- const el = ctx?.element;
19449
- if (!area || !el) return scale.getValueForPixel(cyBase);
19513
+ if (!area) return scale.getValueForPixel(cyBase);
19450
19514
  const margin = calloutCfg?.margin ?? 8;
19451
- const halfH = (el?.height ?? 0) / 2;
19515
+ const halfH = 18 / 2;
19516
+ const minGapPx = calloutCfg?.minGapPx ?? halfH * 2 + 4;
19452
19517
  let cy = cyBase;
19453
- let adjDy = dy;
19518
+ let adjDy = !hasCustomOffset ? laneBaseOffset : dy;
19519
+ if (!hasCustomOffset) {
19520
+ const side = getDefaultXDirection(refAnnotation, layoutIndex);
19521
+ const state = getCalloutLayoutState(chart, layoutIndex);
19522
+ const cachedCy = state.byIndex[layoutIndex];
19523
+ if (isNumber$1(cachedCy)) cy = cachedCy;
19524
+ else {
19525
+ if (side < 0) {
19526
+ cy = Math.max(cy, state.leftLastPx + minGapPx);
19527
+ state.leftLastPx = cy;
19528
+ } else {
19529
+ cy = Math.max(cy, state.rightLastPx + minGapPx);
19530
+ state.rightLastPx = cy;
19531
+ }
19532
+ state.byIndex[layoutIndex] = cy;
19533
+ }
19534
+ }
19454
19535
  if (cy - halfH < area.top + margin) {
19455
19536
  adjDy += area.top + margin + halfH - cy;
19456
19537
  cy = basePx + adjDy;
@@ -19465,16 +19546,176 @@ const isCalloutAnchorInChartArea = (ctx, refAnnotation, margin = 0) => {
19465
19546
  const chart = ctx?.chart;
19466
19547
  const area = chart?.chartArea;
19467
19548
  if (!chart || !area) return true;
19468
- const xScale = getXScale(chart, refAnnotation.annotationAxis);
19469
- const yScale = getYScale(chart, refAnnotation.annotationAxis);
19470
- const xVal = refAnnotation.xValue;
19471
- const yVal = refAnnotation.yValue;
19549
+ const xScale = resolveXScale(chart, refAnnotation);
19550
+ const yScale = resolveYScale(chart, refAnnotation);
19551
+ const xVal = resolveAnchorX(chart, refAnnotation);
19552
+ const yVal = resolveAnchorY(chart, refAnnotation);
19472
19553
  if (!xScale || !yScale) return false;
19473
- if (typeof xVal !== "number" || typeof yVal !== "number") return false;
19554
+ if (!isNumber$1(xVal) || !isNumber$1(yVal)) return false;
19474
19555
  const x = xScale.getPixelForValue(xVal);
19475
19556
  const y = yScale.getPixelForValue(yVal);
19476
19557
  return isInRange(x, area.left + margin, area.right - margin) && isInRange(y, area.top + margin, area.bottom - margin);
19477
19558
  };
19559
+ const getChartFromCtx = (ctx) => {
19560
+ if (!ctx) return;
19561
+ if (ctx.chart?.persistenceId !== void 0) return ctx.chart;
19562
+ if (ctx.chart?.chart?.persistenceId !== void 0) return ctx.chart.chart;
19563
+ if (ctx.$context?.chart?.persistenceId !== void 0) return ctx.$context.chart;
19564
+ return ctx.chart?.chart ?? ctx.chart ?? ctx.$context?.chart;
19565
+ };
19566
+ var isFiniteNumber$1 = (value) => {
19567
+ return typeof value === "number" && Number.isFinite(value);
19568
+ };
19569
+ var parseFontSize = (font) => {
19570
+ if (!font) return 12;
19571
+ const match = font.match(/(\d+(?:\.\d+)?)px/);
19572
+ return match ? Number(match[1]) : 12;
19573
+ };
19574
+ const getScaleByAxis = (chart, axis, ann) => {
19575
+ const preferred = axis === "x" ? [ann?.xScaleID, ann?.annotationAxis] : [ann?.yScaleID, ann?.annotationAxis];
19576
+ for (const key of preferred) if (key && chart?.scales?.[key]) return chart.scales[key];
19577
+ if (axis === "x" && chart?.scales?.x) return chart.scales.x;
19578
+ if (axis === "y" && chart?.scales?.y) return chart.scales.y;
19579
+ const contains = axis === "x" ? "x" : "y";
19580
+ const key = Object.keys(chart?.scales ?? {}).find((k) => k.toLowerCase().includes(contains));
19581
+ return key ? chart.scales[key] : void 0;
19582
+ };
19583
+ const getAnchorValueFromData = (ann, axis) => {
19584
+ const value = axis === "x" ? ann?.xValue : ann?.yValue;
19585
+ if (isFiniteNumber$1(value)) return value;
19586
+ const min = axis === "x" ? ann?.xMin : ann?.yMin;
19587
+ const max = axis === "x" ? ann?.xMax : ann?.yMax;
19588
+ if (isFiniteNumber$1(min) && isFiniteNumber$1(max)) return (min + max) / 2;
19589
+ const annAxis = `${ann?.annotationAxis ?? ""}`.toLowerCase();
19590
+ if (axis === "x" && annAxis.includes("x") && isFiniteNumber$1(ann?.value)) return ann.value;
19591
+ if (axis === "y" && annAxis.includes("y") && isFiniteNumber$1(ann?.value)) return ann.value;
19592
+ };
19593
+ const getLabelSide = (ann) => {
19594
+ const p = `${ann?.labelConfig?.position ?? ""}`.toLowerCase();
19595
+ if (p.includes("left")) return "left";
19596
+ if (p.includes("right")) return "right";
19597
+ return "center";
19598
+ };
19599
+ const buildLikelyOverlapSet = (annotationsData) => {
19600
+ const points = annotationsData.map((ann, idx) => ({
19601
+ idx,
19602
+ side: getLabelSide(ann),
19603
+ x: getAnchorValueFromData(ann, "x"),
19604
+ y: getAnchorValueFromData(ann, "y"),
19605
+ label: ann?.label,
19606
+ visible: ann?.display !== false
19607
+ })).filter((p) => p.visible && !!p.label && isFiniteNumber$1(p.y));
19608
+ if (!points.length) return /* @__PURE__ */ new Set();
19609
+ const ys = points.map((p) => p.y);
19610
+ const rangeY = Math.max(...ys) - Math.min(...ys);
19611
+ const yThreshold = Math.max(120, rangeY * .06);
19612
+ const xThreshold = .35;
19613
+ const overlapSet = /* @__PURE__ */ new Set();
19614
+ for (let i = 0; i < points.length; i += 1) for (let j = i + 1; j < points.length; j += 1) {
19615
+ const a = points[i];
19616
+ const b = points[j];
19617
+ if (!(a.side === "center" || b.side === "center" || a.side === b.side)) continue;
19618
+ const xClose = !isFiniteNumber$1(a.x) || !isFiniteNumber$1(b.x) ? true : Math.abs(a.x - b.x) <= xThreshold;
19619
+ if (Math.abs(a.y - b.y) <= yThreshold && xClose) {
19620
+ overlapSet.add(a.idx);
19621
+ overlapSet.add(b.idx);
19622
+ }
19623
+ }
19624
+ return overlapSet;
19625
+ };
19626
+ const buildOverlapCalloutYMap = (annotationsData, overlapSet) => {
19627
+ const points = annotationsData.map((ann, idx) => ({
19628
+ idx,
19629
+ side: getLabelSide(ann),
19630
+ y: getAnchorValueFromData(ann, "y")
19631
+ })).filter((p) => overlapSet.has(p.idx) && typeof p.y === "number");
19632
+ const yMap = /* @__PURE__ */ new Map();
19633
+ if (!points.length) return yMap;
19634
+ const ys = points.map((p) => p.y);
19635
+ const minY = Math.min(...ys);
19636
+ const maxY = Math.max(...ys);
19637
+ const yRange = Math.max(maxY - minY, 1);
19638
+ const minGap = Math.max(130, yRange * .03);
19639
+ const minBound = minY - minGap * .5;
19640
+ const maxBound = maxY + minGap * .5;
19641
+ const groups = {
19642
+ left: [],
19643
+ right: []
19644
+ };
19645
+ points.forEach((p) => {
19646
+ if (p.side === "right") {
19647
+ groups.right.push({
19648
+ idx: p.idx,
19649
+ y: p.y
19650
+ });
19651
+ return;
19652
+ }
19653
+ groups.left.push({
19654
+ idx: p.idx,
19655
+ y: p.y
19656
+ });
19657
+ });
19658
+ Object.keys(groups).forEach((side) => {
19659
+ const group = groups[side].sort((a, b) => a.y - b.y);
19660
+ if (!group.length) return;
19661
+ const packed = group.map((item, i) => {
19662
+ return i === 0 ? item.y : Math.max(item.y, group[i - 1].y + minGap);
19663
+ });
19664
+ const overflowBottom = packed[packed.length - 1] - maxBound;
19665
+ if (overflowBottom > 0) for (let i = 0; i < packed.length; i += 1) packed[i] -= overflowBottom;
19666
+ const overflowTop = minBound - packed[0];
19667
+ if (overflowTop > 0) for (let i = 0; i < packed.length; i += 1) packed[i] += overflowTop;
19668
+ group.forEach((item, i) => {
19669
+ yMap.set(item.idx, packed[i]);
19670
+ });
19671
+ });
19672
+ return yMap;
19673
+ };
19674
+ const getOverlapCalloutXAdjust = (ann) => {
19675
+ const side = getLabelSide(ann);
19676
+ if (side === "right") return -56;
19677
+ if (side === "left") return 56;
19678
+ return 0;
19679
+ };
19680
+ const hasOverlappingLabel = (ctx, refAnnotation, index, annotationsData) => {
19681
+ const chart = getChartFromCtx(ctx);
19682
+ if (!chart) return false;
19683
+ const yScale = getScaleByAxis(chart, "y", refAnnotation);
19684
+ const xScale = getScaleByAxis(chart, "x", refAnnotation);
19685
+ if (!yScale || !xScale) return false;
19686
+ const area = chart.chartArea;
19687
+ if (!area) return false;
19688
+ const yVal = getAnchorValueFromData(refAnnotation, "y");
19689
+ const xVal = getAnchorValueFromData(refAnnotation, "x");
19690
+ if (!isFiniteNumber$1(yVal)) return false;
19691
+ const currentYPx = yScale.getPixelForValue(yVal);
19692
+ const currentXPx = isFiniteNumber$1(xVal) ? xScale.getPixelForValue(xVal) : void 0;
19693
+ const currentSide = getLabelSide(refAnnotation);
19694
+ const currentFont = refAnnotation?.labelConfig?.font;
19695
+ const currentHeight = parseFontSize(currentFont) + 6;
19696
+ const nearTop = currentYPx - currentHeight <= area.top + 2;
19697
+ const nearBottom = currentYPx + currentHeight >= area.bottom - 2;
19698
+ if (nearTop || nearBottom) return true;
19699
+ for (let i = 0; i < annotationsData.length; i += 1) {
19700
+ if (i === index) continue;
19701
+ const ann = annotationsData[i];
19702
+ if (!ann?.label || ann?.display === false) continue;
19703
+ const otherYScale = getScaleByAxis(chart, "y", ann);
19704
+ const otherXScale = getScaleByAxis(chart, "x", ann);
19705
+ if (!otherYScale || !otherXScale) continue;
19706
+ const otherYVal = getAnchorValueFromData(ann, "y");
19707
+ const otherXVal = getAnchorValueFromData(ann, "x");
19708
+ if (!isFiniteNumber$1(otherYVal)) continue;
19709
+ const otherYPx = otherYScale.getPixelForValue(otherYVal);
19710
+ const otherXPx = isFiniteNumber$1(otherXVal) ? otherXScale.getPixelForValue(otherXVal) : void 0;
19711
+ const otherSide = getLabelSide(ann);
19712
+ const otherFont = ann?.labelConfig?.font;
19713
+ const yThreshold = (currentHeight + (parseFontSize(otherFont) + 6)) / 2;
19714
+ const xClose = !isFiniteNumber$1(currentXPx) || !isFiniteNumber$1(otherXPx) ? true : Math.abs(currentXPx - otherXPx) < 160;
19715
+ if ((currentSide === "center" || otherSide === "center" || currentSide === otherSide) && Math.abs(currentYPx - otherYPx) < yThreshold && xClose) return true;
19716
+ }
19717
+ return false;
19718
+ };
19478
19719
  var STORAGE_PREFIX = "chart_annotations";
19479
19720
  var getStorageKey = (persistenceId) => {
19480
19721
  return `${STORAGE_PREFIX}:${persistenceId}`;
@@ -19509,12 +19750,9 @@ const getAnnotationPosition = (persistenceId, annotationId) => {
19509
19750
  if (!persistenceId) return void 0;
19510
19751
  return readStorage(persistenceId)[annotationId];
19511
19752
  };
19512
- const getChartFromCtx = (ctx) => {
19513
- if (!ctx) return;
19514
- if (ctx.chart?.persistenceId !== void 0) return ctx.chart;
19515
- if (ctx.chart?.chart?.persistenceId !== void 0) return ctx.chart.chart;
19516
- if (ctx.$context?.chart?.persistenceId !== void 0) return ctx.$context.chart;
19517
- return ctx.chart?.chart ?? ctx.chart ?? ctx.$context?.chart;
19753
+ var isDragActive = (chart, annotation) => {
19754
+ const pluginEnabled = Boolean(chart?.options?.plugins?.annotationDraggerPlugin?.enabled);
19755
+ return Boolean(annotation?.enableDrag && pluginEnabled);
19518
19756
  };
19519
19757
  var mapToBoxLikeLabelPosition = (position) => {
19520
19758
  switch (position) {
@@ -19554,7 +19792,8 @@ var mapToBoxLikeLabelPosition = (position) => {
19554
19792
  }
19555
19793
  };
19556
19794
  var handleLineEnter = (element, chart, annotation) => {
19557
- chart.canvas.style.cursor = CursorStyle.Pointer;
19795
+ const canDrag = isDragActive(chart, annotation);
19796
+ chart.canvas.style.cursor = canDrag ? CursorStyle.Pointer : CursorStyle.Initial;
19558
19797
  if (element.options.scaleID?.includes(AxisType.X)) {
19559
19798
  if (element.options.label) element.options.label.xAdjust = chart.chartArea.left;
19560
19799
  }
@@ -19563,7 +19802,7 @@ var handleLineEnter = (element, chart, annotation) => {
19563
19802
  element.label.options.display = true;
19564
19803
  element.options.label.enabled = true;
19565
19804
  }
19566
- if (annotation?.enableDrag) {
19805
+ if (canDrag) {
19567
19806
  chart.hoveredAnnotationId = element.options.id || null;
19568
19807
  chart.update("none");
19569
19808
  }
@@ -19577,14 +19816,14 @@ var handleLineLeave = (element, chart, annotation) => {
19577
19816
  element.label.options.display = false;
19578
19817
  element.options.label.enabled = false;
19579
19818
  }
19580
- if (annotation?.enableDrag) {
19819
+ if (isDragActive(chart, annotation)) {
19581
19820
  chart.hoveredAnnotationId = null;
19582
19821
  chart.update("none");
19583
19822
  }
19584
19823
  chart.draw();
19585
19824
  };
19586
19825
  var handleBoxEnter = (element, chart, annotation) => {
19587
- if (annotation?.enableDrag) {
19826
+ if (isDragActive(chart, annotation)) {
19588
19827
  chart.hoveredAnnotationId = element.options.id || null;
19589
19828
  chart.update("none");
19590
19829
  element.options.borderWidth = BORDER_WIDTH.HOVERED;
@@ -19593,7 +19832,7 @@ var handleBoxEnter = (element, chart, annotation) => {
19593
19832
  chart.draw();
19594
19833
  };
19595
19834
  var handleBoxLeave = (element, chart, annotation) => {
19596
- if (annotation?.enableDrag) {
19835
+ if (isDragActive(chart, annotation)) {
19597
19836
  chart.hoveredAnnotationId = null;
19598
19837
  element.options.borderWidth = BORDER_WIDTH.INITIAL;
19599
19838
  chart.canvas.style.cursor = CursorStyle.Initial;
@@ -19602,7 +19841,7 @@ var handleBoxLeave = (element, chart, annotation) => {
19602
19841
  chart.draw();
19603
19842
  };
19604
19843
  var handlePointEnter = (element, chart, annotation) => {
19605
- if (annotation?.enableDrag) {
19844
+ if (isDragActive(chart, annotation)) {
19606
19845
  chart.hoveredAnnotationId = element.options.id || null;
19607
19846
  chart.update("none");
19608
19847
  element.options.borderWidth = BORDER_WIDTH.POINT_HOVERED;
@@ -19611,7 +19850,7 @@ var handlePointEnter = (element, chart, annotation) => {
19611
19850
  chart.draw();
19612
19851
  };
19613
19852
  var handlePointLeave = (element, chart, annotation) => {
19614
- if (annotation?.enableDrag) {
19853
+ if (isDragActive(chart, annotation)) {
19615
19854
  chart.hoveredAnnotationId = null;
19616
19855
  element.options.borderWidth = BORDER_WIDTH.INITIAL;
19617
19856
  chart.canvas.style.cursor = CursorStyle.Initial;
@@ -19620,7 +19859,7 @@ var handlePointLeave = (element, chart, annotation) => {
19620
19859
  chart.draw();
19621
19860
  };
19622
19861
  var handleLabelEnter = (element, chart, annotation) => {
19623
- if (annotation?.enableDrag) {
19862
+ if (isDragActive(chart, annotation)) {
19624
19863
  chart.hoveredAnnotationId = element.options.id || null;
19625
19864
  chart.update("none");
19626
19865
  chart.canvas.style.cursor = CursorStyle.Pointer;
@@ -19628,7 +19867,7 @@ var handleLabelEnter = (element, chart, annotation) => {
19628
19867
  chart.draw();
19629
19868
  };
19630
19869
  var handleLabelLeave = (_element, chart, annotation) => {
19631
- if (annotation?.enableDrag) {
19870
+ if (isDragActive(chart, annotation)) {
19632
19871
  chart.hoveredAnnotationId = null;
19633
19872
  chart.canvas.style.cursor = CursorStyle.Initial;
19634
19873
  chart.update("none");
@@ -19759,25 +19998,41 @@ const generateAnn = (ann, index) => {
19759
19998
  displayDragCoordinates: ann?.displayDragCoordinates ?? true
19760
19999
  };
19761
20000
  };
19762
- var getCalloutAnnotation = (refAnnotation, index) => {
20001
+ var getCalloutAnnotation = (refAnnotation, index, annotationsData, likelyOverlapSet, overlapCalloutYMap, layoutIndex) => {
19763
20002
  const generated = generateAnn(refAnnotation, index);
19764
20003
  if (!generated) return [];
19765
20004
  const { label, ...baseRest } = generated;
19766
20005
  const baseId = baseRest.id;
19767
20006
  const calloutCfg = refAnnotation?.labelConfig?.callout ?? {};
20007
+ const onlyWhenOverlapping = calloutCfg?.onlyWhenOverlapping ?? false;
20008
+ const hideBoxGlyphInOverlapMode = onlyWhenOverlapping && refAnnotation?.type === AnnotationType$1.BOX;
20009
+ const staticShouldShowCallout = likelyOverlapSet.has(index);
20010
+ const shouldShowCallout = (ctx) => {
20011
+ return !onlyWhenOverlapping || staticShouldShowCallout || calloutCfg?.useRuntimeOverlap === true && hasOverlappingLabel(ctx, refAnnotation, index, annotationsData);
20012
+ };
20013
+ const canDisplayCallout = (ctx) => {
20014
+ return (refAnnotation.display ?? true) && shouldShowCallout(ctx) && isCalloutAnchorInChartArea(ctx, refAnnotation, calloutCfg.margin ?? 0);
20015
+ };
19768
20016
  const baseAnnotation = {
19769
20017
  ...baseRest,
19770
- label: { display: false }
20018
+ backgroundColor: hideBoxGlyphInOverlapMode ? TRANSPARENT : baseRest?.backgroundColor,
20019
+ borderWidth: hideBoxGlyphInOverlapMode ? BORDER_WIDTH.ZERO : baseRest?.borderWidth,
20020
+ borderColor: hideBoxGlyphInOverlapMode ? TRANSPARENT : baseRest?.borderColor,
20021
+ label: {
20022
+ ...label,
20023
+ display: (ctx) => (refAnnotation?.display ?? true) && (!calloutCfg?.enabled || !canDisplayCallout(ctx))
20024
+ }
19771
20025
  };
19772
20026
  const color = calloutCfg?.color ?? "hsl(60, 10.34482759%, 12.5%)";
19773
20027
  const font = calloutCfg?.font ?? `12px "Roobert", "Noto Sans", sans-serif`;
19774
20028
  const borderColor = calloutCfg?.borderColor ?? "transparent";
19775
- const strokeStyle = calloutCfg.strokeStyle ?? baseAnnotation.borderColor;
20029
+ const connectorStrokeStyle = calloutCfg.strokeStyle ?? (hideBoxGlyphInOverlapMode ? refAnnotation?.color ?? "hsl(60, 10.34482759%, 12.5%)" : baseAnnotation.borderColor);
19776
20030
  const lineWidth = typeof calloutCfg.lineWidth === "number" ? calloutCfg.lineWidth : 1;
19777
20031
  const startOffset = typeof calloutCfg.startOffset === "number" ? calloutCfg.startOffset : 6;
19778
20032
  const endOffset = typeof calloutCfg.endOffset === "number" ? calloutCfg.endOffset : 1;
19779
20033
  const calloutId = `callout-annotation-${index}`;
19780
- return [baseAnnotation, {
20034
+ const isCalloutDraggable = refAnnotation?.enableDrag !== false;
20035
+ const calloutAnnotation = {
19781
20036
  id: calloutId,
19782
20037
  type: "label",
19783
20038
  backgroundColor: "transparent",
@@ -19785,6 +20040,8 @@ var getCalloutAnnotation = (refAnnotation, index) => {
19785
20040
  color: (ctx) => {
19786
20041
  const chart = getChartFromCtx(ctx);
19787
20042
  if (!chart) return color;
20043
+ const isDragModeEnabled = Boolean(chart?.options?.plugins?.annotationDraggerPlugin?.enabled);
20044
+ if (!isCalloutDraggable || !isDragModeEnabled) return color;
19788
20045
  if (chart.hoveredAnnotationId === calloutId) return "#DB5B00";
19789
20046
  return color;
19790
20047
  },
@@ -19792,27 +20049,38 @@ var getCalloutAnnotation = (refAnnotation, index) => {
19792
20049
  borderColor,
19793
20050
  borderWidth: BORDER_WIDTH.INITIAL,
19794
20051
  padding: 5,
19795
- display: (ctx) => (refAnnotation.display ?? true) && isCalloutAnchorInChartArea(ctx, refAnnotation, calloutCfg.margin ?? 0),
20052
+ display: canDisplayCallout,
19796
20053
  xValue: (ctx) => {
19797
20054
  const persistenceId = getChartFromCtx(ctx)?.options?.persistenceId;
19798
20055
  const stored = getAnnotationPosition(persistenceId, `callout-annotation-${index}`);
19799
20056
  const explicit = typeof calloutCfg.xValue === "number" ? calloutCfg.xValue : void 0;
19800
- return stored?.x ?? explicit ?? resolveCalloutXValue(ctx, refAnnotation, calloutCfg, index);
20057
+ const overlapCalloutAdjust = onlyWhenOverlapping && !calloutCfg?.xAdjust ? getOverlapCalloutXAdjust(refAnnotation) : calloutCfg?.xAdjust;
20058
+ return stored?.x ?? explicit ?? resolveCalloutXValue(ctx, refAnnotation, {
20059
+ ...calloutCfg,
20060
+ xAdjust: overlapCalloutAdjust,
20061
+ layoutIndex
20062
+ }, index);
19801
20063
  },
19802
20064
  yValue: (ctx) => {
19803
20065
  const persistenceId = getChartFromCtx(ctx)?.options?.persistenceId;
19804
20066
  const stored = getAnnotationPosition(persistenceId, `callout-annotation-${index}`);
19805
20067
  const explicit = typeof calloutCfg.yValue === "number" ? calloutCfg.yValue : void 0;
19806
- return stored?.y ?? explicit ?? resolveCalloutYValue(ctx, refAnnotation, calloutCfg, index);
20068
+ const overlapPackedY = onlyWhenOverlapping ? overlapCalloutYMap.get(index) : void 0;
20069
+ const overlapCalloutYAdjust = onlyWhenOverlapping && !calloutCfg?.yAdjust ? 0 : calloutCfg?.yAdjust;
20070
+ return stored?.y ?? explicit ?? overlapPackedY ?? resolveCalloutYValue(ctx, refAnnotation, {
20071
+ ...calloutCfg,
20072
+ yAdjust: overlapCalloutYAdjust,
20073
+ layoutIndex
20074
+ }, index);
19807
20075
  },
19808
20076
  resizable: false,
19809
20077
  displayDragCoordinates: false,
19810
- enableDrag: true,
20078
+ enableDrag: isCalloutDraggable,
19811
20079
  enter: ({ element }, { chart }) => {
19812
- return handleLabelEnter(element, chart, { enableDrag: true });
20080
+ return handleLabelEnter(element, chart, { enableDrag: isCalloutDraggable });
19813
20081
  },
19814
20082
  leave: ({ element }, { chart }) => {
19815
- return handleLabelLeave(element, chart, { enableDrag: true });
20083
+ return handleLabelLeave(element, chart, { enableDrag: isCalloutDraggable });
19816
20084
  },
19817
20085
  onDragStart: calloutCfg?.onDragStart ? () => (coords) => {
19818
20086
  return calloutCfg.onDragStart?.(coords, refAnnotation);
@@ -19826,16 +20094,58 @@ var getCalloutAnnotation = (refAnnotation, index) => {
19826
20094
  calloutConnector: {
19827
20095
  enabled: true,
19828
20096
  fromId: baseId,
19829
- strokeStyle,
20097
+ strokeStyle: connectorStrokeStyle,
19830
20098
  lineWidth,
19831
20099
  startOffset,
19832
20100
  endOffset
19833
20101
  }
19834
- }];
20102
+ };
20103
+ const anchorX = getAnchorValueFromData(refAnnotation, "x");
20104
+ const anchorY = getAnchorValueFromData(refAnnotation, "y");
20105
+ const originTickAnnotation = typeof anchorX === "number" && typeof anchorY === "number" ? {
20106
+ id: `callout-origin-tick-${index}`,
20107
+ type: "line",
20108
+ xMin: anchorX,
20109
+ xMax: (ctx) => {
20110
+ const chart = getChartFromCtx(ctx);
20111
+ const xScale = chart ? getScaleByAxis(chart, "x", refAnnotation) : null;
20112
+ if (!xScale) return anchorX;
20113
+ const px = xScale.getPixelForValue(anchorX);
20114
+ const tickLength = calloutCfg?.originTickLengthPx ?? 8;
20115
+ return xScale.getValueForPixel(px + tickLength);
20116
+ },
20117
+ yMin: anchorY,
20118
+ yMax: anchorY,
20119
+ borderColor: calloutCfg?.originTickColor ?? connectorStrokeStyle,
20120
+ borderWidth: calloutCfg?.originTickWidth ?? 1,
20121
+ borderDash: [],
20122
+ adjustScaleRange: false,
20123
+ label: {
20124
+ display: false,
20125
+ content: ""
20126
+ },
20127
+ display: (ctx) => onlyWhenOverlapping && (refAnnotation.display ?? true) && shouldShowCallout(ctx),
20128
+ resizable: false,
20129
+ displayDragCoordinates: false,
20130
+ enableDrag: false
20131
+ } : null;
20132
+ if (!onlyWhenOverlapping) return [baseAnnotation, calloutAnnotation];
20133
+ return originTickAnnotation ? [
20134
+ baseAnnotation,
20135
+ originTickAnnotation,
20136
+ calloutAnnotation
20137
+ ] : [baseAnnotation, calloutAnnotation];
19835
20138
  };
19836
20139
  var generateAnnotations = (annotationsData) => {
20140
+ const likelyOverlapSet = buildLikelyOverlapSet(annotationsData);
20141
+ const overlapCalloutYMap = buildOverlapCalloutYMap(annotationsData, likelyOverlapSet);
20142
+ let calloutLayoutIndex = 0;
19837
20143
  return annotationsData?.flatMap((ann, idx) => {
19838
- if (ann?.labelConfig?.callout?.enabled ?? false) return getCalloutAnnotation(ann, idx);
20144
+ if (ann?.labelConfig?.callout?.enabled ?? false) {
20145
+ const annotation = getCalloutAnnotation(ann, idx, annotationsData, likelyOverlapSet, overlapCalloutYMap, calloutLayoutIndex);
20146
+ calloutLayoutIndex += 1;
20147
+ return annotation;
20148
+ }
19839
20149
  return generateAnn(ann, idx);
19840
20150
  });
19841
20151
  };