UNPKG

ag-charts-community

Version:

Advanced Charting / Charts supporting Javascript / Typescript / React / Angular / Vue

8,017 lines 266 kB
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __decorateClass = (decorators, target, key, kind) => {
  var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
  for (var i = decorators.length - 1, decorator; i >= 0; i--)
    if (decorator = decorators[i])
      result = (kind ? decorator(target, key, result) : decorator(result)) || result;
  if (kind && result)
    __defProp(target, key, result);
  return result;
};

// packages/ag-charts-community/src/chart/caption.ts
import {
  BaseProperties as BaseProperties2,
  FONT_SIZE,
  Property as Property2,
  ProxyPropertyOnWrite,
  callWithContext,
  createId as createId2,
  isArray as isArray2,
  isSegmentTruncated,
  isTextTruncated,
  toPlainText as toPlainText2,
  toTextString as toTextString2,
  wrapText,
  wrapTextSegments
} from "ag-charts-core";

// packages/ag-charts-community/src/scene/node.ts
import { DeclaredSceneChangeDetection, Logger, createId, createSvgElement, objectsEqual } from "ag-charts-core";

// packages/ag-charts-community/src/scene/bbox.ts
import { boxContains, boxesEqual, clamp, nearestSquared } from "ag-charts-core";

// packages/ag-charts-community/src/util/interpolating.ts
var interpolate = /*#__PURE__*/ Symbol("interpolate");

// packages/ag-charts-community/src/scene/bbox.ts
var _BBox = /*#__PURE__*/ (() => { var _c$0 = class _BBox {
  constructor(x, y, width, height) {
    this.x = x;
    this.y = y;
    this.width = width;
    this.height = height;
  }
  static fromObject({ x, y, width, height }) {
    return new _BBox(x, y, width, height);
  }
  static merge(boxes) {
    let left = Infinity;
    let top = Infinity;
    let right = -Infinity;
    let bottom = -Infinity;
    for (const box of boxes) {
      if (box.x < left) {
        left = box.x;
      }
      if (box.y < top) {
        top = box.y;
      }
      if (end(box.x, box.width) > right) {
        right = end(box.x, box.width);
      }
      if (end(box.y, box.height) > bottom) {
        bottom = end(box.y, box.height);
      }
    }
    return new _BBox(left, top, right - left, bottom - top);
  }
  static nearestBox(x, y, boxes) {
    return nearestSquared(x, y, boxes);
  }
  toDOMRect() {
    return {
      x: this.x,
      y: this.y,
      width: this.width,
      height: this.height,
      top: this.y,
      left: this.x,
      right: end(this.x, this.width),
      bottom: end(this.y, this.height),
      toJSON() {
        return {};
      }
    };
  }
  clone() {
    const { x, y, width, height } = this;
    return new _BBox(x, y, width, height);
  }
  equals(other) {
    return boxesEqual(this, other);
  }
  containsPoint(x, y) {
    return boxContains(this, x, y);
  }
  intersectsWith(other) {
    return !(this.x + this.width <= other.x || other.x + other.width <= this.x || this.y + this.height <= other.y || other.y + other.height <= this.y);
  }
  intersection(other) {
    const x0 = Math.max(this.x, other.x);
    const y0 = Math.max(this.y, other.y);
    const x1 = Math.min(end(this.x, this.width), end(other.x, other.width));
    const y1 = Math.min(end(this.y, this.height), end(other.y, other.height));
    if (x0 > x1 || y0 > y1)
      return;
    return new _BBox(x0, y0, x1 - x0, y1 - y0);
  }
  collidesBBox(other) {
    return this.x < end(other.x, other.width) && end(this.x, this.width) > other.x && this.y < end(other.y, other.height) && end(this.y, this.height) > other.y;
  }
  computeCenter() {
    return { x: this.x + this.width / 2, y: this.y + this.height / 2 };
  }
  isFinite() {
    return Number.isFinite(this.x) && Number.isFinite(this.y) && Number.isFinite(this.width) && Number.isFinite(this.height);
  }
  distanceSquared(x, y) {
    if (this.containsPoint(x, y)) {
      return 0;
    }
    const dx = x - clamp(this.x, x, end(this.x, this.width));
    const dy = y - clamp(this.y, y, end(this.y, this.height));
    return dx * dx + dy * dy;
  }
  shrink(amount, position) {
    if (typeof amount === "number") {
      this.applyMargin(amount, position);
    } else {
      for (const key of Object.keys(amount)) {
        const value = amount[key];
        if (typeof value === "number") {
          this.applyMargin(value, key);
        }
      }
    }
    if (this.width < 0) {
      this.width = 0;
    }
    if (this.height < 0) {
      this.height = 0;
    }
    return this;
  }
  grow(amount, position) {
    if (typeof amount === "number") {
      this.applyMargin(-amount, position);
    } else {
      for (const key of Object.keys(amount)) {
        const value = amount[key];
        if (typeof value === "number") {
          this.applyMargin(-value, key);
        }
      }
    }
    return this;
  }
  applyMargin(value, position) {
    switch (position) {
      case "top":
        this.y += value;
      case "bottom":
        this.height -= value;
        break;
      case "left":
        this.x += value;
      case "right":
        this.width -= value;
        break;
      case "vertical":
        this.y += value;
        this.height -= value * 2;
        break;
      case "horizontal":
        this.x += value;
        this.width -= value * 2;
        break;
      case void 0:
        this.x += value;
        this.y += value;
        this.width -= value * 2;
        this.height -= value * 2;
        break;
    }
  }
  translate(x, y) {
    this.x += x;
    this.y += y;
    return this;
  }
  [interpolate](other, d) {
    return new _BBox(
      this.x * (1 - d) + other.x * d,
      this.y * (1 - d) + other.y * d,
      this.width * (1 - d) + other.width * d,
      this.height * (1 - d) + other.height * d
    );
  }
}; _c$0.zero = Object.freeze(new _c$0(0, 0, 0, 0)); _c$0.NaN = Object.freeze(new _c$0(Number.NaN, Number.NaN, Number.NaN, Number.NaN)); return _c$0; })()
var BBox = _BBox;
function end(x, width) {
  if (x === -Infinity && width === Infinity)
    return Infinity;
  return x + width;
}

// packages/ag-charts-community/src/scene/zIndex.ts
var cmp = (a, b) => Math.sign(a - b);
function compareZIndex(a, b) {
  if (typeof a === "number" && typeof b === "number") {
    return cmp(a, b);
  }
  const aArray = typeof a === "number" ? [a] : a;
  const bArray = typeof b === "number" ? [b] : b;
  const length = Math.min(aArray.length, bArray.length);
  for (let i = 0; i < length; i += 1) {
    const diff = cmp(aArray[i], bArray[i]);
    if (diff !== 0)
      return diff;
  }
  return cmp(aArray.length, bArray.length);
}

// packages/ag-charts-community/src/scene/node.ts
import { SceneChangeDetection } from "ag-charts-core";
var MAX_ERROR_COUNT = 5;
var _Node = /*#__PURE__*/ (() => { var _c$1 = class _Node {
  constructor(options) {
    /** Unique number to allow creation order to be easily determined. */
    this.serialNumber = _Node._nextSerialNumber++;
    this.childNodeCounts = { groups: 0, nonGroups: 0, thisComplexity: 0, complexity: 0 };
    /** Unique node ID in the form `ClassName-NaturalNumber`. */
    this.id = createId(this);
    this.name = void 0;
    this.transitionOut = void 0;
    this.pointerEvents = 0 /* All */;
    this._datum = void 0;
    this._previousDatum = void 0;
    this.scene = void 0;
    this._debugDirtyProperties = void 0;
    this.parentNode = void 0;
    this.cachedBBox = void 0;
    /**
     * To simplify the type system (especially in Selections) we don't have the `Parent` node
     * (one that has children). Instead, we mimic HTML DOM, where any node can have children.
     * But we still need to distinguish regular leaf nodes from container leafs somehow.
     */
    this.isContainerNode = false;
    this.visible = true;
    this.zIndex = 0;
    this.batchLevel = 0;
    this.batchDirty = false;
    this.name = options?.name;
    this.tag = options?.tag ?? Number.NaN;
    this.zIndex = options?.zIndex ?? 0;
    this.scene = options?.scene;
    if (options?.debugDirty ?? _Node._debugEnabled) {
      this._debugDirtyProperties = /* @__PURE__ */ new Map([["__first__", []]]);
    }
  }
  static toSVG(node, width, height) {
    const svg = node?.toSVG();
    if (svg == null || !svg.elements.length && !svg.defs?.length)
      return;
    const root = createSvgElement("svg");
    root.setAttribute("width", String(width));
    root.setAttribute("height", String(height));
    root.setAttribute("viewBox", `0 0 ${width} ${height}`);
    root.setAttribute("overflow", "visible");
    if (svg.defs?.length) {
      const defs = createSvgElement("defs");
      defs.append(...svg.defs);
      root.append(defs);
    }
    root.append(...svg.elements);
    return root.outerHTML;
  }
  static *extractBBoxes(nodes, skipInvisible) {
    for (const n of nodes) {
      if (!skipInvisible || n.visible && !n.transitionOut) {
        const bbox = n.getBBox();
        if (bbox)
          yield bbox;
      }
    }
  }
  /**
   * Some arbitrary data bound to the node.
   */
  get datum() {
    return this._datum;
  }
  set datum(datum) {
    if (this._datum !== datum) {
      this._previousDatum = this._datum;
      this._datum = datum;
    }
  }
  get previousDatum() {
    return this._previousDatum;
  }
  /** @deprecated do not use unsafe non-null assertion (`datum!`), used typed `datum` */
  get unsafeNonNullDatum() {
    return this.datum;
  }
  /** @deprecated do not use `any`, used typed `datum` */
  get unsafeDatum() {
    return this.datum;
  }
  /** @deprecated do not use `any`, used typed `datum` */
  set unsafeDatum(datum) {
    this.datum = datum;
  }
  /** @deprecated do not use `any`, used typed `previousDatum` */
  get unsafePreviousDatum() {
    return this.previousDatum;
  }
  get layerManager() {
    return this.scene?.layersManager;
  }
  get imageLoader() {
    return this.scene?.imageLoader;
  }
  closestDatum() {
    for (const { datum } of this.traverseUp(true)) {
      if (datum != null) {
        return datum;
      }
    }
  }
  /** @deprecated do not use `any` */
  unsafeClosestDatum() {
    return this.closestDatum();
  }
  /** Perform any pre-rendering initialization. */
  preRender(_renderCtx, thisComplexity = 1) {
    this.childNodeCounts.groups = 0;
    this.childNodeCounts.nonGroups = 1;
    this.childNodeCounts.complexity = thisComplexity;
    this.childNodeCounts.thisComplexity = thisComplexity;
    if (this.batchLevel > 0 || this.batchDirty) {
      throw new Error("AG Charts - illegal rendering state; batched update in progress");
    }
    return this.childNodeCounts;
  }
  /** Guaranteed isolated render - if there is any failure, the Canvas2D context is returned to its prior state. */
  isolatedRender(renderCtx) {
    const savedFont = renderCtx.currentFont;
    renderCtx.ctx.save();
    try {
      this.render(renderCtx);
    } catch (e) {
      const errorCount = e.errorCount ?? 1;
      if (errorCount >= MAX_ERROR_COUNT) {
        e.errorCount = errorCount;
        throw e;
      }
      Logger.warnOnce("Error during rendering", e, e.stack);
    } finally {
      renderCtx.ctx.restore();
      renderCtx.currentFont = savedFont;
    }
  }
  render(renderCtx) {
    const { stats } = renderCtx;
    this.debugDirtyProperties();
    if (renderCtx.debugNodeSearch) {
      const idOrName = this.name ?? this.id;
      if (renderCtx.debugNodeSearch.some((v) => typeof v === "string" ? v === idOrName : v.test(idOrName))) {
        renderCtx.debugNodes[this.name ?? this.id] = this;
      }
    }
    if (stats) {
      stats.nodesRendered++;
      stats.opsPerformed += this.childNodeCounts.thisComplexity;
    }
  }
  setScene(scene) {
    this.scene = scene;
  }
  *traverseUp(includeSelf) {
    if (includeSelf) {
      yield this;
    }
    let node = this.parentNode;
    while (node) {
      yield node;
      node = node.parentNode;
    }
  }
  /**
   * Checks if the node is the root (has no parent).
   */
  isRoot() {
    return !this.parentNode;
  }
  removeChild(node) {
    throw new Error(
      `AG Charts - internal error, unknown child node ${node.name ?? node.id} in $${this.name ?? this.id}`
    );
  }
  remove() {
    this.parentNode?.removeChild(this);
  }
  destroy() {
    if (this.parentNode) {
      this.remove();
    }
  }
  batchedUpdate(fn) {
    this.batchLevel++;
    try {
      fn();
    } finally {
      this.batchLevel--;
      if (this.batchLevel === 0 && this.batchDirty) {
        this.markDirty();
        this.batchDirty = false;
      }
    }
  }
  setProperties(styles) {
    this.batchLevel++;
    try {
      const target = this;
      const source = styles;
      const keys = Object.keys(source);
      for (let i = 0, n = keys.length; i < n; i++) {
        const key = keys[i];
        target[key] = source[key];
      }
    } finally {
      this.batchLevel--;
      if (this.batchLevel === 0 && this.batchDirty) {
        this.markDirty();
        this.batchDirty = false;
      }
    }
    return this;
  }
  setPropertiesWithKeys(styles, keys) {
    this.batchLevel++;
    try {
      const target = this;
      const source = styles;
      for (let i = 0, n = keys.length; i < n; i++) {
        const key = keys[i];
        target[key] = source[key];
      }
    } finally {
      this.batchLevel--;
      if (this.batchLevel === 0 && this.batchDirty) {
        this.markDirty();
        this.batchDirty = false;
      }
    }
    return this;
  }
  containsPoint(_x, _y) {
    return false;
  }
  distanceSquared(_x, _y) {
    return Infinity;
  }
  pickNode(x, y) {
    if (!this.visible || this.pointerEvents === 1 /* None */) {
      return;
    }
    if (this.containsPoint(x, y)) {
      return this;
    }
  }
  pickNodes(x, y, into = []) {
    if (!this.visible || this.pointerEvents === 1 /* None */) {
      return into;
    }
    if (this.containsPoint(x, y)) {
      into.push(this);
    }
    return into;
  }
  getBBox() {
    this.cachedBBox ?? (this.cachedBBox = Object.freeze(this.computeBBox()));
    return this.cachedBBox;
  }
  computeBBox() {
    return;
  }
  onChangeDetection(property) {
    this.markDirty(property);
  }
  markDirtyChildrenOrder() {
    this.cachedBBox = void 0;
  }
  markDirty(property) {
    if (this.batchLevel > 0) {
      this.batchDirty = true;
      return;
    }
    if (property != null && this._debugDirtyProperties) {
      this.markDebugProperties(property);
    }
    this.cachedBBox = void 0;
    this.parentNode?.markDirty();
  }
  markDebugProperties(property) {
    const sources = this._debugDirtyProperties?.get(property) ?? [];
    const caller = new Error("Stack trace for property change tracking").stack?.split("\n").filter((line) => {
      return line !== "Error" && !line.includes(".markDebugProperties") && !line.includes(".markDirty") && !line.includes("Object.assign ") && !line.includes(`${this.constructor.name}.`);
    }) ?? "unknown";
    sources.push(caller[0].replace(" at ", "").trim());
    this._debugDirtyProperties?.set(property, sources);
  }
  debugDirtyProperties() {
    if (this._debugDirtyProperties == null)
      return;
    if (!this._debugDirtyProperties.has("__first__")) {
      for (const [property, sources] of this._debugDirtyProperties.entries()) {
        if (sources.length > 1) {
          Logger.logGroup(
            `Property changed multiple times before render: ${this.constructor.name}.${property} (${sources.length}x)`,
            () => {
              for (const source of sources) {
                Logger.log(source);
              }
            }
          );
        }
      }
    }
    this._debugDirtyProperties.clear();
  }
  static handleNodeZIndexChange(target) {
    target.onZIndexChange();
  }
  onZIndexChange() {
    this.parentNode?.markDirtyChildrenOrder();
  }
  /** Override in subclasses that carry a font (Text) or contain font-bearing children (Group). */
  resolveFont() {
    return void 0;
  }
  toSVG() {
    return;
  }
}; _c$1.className = "AbstractNode"; _c$1._nextSerialNumber = 0; _c$1._debugEnabled = false; __decorateClass([
  DeclaredSceneChangeDetection()
], _c$1.prototype, "visible", 2); __decorateClass([
  DeclaredSceneChangeDetection({
    equals: objectsEqual,
    changeCb: _c$1.handleNodeZIndexChange
  })
], _c$1.prototype, "zIndex", 2); return _c$1; })()
var Node = _Node;

// packages/ag-charts-community/src/scene/shape/text.ts
import {
  BLOCK_IMAGE_SPACING,
  Debug as Debug3,
  LineSplitter,
  Logger as Logger8,
  SceneRefChangeDetection,
  blockStripHeight,
  blockStripWidth,
  cachedTextMeasurer,
  createSvgElement as createSvgElement10,
  imageBoxAroundBaseline,
  isArray,
  measureTextSegments,
  resolvePadding,
  toCanvasTextBaseline,
  toFontString,
  toPlainText,
  toTextString
} from "ag-charts-core";

// packages/ag-charts-community/src/scene/group.ts
import { clamp as clamp5, toIterable } from "ag-charts-core";

// packages/ag-charts-community/src/scene/canvas/hdpiOffscreenCanvas.ts
import { getOffscreenCanvas } from "ag-charts-core";

// packages/ag-charts-community/src/scene/util/pixel.ts
var HALF_PIXEL_EPSILON = 1e-8;
function deviceDimension(pixelRatio, value) {
  const scaled = value * pixelRatio;
  const fractional = scaled - Math.floor(scaled);
  const stable = Math.abs(fractional - 0.5) < HALF_PIXEL_EPSILON ? scaled + HALF_PIXEL_EPSILON : scaled;
  return Math.round(stable);
}
function roundToDevicePixel(pixelRatio, value) {
  return deviceDimension(pixelRatio, value) / pixelRatio;
}
function align(pixelRatio, start, length) {
  const alignedStart = roundToDevicePixel(pixelRatio, start);
  if (length == null) {
    return alignedStart;
  } else if (length === 0) {
    return 0;
  } else if (length < 1) {
    return alignAfter(pixelRatio, length);
  }
  return roundToDevicePixel(pixelRatio, length + start) - alignedStart;
}
function alignBefore(pixelRatio, value) {
  return Math.floor(value * pixelRatio) / pixelRatio;
}
function alignAfter(pixelRatio, value) {
  return Math.ceil(value * pixelRatio) / pixelRatio;
}

// packages/ag-charts-community/src/scene/canvas/canvasUtil.ts
import { Debug } from "ag-charts-core";
function clearContext({
  context,
  pixelRatio,
  width,
  height
}) {
  context.save();
  try {
    context.resetTransform();
    context.clearRect(0, 0, Math.ceil(width * pixelRatio), Math.ceil(height * pixelRatio));
  } finally {
    context.restore();
  }
}
function debugContext(ctx) {
  if (Debug.check("canvas")) {
    const save = ctx.save.bind(ctx);
    const restore = ctx.restore.bind(ctx);
    let depth = 0;
    Object.assign(ctx, {
      save() {
        save();
        depth++;
      },
      restore() {
        if (depth === 0) {
          throw new Error("AG Charts - Unable to restore() past depth 0");
        }
        restore();
        depth--;
      },
      verifyDepthZero() {
        if (depth !== 0) {
          throw new Error(`AG Charts - Save/restore depth is non-zero: ${depth}`);
        }
      }
    });
  }
}

// packages/ag-charts-community/src/scene/canvas/hdpiOffscreenCanvas.ts
function canvasDimensions(width, height, pixelRatio) {
  return [deviceDimension(pixelRatio, width), deviceDimension(pixelRatio, height)];
}
var fallbackCanvas;
function getFallbackCanvas() {
  const OffscreenCanvasCtor = getOffscreenCanvas();
  fallbackCanvas ?? (fallbackCanvas = new OffscreenCanvasCtor(1, 1));
  return fallbackCanvas;
}
var HdpiOffscreenCanvas = class {
  constructor(options) {
    const { width, height, pixelRatio, willReadFrequently = false } = options;
    this.width = width;
    this.height = height;
    this.pixelRatio = pixelRatio;
    const [canvasWidth, canvasHeight] = canvasDimensions(width, height, pixelRatio);
    const OffscreenCanvasCtor = getOffscreenCanvas();
    this.canvas = new OffscreenCanvasCtor(canvasWidth, canvasHeight);
    this.context = this.canvas.getContext("2d", { willReadFrequently });
    this.context.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0);
    debugContext(this.context);
  }
  drawImage(context, dx = 0, dy = 0) {
    return context.drawImage(this.canvas, dx, dy);
  }
  transferToImageBitmap() {
    if (this.canvas.width < 1 || this.canvas.height < 1) {
      return getFallbackCanvas().transferToImageBitmap();
    }
    return this.canvas.transferToImageBitmap();
  }
  resize(width, height, pixelRatio) {
    if (!(width > 0 && height > 0))
      return;
    const { canvas, context } = this;
    if (width !== this.width || height !== this.height || pixelRatio !== this.pixelRatio) {
      const [canvasWidth, canvasHeight] = canvasDimensions(width, height, pixelRatio);
      canvas.width = canvasWidth;
      canvas.height = canvasHeight;
    }
    context.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0);
    this.width = width;
    this.height = height;
    this.pixelRatio = pixelRatio;
  }
  clear() {
    clearContext(this);
  }
  destroy() {
    this.canvas.width = 0;
    this.canvas.height = 0;
    this.context.clearRect(0, 0, 0, 0);
    this.canvas = null;
    this.context = null;
    Object.freeze(this);
  }
};

// packages/ag-charts-community/src/scene/shape/shape.ts
import {
  DeclaredSceneChangeDetection as DeclaredSceneChangeDetection2,
  DeclaredSceneObjectChangeDetection,
  SceneArrayChangeDetection,
  SceneObjectChangeDetection,
  TRIPLE_EQ,
  boxesEqual as boxesEqual2,
  clamp as clamp4,
  generateUUID,
  isGradientFill,
  isImageFill,
  isPatternFill,
  isString,
  objectsEqual as objectsEqual2
} from "ag-charts-core";

// packages/ag-charts-community/src/scene/gradient/conicGradient.ts
import {
  createSvgElement as createSvgElement3,
  normalizeAngle360FromDegrees
} from "ag-charts-core";

// packages/ag-charts-community/src/scene/gradient/gradient.ts
import { createSvgElement as createSvgElement2 } from "ag-charts-core";

// packages/ag-charts-community/src/scale/colorScale.ts
import { Color, Logger as Logger2, clamp as clamp3, toNumber } from "ag-charts-core";

// packages/ag-charts-community/src/scale/abstractScale.ts
var AbstractScale = class {
  invertWithPercentage(value) {
    return this.invert(value, true);
  }
  snapshotDomain() {
    return this.domain;
  }
  restoreDomain(snapshot) {
    this.domain = snapshot;
  }
  get domainMin() {
    return this.getDomainMinMax()[0];
  }
  get domainMax() {
    return this.getDomainMinMax()[1];
  }
  ticks(_ticks, _domain, _visibleRange) {
    return void 0;
  }
  niceDomain(_ticks, domain = this.domain) {
    return domain;
  }
  get bandwidth() {
    return void 0;
  }
  get step() {
    return void 0;
  }
  get inset() {
    return void 0;
  }
};

// packages/ag-charts-community/src/scale/invalidating.ts
var Invalidating = (target, propertyKey) => {
  const mappedProperty = Symbol(String(propertyKey));
  target[mappedProperty] = void 0;
  Object.defineProperty(target, propertyKey, {
    get() {
      return this[mappedProperty];
    },
    set(newValue) {
      const oldValue = this[mappedProperty];
      if (oldValue !== newValue) {
        this[mappedProperty] = newValue;
        this.invalid = true;
      }
    },
    enumerable: true,
    configurable: false
  });
};

// packages/ag-charts-community/src/scale/scaleUtil.ts
import { clamp as clamp2, readIntegratedWrappedValue } from "ag-charts-core";
function visibleTickRange(ticks, reversed, visibleRange) {
  if (visibleRange == null || visibleRange[0] === 0 && visibleRange[1] === 1)
    return;
  const vt0 = clamp2(0, Math.floor(visibleRange[0] * ticks.length), ticks.length);
  const vt1 = clamp2(0, Math.ceil(visibleRange[1] * ticks.length), ticks.length);
  const t0 = reversed ? ticks.length - vt1 : vt0;
  const t1 = reversed ? ticks.length - vt0 : vt1;
  return [t0, t1];
}
function filterVisibleTicks(ticks, reversed, visibleRange) {
  const tickRange = visibleTickRange(ticks, reversed, visibleRange);
  if (tickRange == null)
    return { ticks, count: ticks.length, firstTickIndex: 0 };
  const [t0, t1] = tickRange;
  return {
    ticks: ticks.slice(t0, t1),
    count: ticks.length,
    firstTickIndex: t0
  };
}
function unpackDomainMinMax(domain) {
  const min = readIntegratedWrappedValue(domain.at(0));
  const max = readIntegratedWrappedValue(domain.at(-1));
  return min != void 0 && max != void 0 ? [min, max] : [void 0, void 0];
}

// packages/ag-charts-community/src/scale/colorScale.ts
var convertColorStringToOklcha = (v) => {
  const color = Color.fromString(v);
  const [l, c, h] = Color.RGBtoOKLCH(color.r, color.g, color.b);
  return { l, c, h, a: color.a };
};
var delta = 1e-6;
var isAchromatic = (x) => x.c < delta || x.l < delta || x.l > 1 - delta;
var interpolateOklch = (x, y, d) => {
  d = clamp3(0, d, 1);
  let h;
  if (isAchromatic(x)) {
    h = y.h;
  } else if (isAchromatic(y)) {
    h = x.h;
  } else {
    const xH = x.h;
    let yH = y.h;
    const deltaH = y.h - x.h;
    if (deltaH > 180) {
      yH -= 360;
    } else if (deltaH < -180) {
      yH += 360;
    }
    h = xH * (1 - d) + yH * d;
  }
  const c = x.c * (1 - d) + y.c * d;
  const l = x.l * (1 - d) + y.l * d;
  const a = x.a * (1 - d) + y.a * d;
  return Color.fromOKLCH(l, c, h, a);
};
var ColorScale = /*#__PURE__*/ (() => { var _c$2 = class extends AbstractScale {
  constructor() {
    super(...arguments);
    this.type = "color";
    this.defaultTickCount = 0;
    this.invalid = true;
    this.domain = [0, 1];
    this.range = ["red", "blue"];
    this.mode = "continuous";
    this.parsedRange = this.range.map(convertColorStringToOklcha);
  }
  update() {
    const { domain, range: range2 } = this;
    if (domain.length < 2) {
      Logger2.warnOnce("`colorDomain` should have at least 2 values.");
      if (domain.length === 0) {
        domain.push(0, 1);
      } else if (domain.length === 1) {
        domain.push(domain[0] + 1);
      }
    }
    for (let i = 1; i < domain.length; i++) {
      const a = domain[i - 1];
      const b = domain[i];
      if (a > b) {
        Logger2.warnOnce("`colorDomain` values should be supplied in ascending order.");
        domain.sort((a2, b2) => a2 - b2);
        break;
      }
    }
    const expectedLength = this.mode === "discrete" ? domain.length - 1 : domain.length;
    if (range2.length < expectedLength) {
      for (let i = range2.length; i < expectedLength; i++) {
        range2.push(range2.length > 0 ? range2[0] : "black");
      }
    }
    this.parsedRange = this.range.map(convertColorStringToOklcha);
  }
  normalizeDomains(...domains) {
    return { domain: domains.map((d) => d.domain).flat(), animatable: true };
  }
  toDomain() {
    return;
  }
  convert(x) {
    this.refresh();
    const xn = toNumber(x);
    const { domain, range: range2, parsedRange } = this;
    const d0 = domain[0];
    const d1 = domain.at(-1);
    const r0 = range2[0];
    const r1 = range2.at(-1);
    if (xn <= d0) {
      return r0;
    }
    if (xn >= d1) {
      return r1;
    }
    let index;
    let q;
    if (domain.length === 2) {
      const t = (xn - d0) / (d1 - d0);
      const step = 1 / (range2.length - 1);
      index = range2.length <= 2 ? 0 : Math.min(Math.floor(t * (range2.length - 1)), range2.length - 2);
      q = (t - index * step) / step;
    } else {
      for (index = 0; index < domain.length - 2; index++) {
        if (xn < domain[index + 1]) {
          break;
        }
      }
      const a = domain[index];
      const b = domain[index + 1];
      q = (xn - a) / (b - a);
    }
    if (this.mode === "discrete") {
      return range2[index];
    }
    const c0 = parsedRange[index];
    const c1 = parsedRange[index + 1];
    return interpolateOklch(c0, c1, q).toRgbaString();
  }
  invert() {
    return;
  }
  getDomainMinMax() {
    return unpackDomainMinMax(this.domain);
  }
  refresh() {
    if (!this.invalid)
      return;
    this.invalid = false;
    this.update();
    if (this.invalid) {
      Logger2.warnOnce("Expected update to not invalidate scale");
    }
  }
}; __decorateClass([
  Invalidating
], _c$2.prototype, "domain", 2); __decorateClass([
  Invalidating
], _c$2.prototype, "range", 2); __decorateClass([
  Invalidating
], _c$2.prototype, "mode", 2); return _c$2; })()

// packages/ag-charts-community/src/scene/gradient/gradient.ts
var Gradient = class {
  constructor(colorSpace, stops = [], bbox) {
    this.colorSpace = colorSpace;
    this.stops = stops;
    this.bbox = bbox;
    this._cache = void 0;
  }
  createGradient(ctx, shapeBbox, params) {
    const bbox = this.bbox ?? shapeBbox;
    if (!bbox.isFinite()) {
      return;
    }
    if (this._cache?.ctx === ctx && this._cache.bbox.equals(bbox)) {
      return this._cache.gradient;
    }
    const { stops, colorSpace } = this;
    if (stops.length === 0)
      return;
    if (stops.length === 1)
      return stops[0].color;
    let gradient = this.createCanvasGradient(ctx, bbox, params);
    if (gradient == null)
      return;
    const isOkLch = colorSpace === "oklch";
    const step = 0.05;
    let c0 = stops[0];
    gradient.addColorStop(c0.stop, c0.color);
    for (let i = 1; i < stops.length; i += 1) {
      const c1 = stops[i];
      if (isOkLch) {
        const scale = new ColorScale();
        scale.domain = [c0.stop, c1.stop];
        scale.range = [c0.color, c1.color];
        for (let stop = c0.stop + step; stop < c1.stop; stop += step) {
          gradient.addColorStop(stop, scale.convert(stop) ?? "transparent");
        }
      }
      gradient.addColorStop(c1.stop, c1.color);
      c0 = c1;
    }
    if ("createPattern" in gradient) {
      gradient = gradient.createPattern();
    }
    this._cache = { ctx, bbox, gradient };
    return gradient;
  }
  toSvg(shapeBbox) {
    const bbox = this.bbox ?? shapeBbox;
    const gradient = this.createSvgGradient(bbox);
    for (const { stop: offset, color } of this.stops) {
      const stop = createSvgElement2("stop");
      stop.setAttribute("offset", `${offset}`);
      stop.setAttribute("stop-color", `${color}`);
      gradient.appendChild(stop);
    }
    return gradient;
  }
};

// packages/ag-charts-community/src/scene/gradient/conicGradient.ts
var ConicGradient = class extends Gradient {
  constructor(colorSpace, stops, angle = 0, bbox) {
    super(colorSpace, stops, bbox);
    this.angle = angle;
  }
  createCanvasGradient(ctx, bbox, params) {
    const angleOffset = -90;
    const { angle } = this;
    const radians = normalizeAngle360FromDegrees(angle + angleOffset);
    const cx = params?.centerX ?? bbox.x + bbox.width * 0.5;
    const cy = params?.centerY ?? bbox.y + bbox.height * 0.5;
    return ctx.createConicGradient(radians, cx, cy);
  }
  createSvgGradient(_bbox) {
    return createSvgElement3("linearGradient");
  }
};

// packages/ag-charts-community/src/scene/gradient/linearGradient.ts
import {
  createSvgElement as createSvgElement4,
  normalizeAngle360FromDegrees as normalizeAngle360FromDegrees2
} from "ag-charts-core";
var LinearGradient = class extends Gradient {
  constructor(colorSpace, stops, angle = 0, bbox) {
    super(colorSpace, stops, bbox);
    this.angle = angle;
  }
  getGradientPoints(bbox) {
    const angleOffset = 90;
    const { angle } = this;
    const radians = normalizeAngle360FromDegrees2(angle + angleOffset);
    const cos = Math.cos(radians);
    const sin = Math.sin(radians);
    const w = bbox.width;
    const h = bbox.height;
    const cx = bbox.x + w * 0.5;
    const cy = bbox.y + h * 0.5;
    const diagonal = Math.hypot(h, w) / 2;
    const diagonalAngle = Math.atan2(h, w);
    let quarteredAngle;
    if (radians < Math.PI / 2) {
      quarteredAngle = radians;
    } else if (radians < Math.PI) {
      quarteredAngle = Math.PI - radians;
    } else if (radians < 1.5 * Math.PI) {
      quarteredAngle = radians - Math.PI;
    } else {
      quarteredAngle = 2 * Math.PI - radians;
    }
    const l = diagonal * Math.abs(Math.cos(quarteredAngle - diagonalAngle));
    return { x0: cx + cos * l, y0: cy + sin * l, x1: cx - cos * l, y1: cy - sin * l };
  }
  createCanvasGradient(ctx, bbox) {
    const { x0, y0, x1, y1 } = this.getGradientPoints(bbox);
    if (Number.isNaN(x0) || Number.isNaN(y0) || Number.isNaN(x1) || Number.isNaN(y1)) {
      return void 0;
    }
    return ctx.createLinearGradient(x0, y0, x1, y1);
  }
  createSvgGradient(bbox) {
    const { x0, y0, x1, y1 } = this.getGradientPoints(bbox);
    const gradient = createSvgElement4("linearGradient");
    gradient.setAttribute("x1", String(x0));
    gradient.setAttribute("y1", String(y0));
    gradient.setAttribute("x2", String(x1));
    gradient.setAttribute("y2", String(y1));
    gradient.setAttribute("gradientUnits", "userSpaceOnUse");
    return gradient;
  }
};

// packages/ag-charts-community/src/scene/gradient/radialGradient.ts
import { createSvgElement as createSvgElement5 } from "ag-charts-core";
var RadialGradient = class extends Gradient {
  constructor(colorSpace, stops, bbox) {
    super(colorSpace, stops, bbox);
  }
  createCanvasGradient(ctx, bbox, params) {
    const cx = params?.centerX ?? bbox.x + bbox.width * 0.5;
    const cy = params?.centerY ?? bbox.y + bbox.height * 0.5;
    const innerRadius = params?.innerRadius ?? 0;
    const outerRadius = params?.outerRadius ?? Math.hypot(bbox.width * 0.5, bbox.height * 0.5) / Math.SQRT2;
    return ctx.createRadialGradient(cx, cy, innerRadius, cx, cy, outerRadius);
  }
  createSvgGradient(bbox) {
    const cx = bbox.x + bbox.width * 0.5;
    const cy = bbox.y + bbox.height * 0.5;
    const gradient = createSvgElement5("radialGradient");
    gradient.setAttribute("cx", String(cx));
    gradient.setAttribute("cy", String(cy));
    gradient.setAttribute("r", String(Math.hypot(bbox.width * 0.5, bbox.height * 0.5) / Math.SQRT2));
    gradient.setAttribute("gradientUnits", "userSpaceOnUse");
    return gradient;
  }
};

// packages/ag-charts-community/src/scene/gradient/stops.ts
import {
  BaseProperties,
  PropertiesArray,
  Property,
  discreteColorStops,
  resolveStopPositions
} from "ag-charts-core";
var StopProperties = /*#__PURE__*/ (() => { var _c$3 = class extends BaseProperties {
  constructor() {
    super(...arguments);
    this.color = "black";
  }
}; __decorateClass([
  Property
], _c$3.prototype, "stop", 2); __decorateClass([
  Property
], _c$3.prototype, "color", 2); __decorateClass([
  Property
], _c$3.prototype, "name", 2); return _c$3; })()
var ColorScaleProperties = /*#__PURE__*/ (() => { var _c$4 = class extends BaseProperties {
  constructor() {
    super(...arguments);
    this.fills = new PropertiesArray(StopProperties);
    this.mode = "continuous";
  }
}; __decorateClass([
  Property
], _c$4.prototype, "fills", 2); __decorateClass([
  Property
], _c$4.prototype, "domain", 2); __decorateClass([
  Property
], _c$4.prototype, "mode", 2); __decorateClass([
  Property
], _c$4.prototype, "missingDataFill", 2); return _c$4; })()
function getDefaultColorStops(defaultColorStops, fillMode) {
  const stopOffset = fillMode === "discrete" ? 1 : 0;
  const colorStops = defaultColorStops.map(
    (color, index, { length }) => ({
      stop: (index + stopOffset) / (length - 1 + stopOffset),
      color
    })
  );
  return fillMode === "discrete" ? discreteColorStops(colorStops) : colorStops;
}
function getColorStops(baseFills, defaultColorStops, domain, fillMode = "continuous") {
  const fills = baseFills.map(
    (fill) => typeof fill === "string" ? { color: fill } : fill
  );
  if (fills.length === 0) {
    return getDefaultColorStops(defaultColorStops, fillMode);
  }
  const d0 = Math.min(...domain);
  const d1 = Math.max(...domain);
  const isDiscrete = fillMode === "discrete";
  const stops = resolveStopPositions(fills, d0, d1, isDiscrete);
  let lastDefinedColor = fills.find((c) => c.color != null)?.color;
  let colorScale;
  const colorStops = fills.map((fill, i) => {
    let color = fill?.color;
    const stop = Math.max(0, Math.min(1, (stops[i] - d0) / (d1 - d0)));
    if (color != null) {
      lastDefinedColor = color;
    } else if (lastDefinedColor == null) {
      if (colorScale == null) {
        colorScale = new ColorScale();
        colorScale.domain = [0, 1];
        colorScale.range = defaultColorStops;
      }
      color = colorScale.convert(stop);
    } else {
      color = lastDefinedColor;
    }
    return { stop, color };
  });
  return fillMode === "discrete" ? discreteColorStops(colorStops) : colorStops;
}

// packages/ag-charts-community/src/scene/image/image.ts
import {
  Logger as Logger3,
  createSvgElement as createSvgElement6,
  getDOMMatrix,
  normalizeAngle360FromDegrees as normalizeAngle360FromDegrees3
} from "ag-charts-core";
var Image = class {
  constructor(imageLoader, imageOptions) {
    this.imageLoader = imageLoader;
    this._cache = void 0;
    this.url = imageOptions.url;
    this.backgroundFill = imageOptions.backgroundFill ?? "black";
    this.backgroundFillOpacity = imageOptions.backgroundFillOpacity ?? 1;
    this.repeat = imageOptions.repeat ?? "no-repeat";
    this.width = imageOptions.width;
    this.height = imageOptions.height;
    this.fit = imageOptions.fit ?? "stretch";
    this.rotation = imageOptions.rotation ?? 0;
  }
  createCanvasImage(ctx, image, width, height) {
    if (!image)
      return null;
    const [renderedWidth, renderedHeight] = this.getSize(image.width, image.height, width, height);
    if (renderedWidth < 1 || renderedHeight < 1) {
      Logger3.warnOnce("Image fill is too small to render, ignoring.");
      return null;
    }
    return ctx.createPattern(image, this.repeat);
  }
  getSize(imageWidth, imageHeight, width, height) {
    const { fit } = this;
    let dw = imageWidth;
    let dh = imageHeight;
    let scale = 1;
    const shapeAspectRatio = width / height;
    const imageAspectRatio = imageWidth / imageHeight;
    if (fit === "stretch" || imageWidth === 0 || imageHeight === 0) {
      dw = width;
      dh = height;
    } else if (fit === "contain") {
      scale = imageAspectRatio > shapeAspectRatio ? width / imageWidth : height / imageHeight;
    } else if (fit === "cover") {
      scale = imageAspectRatio > shapeAspectRatio ? height / imageHeight : width / imageWidth;
    }
    return [Math.max(1, dw * scale), Math.max(1, dh * scale)];
  }
  setImageTransform(pattern, bbox) {
    if (typeof pattern === "string")
      return;
    const { url, rotation, width, height } = this;
    const image = this.imageLoader?.loadImage(url);
    if (!image) {
      return;
    }
    const angle = normalizeAngle360FromDegrees3(rotation);
    const cos = Math.cos(angle);
    const sin = Math.sin(angle);
    const [renderedWidth, renderedHeight] = this.getSize(
      image.width,
      image.height,
      width ?? bbox.width,
      height ?? bbox.height
    );
    const widthScale = renderedWidth / image.width;
    const heightScale = renderedHeight / image.height;
    const bboxCenterX = bbox.x + bbox.width / 2;
    const bboxCenterY = bbox.y + bbox.height / 2;
    const rotatedW = cos * renderedWidth - sin * renderedHeight;
    const rotatedH = sin * renderedWidth + cos * renderedHeight;
    const shapeCenterX = rotatedW / 2;
    const shapeCenterY = rotatedH / 2;
    const DOMMatrixCtor = getDOMMatrix();
    pattern?.setTransform(
      new DOMMatrixCtor([
        cos * widthScale,
        sin * heightScale,
        -sin * widthScale,
        cos * heightScale,
        bboxCenterX - shapeCenterX,
        bboxCenterY - shapeCenterY
      ])
    );
  }
  createPattern(ctx, shapeWidth, shapeHeight, node) {
    const width = this.width ?? shapeWidth;
    const height = this.height ?? shapeHeight;
    const cache = this._cache;
    if (cache?.ctx === ctx && cache.width === width && cache.height === height) {
      return cache.pattern;
    }
    const image = this.imageLoader?.loadImage(this.url, node);
    const pattern = this.createCanvasImage(ctx, image, width, height);
    if (pattern == null)
      return;
    this._cache = { ctx, pattern, width, height };
    return pattern;
  }
  toSvg(bbox, pixelRatio) {
    const { url, rotation, backgroundFill, backgroundFillOpacity } = this;
    const { x, y, width, height } = bbox;
    const pattern = createSvgElement6("pattern");
    pattern.setAttribute("viewBox", `0 0 ${width} ${height}`);
    pattern.setAttribute("x", String(x));
    pattern.setAttribute("y", String(y));
    pattern.setAttribute("width", String(width));
    pattern.setAttribute("height", String(height));
    pattern.setAttribute("patternUnits", "userSpaceOnUse");
    const rect = createSvgElement6("rect");
    rect.setAttribute("x", "0");
    rect.setAttribute("y", "0");
    rect.setAttribute("width", String(width));
    rect.setAttribute("height", String(height));
    rect.setAttribute("fill", backgroundFill);
    rect.setAttribute("fill-opacity", String(backgroundFillOpacity));
    pattern.appendChild(rect);
    const image = createSvgElement6("image");
    image.setAttribute("href", url);
    image.setAttribute("x", "0");
    image.setAttribute("y", "0");
    image.setAttribute("width", String(width));
    image.setAttribute("height", String(height));
    image.setAttribute("preserveAspectRatio", "none");
    image.setAttribute("transform", `scale(${1 / pixelRatio}) rotate(${rotation}, ${width / 2}, ${height / 2})`);
    pattern.appendChild(image);
    return pattern;
  }
};

// packages/ag-charts-community/src/scene/pattern/pattern.ts
import {
  Logger as Logger5,
  createSvgElement as createSvgElement7,
  getDOMMatrix as getDOMMatrix2,
  normalizeAngle360FromDegrees as normalizeAngle360FromDegrees4
} from "ag-charts-core";

// packages/ag-charts-community/src/scene/extendedPath2D.ts
import {
  bezier2DDistance,
  bezier2DExtrema,
  evaluateBezier,
  getPath2D,
  lineDistanceSquared,
  normalizeAngle360
} from "ag-charts-core";

// packages/ag-charts-community/src/util/svg.ts
import { Logger as Logger4 } from "ag-charts-core";
var commandEx = /^[\t\n\f\r ]*([achlmqstvz])[\t\n\f\r ]*/i;
var coordinateEx = /^[+-]?((\d*\.\d+)|(\d+\.)|(\d+))(e[+-]?\d+)?/i;
var commaEx = /[\t\n\f\r ]*,?[\t\n\f\r ]*/;
var flagEx = /^[01]/;
var pathParams = {
  z: [],
  h: [coordinateEx],
  v: [coordinateEx],
  m: [coordinateEx, coordinateEx],
  l: [coordinateEx, coordinateEx],
  t: [coordinateEx, coordinateEx],
  s: [coordinateEx, coordinateEx, coordinateEx, coordinateEx],
  q: [coordinateEx, coordinateEx, coordinateEx, coordinateEx],
  c: [coordinateEx, coordinateEx, coordinateEx, coordinateEx, coordinateEx, coordinateEx],
  a: [coordinateEx, coordinateEx, coordinateEx, flagEx, flagEx, coordinateEx, coordinateEx]
};
function parseSvg(d) {
  if (!d)
    return;
  const segments = [];
  let i = 0;
  let currentCommand;
  while (i < d.length) {
    const commandMatch = commandEx.exec(d.slice(i));
    let command;
    if (commandMatch == null) {
      if (!currentCommand) {
        Logger4.warnOnce(`Invalid SVG path, error at index ${i}: Missing command.`);
        return;
      }
      command = currentCommand;
    } else {
      command = commandMatch[1];
      i += commandMatch[0].length;
    }
    const segment = parseSegment(command, d, i);
    if (!segment)
      return;
    i = segment[0];
    currentCommand = command;
    segments.push(segment[1]);
  }
  return segments;
}
function parseSegment(command, d, index) {
  const params = pathParams[command.toLocaleLowerCase()];
  const pathSeg = { command, params: [] };
  for (const regex of params) {
    const segment = d.slice(index);
    const match = regex.exec(segment);
    if (match != null) {
      pathSeg.params.push(Number.parseFloat(match[0]));
      index += match[0].length;
      const next = commaEx.exec(segment.slice(match[0].length));
      if (next != null) {
        index += next[0].length;
      }
    } else if (pathSeg.params.length === 1) {
      return [index, pathSeg];
    } else {
      Logger4.warnOnce(
        `Invalid SVG path, error at index ${index}: No path segment parameters for command [${command}]`
      );
      return;
    }
  }
  return [index, pathSeg];
}

// packages/ag-charts-community/src/scene/polyRoots.ts
function linearRoot(a, b) {
  const t = -b / a;
  return a !== 0 && t >= 0 && t <= 1 ? [t] : [];
}
function quadraticRoots(a, b, c, delta3 = 1e-6) {
  if (Math.abs(a) < delta3) {
    return linearRoot(b, c);
  }
  const D = b * b - 4 * a * c;
  const roots = [];
  if (Math.abs(D) < delta3) {
    const t = -b / (2 * a);
    if (t >= 0 && t <= 1) {
      roots.push(t);
    }
  } else if (D > 0) {
    const rD = Math.sqrt(D);
    const t1 = (-b - rD) / (2 * a);
    const t2 = (-b + rD) / (2 * a);
    if (t1 >= 0 && t1 <= 1) {
      roots.push(t1);
    }
    if (t2 >= 0 && t2 <= 1) {
      roots.push(t2);
    }
  }
  return roots;
}
function cubicRoots(a, b, c, d, delta3 = 1e-6) {
  if (Math.abs(a) < delta3) {
    return quadraticRoots(b, c, d, delta3);
  }
  const A = b / a;
  const B = c / a;
  const C = d / a;
  const Q = (3 * B - A * A) / 9;
  const R = (9 * A * B - 27 * C - 2 * A * A * A) / 54;
  const D = Q * Q * Q + R * R;
  const third = 1 / 3;
  const roots = [];
  if (D >= 0) {
    const rD = Math.sqrt(D);
    const S = Math.sign(R + rD) * Math.pow(Math.abs(R + rD), third);
    const T = Math.sign(R - rD) * Math.pow(Math.abs(R - rD), third);
    const Im = Math.abs(Math.sqrt(3) * (S - T) / 2);
    const t = -third * A + (S + T);
    if (t >= 0 && t <= 1) {
      roots.push(t);
    }
    if (Math.abs(Im) < delta3) {
      const t2 = -third * A - (S + T) / 2;
      if (t2 >= 0 && t2 <= 1) {
        roots.push(t2);
      }
    }
  } else {
    const theta = Math.acos(R / Math.sqrt(-Q * Q * Q));
    const thirdA = third * A;
    const twoSqrtQ = 2 * Math.sqrt(-Q);
    const t1 = twoSqrtQ * Math.cos(third * theta) - thirdA;
    const t2 = twoSqrtQ * Math.cos(third * (theta + 2 * Math.PI)) - thirdA;
    const t3 = twoSqrtQ * Math.cos(third * (theta + 4 * Math.PI)) - thirdA;
    if (t1 >= 0 && t1 <= 1) {
      roots.push(t1);
    }
    if (t2 >= 0 && t2 <= 1) {
      roots.push(t2);
    }
    if (t3 >= 0 && t3 <= 1) {
      roots.push(t3);
    }
  }
  return roots;
}

// packages/ag-charts-community/src/scene/intersection.ts
function segmentIntersection(ax1, ay1, ax2, ay2, bx1, by1, bx2, by2) {
  const d = (ax2 - ax1) * (by2 - by1) - (ay2 - ay1) * (bx2 - bx1);
  if (d === 0) {
    return 0;
  }
  const ua = ((bx2 - bx1) * (ay1 - by1) - (ax1 - bx1) * (by2 - by1)) / d;
  const ub = ((ax2 - ax1) * (ay1 - by1) - (ay2 - ay1) * (ax1 - bx1)) / d;
  if (ua >= 0 && ua <= 1 && ub >= 0 && ub <= 1) {
    return 1;
  }
  return 0;
}
function cubicSegmentIntersections(px1, py1, px2, py2, px3, py3, px4, py4, x1, y1, x2, y2) {
  let intersections = 0;
  const A = y1 - y2;
  const B = x2 - x1;
  const C = x1 * (y2 - y1) - y1 * (x2 - x1);
  const bx = bezierCoefficients(px1, px2, px3, px4);
  const by = bezierCoefficients(py1, py2, py3, py4);
  const a = A * bx[0] + B * by[0];
  const b = A * bx[1] + B * by[1];
  const c = A * bx[2] + B * by[2];
  const d = A * bx[3] + B * by[3] + C;
  const roots = cubicRoots(a, b, c, d);
  for (const t of roots) {
    const tt = t * t;
    const ttt = t * tt;
    const x = bx[0] * ttt + bx[1] * tt + bx[2] * t + bx[3];
    const y = by[0] * ttt + by[1] * tt + by[2] * t + by[3];
    let s;
    if (x1 === x2) {
      s = (y - y1) / (y2 - y1);
    } else {
      s = (x - x1) / (x2 - x1);
    }
    if (s >= 0 && s <= 1) {
      intersections++;
    }
  }
  return intersections;
}
function bezierCoefficients(P1, P2, P3, P4) {
  return [
    // Bézier expressed as matrix operations:
    //                 |-1  3 -3  1| |P1|
    //   [t^3 t^2 t 1] | 3 -6  3  0| |P2|
    //                 |-3  3  0  0| |P3|
    //                 | 1  0  0  0| |P4|
    -P1 + 3 * P2 - 3 * P3 + P4,
    3 * P1 - 6 * P2 + 3 * P3,
    -3 * P1 + 3 * P2,
    P1
  ];
}

// packages/ag-charts-community/src/scene/extendedPath2D.ts
var ExtendedPath2D = class {
  constructor() {
    this.previousCommands = [];
    this.previousParams = [];
    this.previousClosedPath = false;
    this.commands = [];
    this.params = [];
    this.commandsLength = 0;
    this.paramsLength = 0;
    this.cx = Number.NaN;
    this.cy = Number.NaN;
    this.sx = Number.NaN;
    this.sy = Number.NaN;
    this.openedPath = false;
    this.closedPath = false;
    const Path2DCtor = getPath2D();
    this.path2d = new Path2DCtor();
  }
  isEmpty() {
    return this.commandsLength === 0;
  }
  isDirty() {
    return this.closedPath !== this.previousClosedPath || this.previousCommands.length !== this.commandsLength || this.previousParams.length !== this.paramsLength || this.previousCommands.toString() !== this.commands.slice(0, this.commandsLength).toString() || this.previousParams.toString() !== this.params.slice(0, this.paramsLength).toString();
  }
  getPath2D() {
    return this.path2d;
  }
  moveTo(x, y) {
    this.openedPath = true;
    this.sx = x;
    this.sy = y;
    this.cx = x;
    this.cy = y;
    this.path2d.moveTo(x, y);
    this.commands[this.commandsLength++] = 0 /* Move */;
    this.params[this.paramsLength++] = x;
    this.params[this.paramsLength++] = y;
  }
  lineTo(x, y) {
    if (this.openedPath) {
      this.cx = x;
      this.cy = y;
      this.path2d.lineTo(x, y);
      this.commands[this.commandsLength++] = 1 /* Line */;
      this.params[this.paramsLength++] = x;
      this.params[this.paramsLength++] = y;
    } else {
      this.moveTo(x, y);
    }
  }
  cubicCurveTo(cx1, cy1, cx2, cy2, x, y) {
    if (!this.openedPath) {
      this.moveTo(cx1, cy1);
    }
    this.path2d.bezierCurveTo(cx1, cy1, cx2, cy2, x, y);
    this.commands[this.commandsLength++] = 2 /* Curve */;
    this.params[this.paramsLength++] = cx1;
    this.params[this.paramsLength++] = cy1;
    this.params[this.paramsLength++] = cx2;
    this.params[this.paramsLength++] = cy2;
    this.params[this.paramsLength++] = x;
    this.params[this.paramsLength++] = y;
  }
  closePath() {
    if (this.openedPath) {
      this.cx = this.sx;
      this.cy = this.sy;
      this.sx = Number.NaN;
      this.sy = Number.NaN;
      this.path2d.closePath();
      this.commands[this.commandsLength++] = 3 /* ClosePath */;
      this.openedPath = false;
      this.closedPath = true;
    }
  }
  rect(x, y, width, height) {
    this.moveTo(x, y);
    this.lineTo(x + width, y);
    this.lineTo(x + width, y + height);
    this.lineTo(x, y + height);
    this.closePath();
  }
  roundRect(x, y, width, height, radii) {
    radii = Math.min(radii, width / 2, height / 2);
    this.moveTo(x, y + radii);
    this.arc(x + radii, y + radii, radii, Math.PI, 1.5 * Math.PI);
    this.lineTo(x + radii, y);
    this.lineTo(x + width - radii, y);
    this.arc(x + width - radii, y + radii, radii, 1.5 * Math.PI, 2 * Math.PI);
    this.lineTo(x + width, y + radii);
    this.lineTo(x + width, y + height - radii);
    this.arc(x + width - radii, y + height - radii, radii, 0, Math.PI / 2);
    this.lineTo(x + width - radii, y + height);
    this.lineTo(x + radii, y + height);
    this.arc(x + +radii, y + height - radii, radii, Math.PI / 2, Math.PI);
    this.lineTo(x, y + height - radii);
    this.closePath();
  }
  ellipse(cx, cy, rx, ry, rotation, sAngle, eAngle, counterClockwise = false) {
    const r = rx;
    const scaleY = ry / rx;
    const mxx = Math.cos(rotation);
    const myx = Math.sin(rotation);
    const mxy = -scaleY * myx;
    const myy = scaleY * mxx;
    const x0 = r * Math.cos(sAngle);
    const y0 = r * Math.sin(sAngle);
    const sx = cx + mxx * x0 + mxy * y0;
    const sy = cy + myx * x0 + myy * y0;
    const distanceSquared = (sx - this.cx) ** 2 + (sy - this.cy) ** 2;
    if (!this.openedPath) {
      this.moveTo(sx, sy);
    } else if (distanceSquared > 1e-6) {
      this.lineTo(sx, sy);
    }
    let sweep = counterClockwise ? -normalizeAngle360(sAngle - eAngle) : normalizeAngle360(eAngle - sAngle);
    if (Math.abs(Math.abs(eAngle - sAngle) - 2 * Math.PI) < 1e-6 && sweep < 2 * Math.PI) {
      sweep += 2 * Math.PI * (counterClockwise ? -1 : 1);
    }
    const arcSections = Math.max(Math.ceil(Math.abs(sweep) / (Math.PI / 2)), 1);
    const step = sweep / arcSections;
    const h = 4 / 3 * Math.tan(step / 4);
    for (let i = 0; i < arcSections; i += 1) {
      const a0 = sAngle + step * (i + 0);
      const a1 = sAngle + step * (i + 1);
      const rSinStart = r * Math.sin(a0);
      const rCosStart = r * Math.cos(a0);
      const rSinEnd = r * Math.sin(a1);
      const rCosEnd = r * Math.cos(a1);
      const cp1x = rCosStart - h * rSinStart;
      const cp1y = rSinStart + h * rCosStart;
      const cp2x = rCosEnd + h * rSinEnd;
      const cp2y = rSinEnd - h * rCosEnd;
      const cp3x = rCosEnd;
      const cp3y = rSinEnd;
      this.cubicCurveTo(
        cx + mxx * cp1x + mxy * cp1y,
        cy + myx * cp1x + myy * cp1y,
        cx + mxx * cp2x + mxy * cp2y,
        cy + myx * cp2x + myy * cp2y,
        cx + mxx * cp3x + mxy * cp3y,
        cy + myx * cp3x + myy * cp3y
      );
    }
  }
  arc(x, y, r, sAngle, eAngle, counterClockwise) {
    this.ellipse(x, y, r, r, 0, sAngle, eAngle, counterClockwise);
  }
  appendSvg(svg) {
    const parts = parseSvg(svg);
    if (parts == null)
      return false;
    let sx = 0;
    let sy = 0;
    let cx;
    let cy;
    let cpx = 0;
    let cpy = 0;
    for (const { command, params } of parts) {
      cx ?? (cx = params[0]);
      cy ?? (cy = params[1]);
      const relative = command === command.toLowerCase();
      const dx = relative ? cx : 0;
      const dy = relative ? cy : 0;
      switch (command.toLowerCase()) {
        case "m":
          this.moveTo(dx + params[0], dy + params[1]);
          cx = dx + params[0];
          cy = dy + params[1];
          sx = cx;
          sy = cy;
          break;
        case "c":
          this.cubicCurveTo(
            dx + params[0],
            dy + params[1],
            dx + params[2],
            dy + params[3],
            dx + params[4],
            dy + params[5]
          );
          cpx = dx + params[2];
          cpy = dy + params[3];
          cx = dx + params[4];
          cy = dy + params[5];
          break;
        case "s":
          this.cubicCurveTo(
            cx + cx - cpx,
            cy + cy - cpy,
            dx + params[0],
            dy + params[1],
            dx + params[2],
            dy + params[3]
          );
          cpx = dx + params[0];
          cpy = dy + params[1];
          cx = dx + params[2];
          cy = dy + params[3];
          break;
        case "q":
          this.cubicCurveTo(
            (dx + 2 * params[0]) / 3,
            (dy + 2 * params[1]) / 3,
            (2 * params[0] + params[2]) / 3,
            (2 * params[1] + params[3]) / 3,
            params[2],
            params[3]
          );
          cpx = params[0];
          cpy = params[1];
          cx = params[2];
          cy = params[3];
          break;
        case "t":
          this.cubicCurveTo(
            (cx + 2 * (cx + cx - cpx)) / 3,
            (cy + 2 * (cy + cy - cpy)) / 3,
            (2 * (cx + cx - cpx) + params[0]) / 3,
            (2 * (cy + cy - cpy) + params[1]) / 3,
            params[0],
            params[1]
          );
          cpx = cx + cx - cpx;
          cpy = cy + cy - cpy;
          cx = params[0];
          cy = params[1];
          break;
        case "a":
          this.svgEllipse(
            cx,
            cy,
            params[0],
            params[1],
            params[2] * Math.PI / 180,
            params[3],
            params[4],
            dx + params[5],
            dy + params[6]
          );
          cx = dx + params[5];
          cy = dy + params[6];
          break;
        case "h":
          this.lineTo(dx + params[0], cy);
          cx = dx + params[0];
          break;
        case "l":
          this.lineTo(dx + params[0], dy + params[1]);
          cx = dx + params[0];
          cy = dy + params[1];
          break;
        case "v":
          this.lineTo(cx, dy + params[0]);
          cy = dy + params[0];
          break;
        case "z":
          this.closePath();
          cx = sx;
          cy = sy;
          break;
        default:
          throw new Error(`Could not translate command '${command}' with '${params.join(" ")}'`);
      }
    }
    return true;
  }
  svgEllipse(x1, y1, rx, ry, rotation, fA, fS, x2, y2) {
    rx = Math.abs(rx);
    ry = Math.abs(ry);
    const dx = (x1 - x2) / 2;
    const dy = (y1 - y2) / 2;
    const sin = Math.sin(rotation);
    const cos = Math.cos(rotation);
    const rotX = cos * dx + sin * dy;
    const rotY = -sin * dx + cos * dy;
    const normX = rotX / rx;
    const normY = rotY / ry;
    let scale = normX * normX + normY * normY;
    let cx = (x1 + x2) / 2;
    let cy = (y1 + y2) / 2;
    let cpx = 0;
    let cpy = 0;
    if (scale >= 1) {
      scale = Math.sqrt(scale);
      rx *= scale;
      ry *= scale;
    } else {
      scale = Math.sqrt(1 / scale - 1);
      if (fA === fS)
        scale = -scale;
      cpx = scale * rx * normY;
      cpy = -scale * ry * normX;
      cx += cos * cpx - sin * cpy;
      cy += sin * cpx + cos * cpy;
    }
    const sAngle = Math.atan2((rotY - cpy) / ry, (rotX - cpx) / rx);
    const deltaTheta = Math.atan2((-rotY - cpy) / ry, (-rotX - cpx) / rx) - sAngle;
    const eAngle = sAngle + deltaTheta;
    const counterClockwise = !!(1 - fS);
    this.ellipse(cx, cy, rx, ry, rotation, sAngle, eAngle, counterClockwise);
  }
  clear(trackChanges) {
    if (trackChanges) {
      this.previousCommands = this.commands.slice(0, this.commandsLength);
      this.previousParams = this.params.slice(0, this.paramsLength);
      this.previousClosedPath = this.closedPath;
      this.commands = [];
      this.params = [];
      this.commandsLength = 0;
      this.paramsLength = 0;
    } else {
      this.commandsLength = 0;
      this.paramsLength = 0;
    }
    const Path2DCtor = getPath2D();
    this.path2d = new Path2DCtor();
    this.openedPath = false;
    this.closedPath = false;
  }
  isPointInPath(x, y) {
    const commands = this.commands;
    const params = this.params;
    const cn = this.commandsLength;
    const ox = -1e4;
    const oy = -1e4;
    let sx = Number.NaN;
    let sy = Number.NaN;
    let px = 0;
    let py = 0;
    let intersectionCount = 0;
    for (let ci = 0, pi = 0; ci < cn; ci++) {
      switch (commands[ci]) {
        case 0 /* Move */:
          intersectionCount += segmentIntersection(sx, sy, px, py, ox, oy, x, y);
          px = params[pi++];
          sx = px;
          py = params[pi++];
          sy = py;
          break;
        case 1 /* Line */:
          intersectionCount += segmentIntersection(px, py, params[pi++], params[pi++], ox, oy, x, y);
          px = params[pi - 2];
          py = params[pi - 1];
          break;
        case 2 /* Curve */:
          intersectionCount += cubicSegmentIntersections(
            px,
            py,
            params[pi++],
            params[pi++],
            params[pi++],
            params[pi++],
            params[pi++],
            params[pi++],
            ox,
            oy,
            x,
            y
          );
          px = params[pi - 2];
          py = params[pi - 1];
          break;
        case 3 /* ClosePath */:
          intersectionCount += segmentIntersection(sx, sy, px, py, ox, oy, x, y);
          break;
      }
    }
    return intersectionCount % 2 === 1;
  }
  distanceSquared(x, y) {
    let best = Infinity;
    const commands = this.commands;
    const params = this.params;
    const cn = this.commandsLength;
    let sx = Number.NaN;
    let sy = Number.NaN;
    let cx = 0;
    let cy = 0;
    for (let ci = 0, pi = 0; ci < cn; ci++) {
      switch (commands[ci]) {
        case 0 /* Move */:
          cx = sx = params[pi++];
          cy = sy = params[pi++];
          break;
        case 1 /* Line */: {
          const x0 = cx;
          const y0 = cy;
          cx = params[pi++];
          cy = params[pi++];
          best = lineDistanceSquared(x, y, x0, y0, cx, cy, best);
          break;
        }
        case 2 /* Curve */: {
          const cp0x = cx;
          const cp0y = cy;
          const cp1x = params[pi++];
          const cp1y = params[pi++];
          const cp2x = params[pi++];
          const cp2y = params[pi++];
          cx = params[pi++];
          cy = params[pi++];
          best = bezier2DDistance(cp0x, cp0y, cp1x, cp1y, cp2x, cp2y, cx, cy, x, y) ** 2;
          break;
        }
        case 3 /* ClosePath */:
          best = lineDistanceSquared(x, y, cx, cy, sx, sy, best);
          break;
      }
    }
    return best;
  }
  // https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/d
  toSVG(transform = (x, y) => ({ x, y })) {
    const buffer = [];
    const { commands, params } = this;
    const addCommand = (command, count) => {
      buffer.push(command);
      for (let i = 0; i < count; i += 2) {
        const { x, y } = transform(params[pi++], params[pi++]);
        buffer.push(x, y);
      }
    };
    let pi = 0;
    for (let ci = 0; ci < this.commandsLength; ci++) {
      const command = commands[ci];
      switch (command) {
        case 0 /* Move */:
          addCommand("M", 2);
          break;
        case 1 /* Line */:
          addCommand("L", 2);
          break;
        case 2 /* Curve */:
          addCommand("C", 6);
          break;
        case 3 /* ClosePath */:
          addCommand("Z", 0);
          break;
      }
    }
    return buffer.join(" ");
  }
  computeBBox() {
    const { commands, params } = this;
    let [top, left, right, bot] = [Infinity, Infinity, -Infinity, -Infinity];
    let [cx, cy] = [Number.NaN, Number.NaN];
    let [sx, sy] = [Number.NaN, Number.NaN];
    const joinPoint = (x, y) => {
      top = Math.min(y, top);
      left = Math.min(x, left);
      right = Math.max(x, right);
      bot = Math.max(y, bot);
      cx = x;
      cy = y;
    };
    let pi = 0;
    for (let ci = 0; ci < this.commandsLength; ci++) {
      const command = commands[ci];
      switch (command) {
        case 0 /* Move */:
          joinPoint(params[pi++], params[pi++]);
          sx = cx;
          sy = cy;
          break;
        case 1 /* Line */:
          joinPoint(params[pi++], params[pi++]);
          break;
        case 2 /* Curve */: {
          const cp0x = cx;
          const cp0y = cy;
          const cp1x = params[pi++];
          const cp1y = params[pi++];
          const cp2x = params[pi++];
          const cp2y = params[pi++];
          const cp3x = params[pi++];
          const cp3y = params[pi++];
          const ts = bezier2DExtrema(cp0x, cp0y, cp1x, cp1y, cp2x, cp2y, cp3x, cp3y);
          for (const t of ts) {
            const px = evaluateBezier(cp0x, cp1x, cp2x, cp3x, t);
            const py = evaluateBezier(cp0y, cp1y, cp2y, cp3y, t);
            joinPoint(px, py);
          }
          joinPoint(cp3x, cp3y);
          break;
        }
        case 3 /* ClosePath */:
          joinPoint(sx, sy);
          sx = Number.NaN;
          sy = Number.NaN;
          break;
      }
    }
    return new BBox(left, top, right - left, bot - top);
  }
};

// packages/ag-charts-community/src/scene/pattern/patterns.ts
import { toRadians } from "ag-charts-core";
function drawPatternUnitPolygon(path, params, moves) {
  const { width, height, padding, strokeWidth } = params;
  const x0 = width / 2;
  const y0 = height / 2;
  const w = Math.max(1, width - padding - strokeWidth / 2);
  const h = Math.max(1, height - padding - strokeWidth / 2);
  let didMove = false;
  for (const [dx, dy] of moves) {
    const x = x0 + (dx - 0.5) * w;
    const y = y0 + (dy - 0.5) * h;
    if (didMove) {
      path.lineTo(x, y);
    } else {
      path.moveTo(x, y);
    }
    didMove = true;
  }
  path.closePath();
}
var PATTERNS = {
  circles(path, { width, strokeWidth, padding }) {
    const c = width / 2;
    const r = Math.max(1, c - padding - strokeWidth / 2);
    path.arc(c, c, r, 0, Math.PI * 2);
  },
  squares(path, { width, height, pixelRatio, padding, strokeWidth }) {
    const offset = padding + strokeWidth / 2;
    path.moveTo(align(pixelRatio, offset), align(pixelRatio, offset));
    path.lineTo(align(pixelRatio, width - offset), align(pixelRatio, offset));
    path.lineTo(align(pixelRatio, width - offset), align(pixelRatio, height - offset));
    path.lineTo(align(pixelRatio, offset), align(pixelRatio, height - offset));
    path.closePath();
  },
  triangles(path, params) {
    drawPatternUnitPolygon(path, params, [
      [0.5, 0],
      [1, 1],
      [0, 1]
    ]);
  },
  diamonds(path, params) {
    drawPatternUnitPolygon(path, params, [
      [0.5, 0],
      [1, 0.5],
      [0.5, 1],
      [0, 0.5]
    ]);
  },
  stars(path, { width, height, padding }) {
    const spikes = 5;
    const outerRadius = Math.max(1, (width - padding) / 2);
    const innerRadius = outerRadius / 2;
    const rotation = Math.PI / 2;
    for (let i = 0; i < spikes * 2; i++) {
      const radius = i % 2 === 0 ? outerRadius : innerRadius;
      const angle = i * Math.PI / spikes - rotation;
      const xCoordinate = width / 2 + Math.cos(angle) * radius;
      const yCoordinate = height / 2 + Math.sin(angle) * radius;
      path.lineTo(xCoordinate, yCoordinate);
    }
    path.closePath();
  },
  hearts(path, { width, height, padding }) {
    const r = Math.max(1, width / 4 - padding / 2);
    const x = width / 2;
    const y = height / 2 + r / 2;
    path.arc(x - r, y - r, r, toRadians(130), toRadians(330));
    path.arc(x + r, y - r, r, toRadians(220), toRadians(50));
    path.lineTo(x, y + r);
    path.closePath();
  },
  crosses(path, params) {
    drawPatternUnitPolygon(path, params, [
      [0.25, 0],
      [0.5, 0.25],
      [0.75, 0],
      [1, 0.25],
      [0.75, 0.5],
      [1, 0.75],
      [0.75, 1],
      [0.5, 0.75],
      [0.25, 1],
      [0, 0.75],
      [0.25, 0.5],
      [0, 0.25]
    ]);
  },
  "vertical-lines"(path, { width, height, pixelRatio, strokeWidth }) {
    const x = align(pixelRatio, width / 2) - strokeWidth % 2 / 2;
    path.moveTo(x, 0);
    path.lineTo(x, height);
  },
  "horizontal-lines"(path, { width, height, pixelRatio, strokeWidth }) {
    const y = align(pixelRatio, height / 2) - strokeWidth % 2 / 2;
    path.moveTo(0, y);
    path.lineTo(width, y);
  },
  "forward-slanted-lines"(path, { width, height, strokeWidth }) {
    const angle = Math.atan2(height, width);
    const insetX = strokeWidth * Math.cos(angle);
    const insetY = strokeWidth * Math.sin(angle);
    path.moveTo(-insetX, insetY);
    path.lineTo(insetX, -insetY);
    path.moveTo(-insetX, height + insetY);
    path.lineTo(width + insetX, -insetY);
    path.moveTo(width - insetX, height + insetY);
    path.lineTo(width + insetX, height - insetY);
  },
  "backward-slanted-lines"(path, { width, height, strokeWidth }) {
    const angle = Math.atan2(height, width);
    const insetX = strokeWidth * Math.cos(angle);
    const insetY = strokeWidth * Math.sin(angle);
    path.moveTo(width - insetX, -insetY);
    path.lineTo(width + insetX, insetY);
    path.moveTo(-insetX, -insetY);
    path.lineTo(width + insetX, height + insetY);
    path.moveTo(-insetX, height - insetY);
    path.lineTo(insetX, height + insetY);
  }
};

// packages/ag-charts-community/src/scene/pattern/pattern.ts
var Pattern = class {
  constructor(patternOptions) {
    this._cache = void 0;
    this.width = Math.max(patternOptions?.width ?? 10, 1);
    this.height = Math.max(patternOptions?.height ?? 10, 1);
    this.fill = patternOptions.fill ?? "none";
    this.fillOpacity = patternOptions.fillOpacity ?? 1;
    this.backgroundFill = patternOptions.backgroundFill ?? "none";
    this.backgroundFillOpacity = patternOptions.backgroundFillOpacity ?? 1;
    this.stroke = patternOptions.stroke ?? "black";
    this.strokeOpacity = patternOptions.strokeOpacity ?? 1;
    this.strokeWidth = patternOptions.strokeWidth ?? 1;
    this.padding = patternOptions.padding ?? 1;
    this.pattern = patternOptions.pattern ?? "forward-slanted-lines";
    this.rotation = patternOptions.rotation ?? 0;
    this.scale = patternOptions.scale ?? 1;
    this.path = patternOptions.path;
  }
  getPath(pixelRatio) {
    const { pattern, width, height, padding, strokeWidth, path: svgPath } = this;
    const path = new ExtendedPath2D();
    let renderPattern = PATTERNS[pattern] != null;
    if (svgPath) {
      renderPattern && (renderPattern = !path.appendSvg(svgPath));
    }
    if (renderPattern) {
      PATTERNS[pattern](path, { width, height, pixelRatio, strokeWidth, padding });
    }
    return path;
  }
  renderStroke(path2d, ctx) {
    const { stroke, strokeWidth, strokeOpacity } = this;
    if (!strokeWidth)
      return;
    ctx.strokeStyle = stroke;
    ctx.lineWidth = strokeWidth;
    ctx.globalAlpha = strokeOpacity;
    ctx.stroke(path2d);
  }
  renderFill(path2d, ctx) {
    const { fill, fillOpacity } = this;
    if (fill === "none") {
      return;
    }
    ctx.fillStyle = fill;
    ctx.globalAlpha = fillOpacity;
    ctx.fill(path2d);
  }
  createCanvasPattern(ctx, pixelRatio) {
    const { width, height, scale, backgroundFill, backgroundFillOpacity } = this;
    if (width * scale < 1 || height * scale < 1) {
      Logger5.warnOnce("Pattern fill is too small to render, ignoring.");
      return null;
    }
    const offscreenPattern = new HdpiOffscreenCanvas({ width, height, pixelRatio: pixelRatio * scale });
    const offscreenPatternCtx = offscreenPattern.context;
    if (backgroundFill !== "none") {
      offscreenPatternCtx.fillStyle = backgroundFill;
      offscreenPatternCtx.globalAlpha = backgroundFillOpacity;
      offscreenPatternCtx.fillRect(0, 0, width, height);
    }
    const path2d = this.getPath(pixelRatio).getPath2D();
    this.renderFill(path2d, offscreenPatternCtx);
    this.renderStroke(path2d, offscreenPatternCtx);
    const pattern = ctx.createPattern(offscreenPattern.canvas, "repeat");
    this.setPatternTransform(pattern, pixelRatio);
    offscreenPattern.destroy();
    return pattern;
  }
  setPatternTransform(pattern, pixelRatio, tx = 0, ty = 0) {
    if (pattern == null)
      return;
    const angle = normalizeAngle360FromDegrees4(this.rotation);
    const scale = 1 / pixelRatio;
    const cos = Math.cos(angle) * scale;
    const sin = Math.sin(angle) * scale;
    const DOMMatrixCtor = getDOMMatrix2();
    pattern.setTransform(new DOMMatrixCtor([cos, sin, -sin, cos, tx, ty]));
  }
  createPattern(ctx, pixelRatio) {
    if (this._cache?.ctx === ctx && this._cache.pixelRatio === pixelRatio) {
      return this._cache.pattern;
    }
    const pattern = this.createCanvasPattern(ctx, pixelRatio);
    if (pattern == null)
      return;
    this._cache = { ctx, pattern, pixelRatio };
    return pattern;
  }
  toSvg() {
    const {
      width,
      height,
      fill,
      fillOpacity,
      backgroundFill,
      backgroundFillOpacity,
      stroke,
      strokeWidth,
      strokeOpacity,
      rotation,
      scale
    } = this;
    const pattern = createSvgElement7("pattern");
    pattern.setAttribute("viewBox", `0 0 ${width} ${height}`);
    pattern.setAttribute("width", String(width));
    pattern.setAttribute("height", String(height));
    pattern.setAttribute("patternUnits", "userSpaceOnUse");
    const rect = createSvgElement7("rect");
    rect.setAttribute("x", "0");
    rect.setAttribute("y", "0");
    rect.setAttribute("width", String(width));
    rect.setAttribute("height", String(height));
    rect.setAttribute("fill", backgroundFill);
    rect.setAttribute("fill-opacity", String(backgroundFillOpacity));
    pattern.appendChild(rect);
    const path = createSvgElement7("path");
    path.setAttribute("fill", fill);
    path.setAttribute("fill-opacity", String(fillOpacity));
    path.setAttribute("stroke-opacity", String(strokeOpacity));
    path.setAttribute("stroke", stroke);
    path.setAttribute("stroke-width", String(strokeWidth));
    path.setAttribute("transform", `rotate(${rotation}) scale(${scale})`);
    path.setAttribute("d", this.getPath(1).toSVG());
    pattern.appendChild(path);
    return pattern;
  }
};

// packages/ag-charts-community/src/scene/shape/svgUtils.ts
function setSvgFontAttributes(element, options) {
  const { fontStyle, fontWeight, fontSize, fontFamily } = options;
  if (fontStyle)
    element.setAttribute("font-style", fontStyle);
  if (fontWeight)
    element.setAttribute("font-weight", String(fontWeight));
  if (fontSize != null)
    element.setAttribute("font-size", String(fontSize));
  if (fontFamily)
    element.setAttribute("font-family", fontFamily);
}
function setSvgStrokeAttributes(element, options) {
  const { stroke, strokeWidth, strokeOpacity } = options;
  if (stroke)
    element.setAttribute("stroke", stroke);
  if (strokeWidth != null)
    element.setAttribute("stroke-width", String(strokeWidth));
  if (strokeOpacity != null)
    element.setAttribute("stroke-opacity", String(strokeOpacity));
}
function setSvgLineDashAttributes(element, options) {
  const { lineDash, lineDashOffset } = options;
  if (lineDash?.some((d) => d !== 0)) {
    const lineDashArray = lineDash.length % 2 === 1 ? [...lineDash, ...lineDash] : lineDash;
    element.setAttribute("stroke-dasharray", lineDashArray.join(" "));
    if (lineDashOffset != null)
      element.setAttribute("stroke-dashoffset", String(lineDashOffset));
  }
}

// packages/ag-charts-community/src/scene/shape/shape.ts
var _Shape = /*#__PURE__*/ (() => { var _c$5 = class _Shape extends Node {
  constructor() {
    super(...arguments);
    this.drawingMode = "overlay";
    this.fillOpacity = 1;
    this.strokeOpacity = 1;
    this.fill = "black";
    this.strokeWidth = 0;
    this.lineDashOffset = 0;
    this.opacity = 1;
  }
  // optimised field accessor
  getGradient(fill) {
    if (isGradientFill(fill))
      return this.createGradient(fill);
  }
  createGradient(fill) {
    const { colorSpace = "rgb", gradient = "linear", colorStops, rotation = 0, reverse = false } = fill;
    if (colorStops == null)
      return;
    let stops = getColorStops(colorStops, ["black"], [0, 1]);
    if (reverse) {
      stops = stops.map((s) => ({ color: s.color, stop: 1 - s.stop })).reverse();
    }
    switch (gradient) {
      case "linear":
        return new LinearGradient(colorSpace, stops, rotation);
      case "radial":
        return new RadialGradient(colorSpace, stops);
      case "conic":
        return new ConicGradient(colorSpace, stops, rotation);
    }
  }
  getPattern(fill) {
    if (isPatternFill(fill))
      return this.createPattern(fill);
  }
  createPattern(fill) {
    return new Pattern(fill);
  }
  getImage(fill) {
    if (isImageFill(fill))
      return this.createImage(fill);
  }
  createImage(fill) {
    return new Image(this.imageLoader, fill);
  }
  onFillChange() {
    if (typeof this.fill === "object") {
      if (objectsEqual2(this._cachedFill ?? {}, this.fill)) {
        return;
      }
    }
    this.fillGradient = this.getGradient(this.fill);
    this.fillPattern = this.getPattern(this.fill);
    this.fillImage = this.getImage(this.fill);
    this._cachedFill = this.fill;
  }
  // optimised field accessor
  onStrokeChange() {
    this.strokeGradient = this.getGradient(this.stroke);
  }
  // optimised field accessor
  /**
   * Returns a device-pixel aligned coordinate (or length if length is supplied).
   *
   * NOTE: Not suitable for strokes, since the stroke needs to be offset to the middle
   * of a device pixel.
   */
  align(start, length) {
    return align(this.layerManager?.canvas?.pixelRatio ?? 1, start, length);
  }
  markDirty(property) {
    super.markDirty(property);
    this.cachedDefaultGradientFillBBox = void 0;
  }
  fillStroke(ctx, path, bboxOverride, fillBBoxOverride) {
    if (this.__drawingMode === "cutout") {
      ctx.globalCompositeOperation = "destination-out";
      this.executeFill(ctx, path);
      ctx.globalCompositeOperation = "source-over";
    }
    this.renderFill(ctx, path, bboxOverride, fillBBoxOverride);
    this.renderStroke(ctx, path, bboxOverride);
  }
  renderFill(ctx, path, bboxOverride, fillBBoxOverride) {
    const { __fill: fill, __fillOpacity: fillOpacity = 1, fillImage } = this;
    if (fill != null && fill !== "none" && fillOpacity > 0) {
      const globalAlpha = ctx.globalAlpha;
      if (fillImage) {
        ctx.globalAlpha = fillImage.backgroundFillOpacity;
        ctx.fillStyle = fillImage.backgroundFill;
        this.executeFill(ctx, path);
        ctx.globalAlpha = globalAlpha;
      }
      this.applyFillAndAlpha(ctx, bboxOverride, fillBBoxOverride);
      this.applyShadow(ctx);
      this.executeFill(ctx, path);
      ctx.globalAlpha = globalAlpha;
      if (this.fillShadow?.enabled) {
        ctx.shadowColor = "rgba(0, 0, 0, 0)";
      }
    }
  }
  executeFill(ctx, path) {
    if (path) {
      ctx.fill(path);
    } else {
      ctx.fill();
    }
  }
  applyFillAndAlpha(ctx, bboxOverride, fillBBoxOverride) {
    const {
      __fill: fill,
      fillGradient,
      fillPattern,
      fillImage,
      __fillOpacity: fillOpacity = 1,
      __opacity: opacity = 1
    } = this;
    const combinedOpacity = opacity * fillOpacity;
    if (combinedOpacity !== 1) {
      ctx.globalAlpha *= combinedOpacity;
    }
    if (fillGradient) {
      const fillBBox = fillBBoxOverride ?? this.fillBBox ?? this.getDefaultGradientFillBBox() ?? bboxOverride ?? this.getBBox();
      const { fillParams } = this;
      ctx.fillStyle = fillGradient.createGradient(ctx, fillBBox, fillParams) ?? "black";
    } else if (fillPattern) {
      const { x, y } = bboxOverride ?? this.getBBox();
      const pixelRatio = this.layerManager?.canvas?.pixelRatio ?? 1;
      const pattern = fillPattern.createPattern(ctx, pixelRatio);
      fillPattern.setPatternTransform(pattern, pixelRatio, x, y);
      if (pattern) {
        ctx.fillStyle = pattern;
      } else {
        ctx.fillStyle = fillPattern.fill;
        ctx.globalAlpha *= fillPattern.fillOpacity;
      }
    } else if (fillImage) {
      const bbox = bboxOverride ?? this.getBBox();
      const image = fillImage.createPattern(ctx, bbox.width, bbox.height, this);
      fillImage.setImageTransform(image, bbox);
      ctx.fillStyle = image ?? "transparent";
    } else {
      ctx.fillStyle = typeof fill === "string" ? fill : "black";
    }
  }
  applyStrokeAndAlpha(ctx, bboxOverride) {
    const { __stroke: stroke, __strokeOpacity: strokeOpacity = 1, strokeGradient, __opacity: opacity = 1 } = this;
    ctx.strokeStyle = strokeGradient?.createGradient(ctx, bboxOverride ?? this.getBBox()) ?? (typeof stroke === "string" ? stroke : void 0) ?? "black";
    const combinedOpacity = opacity * strokeOpacity;
    if (combinedOpacity !== 1) {
      ctx.globalAlpha *= combinedOpacity;
    }
  }
  applyShadow(ctx) {
    const pixelRatio = this.layerManager?.canvas.pixelRatio ?? 1;
    const { __fillShadow: fillShadow } = this;
    if (fillShadow?.enabled) {
      ctx.shadowColor = fillShadow.color;
      ctx.shadowOffsetX = fillShadow.xOffset * pixelRatio;
      ctx.shadowOffsetY = fillShadow.yOffset * pixelRatio;
      ctx.shadowBlur = fillShadow.blur * pixelRatio;
    }
  }
  renderStroke(ctx, path, bboxOverride) {
    const {
      __stroke: stroke,
      __strokeWidth: strokeWidth = 0,
      __strokeOpacity: strokeOpacity = 1,
      __lineDash: lineDash,
      __lineDashOffset: lineDashOffset,
      __lineCap: lineCap,
      __lineJoin: lineJoin,
      __miterLimit: miterLimit
    } = this;
    if (stroke != null && stroke !== "none" && strokeWidth > 0 && strokeOpacity > 0) {
      const { globalAlpha } = ctx;
      this.applyStrokeAndAlpha(ctx, bboxOverride);
      ctx.lineWidth = strokeWidth;
      if (lineDash) {
        ctx.setLineDash(lineDash);
      }
      if (lineDashOffset) {
        ctx.lineDashOffset = lineDashOffset;
      }
      if (lineCap) {
        ctx.lineCap = lineCap;
      }
      if (lineJoin) {
        ctx.lineJoin = lineJoin;
      }
      if (miterLimit != null) {
        ctx.miterLimit = miterLimit;
      }
      this.executeStroke(ctx, path);
      ctx.globalAlpha = globalAlpha;
    }
  }
  executeStroke(ctx, path) {
    if (path) {
      ctx.stroke(path);
    } else {
      ctx.stroke();
    }
  }
  getDefaultGradientFillBBox() {
    this.cachedDefaultGradientFillBBox ?? (this.cachedDefaultGradientFillBBox = Object.freeze(this.computeDefaultGradientFillBBox()));
    return this.cachedDefaultGradientFillBBox;
  }
  computeDefaultGradientFillBBox() {
    return;
  }
  containsPoint(x, y) {
    return this.isPointInPath(x, y);
  }
  applySvgFillAttributes(element, defs) {
    const { fill, fillOpacity } = this;
    if (typeof fill === "string") {
      element.setAttribute("fill", fill);
    } else if (isGradientFill(fill) && this.fillGradient) {
      defs ?? (defs = []);
      const gradient = this.fillGradient.toSvg(this.fillBBox ?? this.getBBox());
      const id = generateUUID();
      gradient.setAttribute("id", id);
      defs.push(gradient);
      element.setAttribute("fill", `url(#${id})`);
    } else if (isPatternFill(fill) && this.fillPattern) {
      defs ?? (defs = []);
      const pattern = this.fillPattern.toSvg();
      const id = generateUUID();
      pattern.setAttribute("id", id);
      defs.push(pattern);
      element.setAttribute("fill", `url(#${id})`);
    } else if (isImageFill(fill) && this.fillImage) {
      defs ?? (defs = []);
      const pixelRatio = this.layerManager?.canvas?.pixelRatio ?? 1;
      const pattern = this.fillImage.toSvg(this.getBBox(), pixelRatio);
      const id = generateUUID();
      pattern.setAttribute("id", id);
      defs.push(pattern);
      element.setAttribute("fill", `url(#${id})`);
    } else {
      element.setAttribute("fill", "none");
    }
    element.setAttribute("fill-opacity", String(fillOpacity));
    return defs;
  }
  applySvgStrokeAttributes(element) {
    const { stroke, strokeOpacity, strokeWidth, lineDash, lineDashOffset } = this;
    setSvgStrokeAttributes(element, { stroke: isString(stroke) ? stroke : void 0, strokeOpacity, strokeWidth });
    setSvgLineDashAttributes(element, { lineDash, lineDashOffset });
  }
  static handleFillChange(shape) {
    shape.onFillChange();
  }
  static handleStrokeChange(shape) {
    shape.onStrokeChange();
  }
  /**
   * Sets style properties on the shape, optimizing by writing directly to __ prefix fields
   * where possible to avoid setter overhead.
   */
  setStyleProperties(style, fillBBox, fillParams) {
    const opacity = style?.opacity ?? 1;
    const fill = style?.fill;
    const computedFillOpacity = (style?.fillOpacity ?? 1) * opacity;
    const computedStrokeOpacity = (style?.strokeOpacity ?? 1) * opacity;
    const computedStrokeWidth = style?.strokeWidth ?? 0;
    const computedLineDashOffset = style?.lineDashOffset ?? 0;
    let hasDirectChanges = false;
    if (this.__fillOpacity !== computedFillOpacity) {
      this.__fillOpacity = computedFillOpacity;
      hasDirectChanges = true;
    }
    if (this.__strokeOpacity !== computedStrokeOpacity) {
      this.__strokeOpacity = computedStrokeOpacity;
      hasDirectChanges = true;
    }
    if (this.__strokeWidth !== computedStrokeWidth) {
      this.__strokeWidth = computedStrokeWidth;
      hasDirectChanges = true;
    }
    if (this.__lineDashOffset !== computedLineDashOffset) {
      this.__lineDashOffset = computedLineDashOffset;
      hasDirectChanges = true;
    }
    if (this.__lineDash !== style?.lineDash) {
      this.__lineDash = style?.lineDash;
      hasDirectChanges = true;
    }
    this.setFillProperties(fill, fillBBox, fillParams);
    if (fill !== this.fill) {
      this.fill = fill;
    }
    if (style?.stroke !== this.stroke) {
      this.stroke = style?.stroke;
    }
    if (hasDirectChanges) {
      this.markDirty();
    }
  }
  /**
   * Sets fill-related properties (fillBBox and fillParams) on the shape.
   * Used for gradient fills that need bounding box information.
   */
  setFillProperties(fill, fillBBox, fillParams) {
    const computedFillBBox = fillBBox == null || !isGradientFill(fill) || fill.bounds == null || fill.bounds === "item" ? void 0 : fillBBox[fill.bounds];
    let hasDirectChanges = false;
    if (this.__fillBBox !== computedFillBBox) {
      this.__fillBBox = computedFillBBox;
      hasDirectChanges = true;
    }
    if (this.__fillParams !== fillParams) {
      this.__fillParams = fillParams;
      hasDirectChanges = true;
    }
    if (hasDirectChanges) {
      this.onFillChange();
      this.markDirty();
    }
  }
}; __decorateClass([
  DeclaredSceneChangeDetection2()
], _c$5.prototype, "drawingMode", 2); __decorateClass([
  DeclaredSceneChangeDetection2()
], _c$5.prototype, "fillOpacity", 2); __decorateClass([
  DeclaredSceneChangeDetection2()
], _c$5.prototype, "strokeOpacity", 2); __decorateClass([
  DeclaredSceneObjectChangeDetection({
    equals: objectsEqual2,
    changeCb: _c$5.handleFillChange
  })
], _c$5.prototype, "fill", 2); __decorateClass([
  SceneObjectChangeDetection({ equals: objectsEqual2, changeCb: _c$5.handleStrokeChange })
], _c$5.prototype, "stroke", 2); __decorateClass([
  DeclaredSceneChangeDetection2()
], _c$5.prototype, "strokeWidth", 2); __decorateClass([
  SceneArrayChangeDetection()
], _c$5.prototype, "lineDash", 2); __decorateClass([
  DeclaredSceneChangeDetection2()
], _c$5.prototype, "lineDashOffset", 2); __decorateClass([
  DeclaredSceneChangeDetection2()
], _c$5.prototype, "lineCap", 2); __decorateClass([
  DeclaredSceneChangeDetection2()
], _c$5.prototype, "lineJoin", 2); __decorateClass([
  DeclaredSceneChangeDetection2()
], _c$5.prototype, "miterLimit", 2); __decorateClass([
  DeclaredSceneChangeDetection2({ convertor: (v) => clamp4(0, v ?? 1, 1) })
], _c$5.prototype, "opacity", 2); __decorateClass([
  SceneObjectChangeDetection({ equals: TRIPLE_EQ, checkDirtyOnAssignment: true })
], _c$5.prototype, "fillShadow", 2); __decorateClass([
  DeclaredSceneObjectChangeDetection({ equals: boxesEqual2, changeCb: (s) => s.onFillChange() })
], _c$5.prototype, "fillBBox", 2); __decorateClass([
  DeclaredSceneObjectChangeDetection({ equals: objectsEqual2, changeCb: (s) => s.onFillChange() })
], _c$5.prototype, "fillParams", 2); return _c$5; })()
var Shape = _Shape;

// packages/ag-charts-community/src/scene/transformable.ts
import { createSvgElement as createSvgElement8 } from "ag-charts-core";

// packages/ag-charts-community/src/scene/matrix.ts
import { isNumberEqual } from "ag-charts-core";
var IDENTITY_MATRIX_ELEMENTS = [1, 0, 0, 1, 0, 0];
var Matrix = class _Matrix {
  get e() {
    return [...this.elements];
  }
  constructor(elements = IDENTITY_MATRIX_ELEMENTS) {
    this.elements = [...elements];
  }
  setElements(elements) {
    const e = this.elements;
    e[0] = elements[0];
    e[1] = elements[1];
    e[2] = elements[2];
    e[3] = elements[3];
    e[4] = elements[4];
    e[5] = elements[5];
    return this;
  }
  get identity() {
    const e = this.elements;
    return isNumberEqual(e[0], 1) && isNumberEqual(e[1], 0) && isNumberEqual(e[2], 0) && isNumberEqual(e[3], 1) && isNumberEqual(e[4], 0) && isNumberEqual(e[5], 0);
  }
  /**
   * Performs the AxB matrix multiplication and saves the result
   * to `C`, if given, or to `A` otherwise.
   */
  AxB(A, B, C) {
    const a = A[0] * B[0] + A[2] * B[1], b = A[1] * B[0] + A[3] * B[1], c = A[0] * B[2] + A[2] * B[3], d = A[1] * B[2] + A[3] * B[3], e = A[0] * B[4] + A[2] * B[5] + A[4], f = A[1] * B[4] + A[3] * B[5] + A[5];
    C = C ?? A;
    C[0] = a;
    C[1] = b;
    C[2] = c;
    C[3] = d;
    C[4] = e;
    C[5] = f;
  }
  /**
   * The `other` matrix gets post-multiplied to the current matrix.
   * Returns the current matrix.
   * @param other
   */
  multiplySelf(other) {
    this.AxB(this.elements, other.elements);
    return this;
  }
  /**
   * The `other` matrix gets post-multiplied to the current matrix.
   * Returns a new matrix.
   * @param other
   */
  multiply(other) {
    const elements = [Number.NaN, Number.NaN, Number.NaN, Number.NaN, Number.NaN, Number.NaN];
    if (other instanceof _Matrix) {
      this.AxB(this.elements, other.elements, elements);
    } else {
      this.AxB(this.elements, [other.a, other.b, other.c, other.d, other.e, other.f], elements);
    }
    return new _Matrix(elements);
  }
  preMultiplySelf(other) {
    this.AxB(other.elements, this.elements, this.elements);
    return this;
  }
  /**
   * Returns the inverse of this matrix as a new matrix.
   */
  inverse() {
    const el = this.elements;
    let a = el[0], b = el[1], c = el[2], d = el[3];
    const e = el[4], f = el[5];
    const rD = 1 / (a * d - b * c);
    a *= rD;
    b *= rD;
    c *= rD;
    d *= rD;
    return new _Matrix([d, -b, -c, a, c * f - d * e, b * e - a * f]);
  }
  invertSelf() {
    const el = this.elements;
    let a = el[0], b = el[1], c = el[2], d = el[3];
    const e = el[4], f = el[5];
    const rD = 1 / (a * d - b * c);
    a *= rD;
    b *= rD;
    c *= rD;
    d *= rD;
    el[0] = d;
    el[1] = -b;
    el[2] = -c;
    el[3] = a;
    el[4] = c * f - d * e;
    el[5] = b * e - a * f;
    return this;
  }
  transformPoint(x, y) {
    const e = this.elements;
    return {
      x: x * e[0] + y * e[2] + e[4],
      y: x * e[1] + y * e[3] + e[5]
    };
  }
  transformBBox(bbox, target) {
    const el = this.elements;
    const xx = el[0];
    const xy = el[1];
    const yx = el[2];
    const yy = el[3];
    const h_w = bbox.width * 0.5;
    const h_h = bbox.height * 0.5;
    const cx = bbox.x + h_w;
    const cy = bbox.y + h_h;
    const w = Math.abs(h_w * xx) + Math.abs(h_h * yx);
    const h = Math.abs(h_w * xy) + Math.abs(h_h * yy);
    target ?? (target = new BBox(0, 0, 0, 0));
    target.x = cx * xx + cy * yx + el[4] - w;
    target.y = cx * xy + cy * yy + el[5] - h;
    target.width = w + w;
    target.height = h + h;
    return target;
  }
  toContext(ctx) {
    if (this.identity) {
      return;
    }
    const e = this.elements;
    ctx.transform(e[0], e[1], e[2], e[3], e[4], e[5]);
  }
  static updateTransformMatrix(matrix, scalingX, scalingY, rotation, translationX, translationY, opts) {
    const sx = scalingX;
    const sy = scalingY;
    let scx;
    let scy;
    if (sx === 1 && sy === 1) {
      scx = 0;
      scy = 0;
    } else {
      scx = opts?.scalingCenterX ?? 0;
      scy = opts?.scalingCenterY ?? 0;
    }
    const r = rotation;
    const cos = Math.cos(r);
    const sin = Math.sin(r);
    let rcx;
    let rcy;
    if (r === 0) {
      rcx = 0;
      rcy = 0;
    } else {
      rcx = opts?.rotationCenterX ?? 0;
      rcy = opts?.rotationCenterY ?? 0;
    }
    const tx = translationX;
    const ty = translationY;
    const tx4 = scx * (1 - sx) - rcx;
    const ty4 = scy * (1 - sy) - rcy;
    matrix.setElements([
      cos * sx,
      sin * sx,
      -sin * sy,
      cos * sy,
      cos * tx4 - sin * ty4 + rcx + tx,
      sin * tx4 + cos * ty4 + rcy + ty
    ]);
    return matrix;
  }
};

// packages/ag-charts-community/src/scene/transformable.ts
function isMatrixTransform(node) {
  return isMatrixTransformType(node.constructor);
}
var MATRIX_TRANSFORM_TYPE = /*#__PURE__*/ Symbol("isMatrixTransform");
function isMatrixTransformType(cstr) {
  return cstr[MATRIX_TRANSFORM_TYPE] === true;
}
function MatrixTransform(Parent) {
  var _a, _b;
  const ParentNode = Parent;
  if (isMatrixTransformType(Parent)) {
    return Parent;
  }
  const TRANSFORM_MATRIX = Symbol("matrix_combined_transform");
  class MatrixTransformInternal extends ParentNode {
    constructor() {
      super(...arguments);
      this[_b] = new Matrix();
      this._dirtyTransform = true;
    }
    onChangeDetection(property) {
      super.onChangeDetection(property);
      this._dirtyTransform = true;
      if (this.batchLevel > 0) {
        return;
      }
      this.markDirty("transform");
    }
    updateMatrix(_matrix) {
    }
    computeTransformMatrix() {
      if (!this._dirtyTransform)
        return;
      this[TRANSFORM_MATRIX].setElements(IDENTITY_MATRIX_ELEMENTS);
      this.updateMatrix(this[TRANSFORM_MATRIX]);
      this._dirtyTransform = false;
    }
    toParent(bbox) {
      this.computeTransformMatrix();
      if (this[TRANSFORM_MATRIX].identity)
        return bbox.clone();
      return this[TRANSFORM_MATRIX].transformBBox(bbox);
    }
    toParentPoint(x, y) {
      this.computeTransformMatrix();
      if (this[TRANSFORM_MATRIX].identity)
        return { x, y };
      return this[TRANSFORM_MATRIX].transformPoint(x, y);
    }
    fromParent(bbox) {
      this.computeTransformMatrix();
      if (this[TRANSFORM_MATRIX].identity)
        return bbox.clone();
      return this[TRANSFORM_MATRIX].inverse().transformBBox(bbox);
    }
    fromParentPoint(x, y) {
      this.computeTransformMatrix();
      if (this[TRANSFORM_MATRIX].identity)
        return { x, y };
      return this[TRANSFORM_MATRIX].inverse().transformPoint(x, y);
    }
    computeBBox() {
      const bbox = super.computeBBox();
      if (!bbox)
        return bbox;
      return this.toParent(bbox);
    }
    computeBBoxWithoutTransforms() {
      return super.computeBBox();
    }
    pickNode(x, y) {
      ({ x, y } = this.fromParentPoint(x, y));
      return super.pickNode(x, y);
    }
    pickNodes(x, y, into) {
      ({ x, y } = this.fromParentPoint(x, y));
      return super.pickNodes(x, y, into);
    }
    distanceSquared(x, y) {
      ({ x, y } = this.fromParentPoint(x, y));
      return super.distanceSquared(x, y);
    }
    render(renderCtx) {
      this.computeTransformMatrix();
      const { ctx } = renderCtx;
      const matrix = this[TRANSFORM_MATRIX];
      let performRestore = false;
      try {
        if (!matrix.identity) {
          ctx.save();
          performRestore = true;
          matrix.toContext(ctx);
        }
        super.render(renderCtx);
      } finally {
        if (performRestore) {
          ctx.restore();
        }
      }
    }
    toSVG() {
      this.computeTransformMatrix();
      const svg = super.toSVG();
      const matrix = this[TRANSFORM_MATRIX];
      if (matrix.identity || svg == null)
        return svg;
      const g = createSvgElement8("g");
      g.append(...svg.elements);
      const [a, b, c, d, e, f] = matrix.e;
      g.setAttribute("transform", `matrix(${a} ${b} ${c} ${d} ${e} ${f})`);
      return {
        elements: [g],
        defs: svg.defs
      };
    }
  }
  _a = MATRIX_TRANSFORM_TYPE, _b = TRANSFORM_MATRIX;
  MatrixTransformInternal[_a] = true;
  return MatrixTransformInternal;
}
function Rotatable(Parent) {
  var _a;
  const ParentNode = Parent;
  const ROTATABLE_MATRIX = Symbol("matrix_rotation");
  class RotatableInternal extends MatrixTransform(ParentNode) {
    constructor() {
      super(...arguments);
      this[_a] = new Matrix();
      this.rotationCenterX = 0;
      this.rotationCenterY = 0;
      this.rotation = 0;
    }
    updateMatrix(matrix) {
      super.updateMatrix(matrix);
      const { rotation, rotationCenterX, rotationCenterY } = this;
      if (rotation === 0)
        return;
      Matrix.updateTransformMatrix(this[ROTATABLE_MATRIX], 1, 1, rotation, 0, 0, {
        rotationCenterX,
        rotationCenterY
      });
      matrix.multiplySelf(this[ROTATABLE_MATRIX]);
    }
  }
  _a = ROTATABLE_MATRIX;
  __decorateClass([
    SceneChangeDetection()
  ], RotatableInternal.prototype, "rotationCenterX", 2);
  __decorateClass([
    SceneChangeDetection()
  ], RotatableInternal.prototype, "rotationCenterY", 2);
  __decorateClass([
    SceneChangeDetection()
  ], RotatableInternal.prototype, "rotation", 2);
  return RotatableInternal;
}
function Scalable(Parent) {
  var _a;
  const ParentNode = Parent;
  const SCALABLE_MATRIX = Symbol("matrix_scale");
  class ScalableInternal extends MatrixTransform(ParentNode) {
    constructor() {
      super(...arguments);
      this[_a] = new Matrix();
      this.scalingX = 1;
      this.scalingY = 1;
      this.scalingCenterX = 0;
      this.scalingCenterY = 0;
    }
    // optimised field accessor
    updateMatrix(matrix) {
      super.updateMatrix(matrix);
      const { scalingX, scalingY, scalingCenterX, scalingCenterY } = this;
      if (scalingX === 1 && scalingY === 1)
        return;
      Matrix.updateTransformMatrix(this[SCALABLE_MATRIX], scalingX, scalingY, 0, 0, 0, {
        scalingCenterX,
        scalingCenterY
      });
      matrix.multiplySelf(this[SCALABLE_MATRIX]);
    }
    /**
     * Optimised reset for animation hot paths.
     * Bypasses SceneChangeDetection decorators by writing directly to backing fields.
     */
    resetScalingProperties(scalingX, scalingY, scalingCenterX, scalingCenterY) {
      this.__scalingX = scalingX;
      this.__scalingY = scalingY;
      this.__scalingCenterX = scalingCenterX;
      this.__scalingCenterY = scalingCenterY;
      this.onChangeDetection("scaling");
    }
  }
  _a = SCALABLE_MATRIX;
  __decorateClass([
    SceneChangeDetection()
  ], ScalableInternal.prototype, "scalingX", 2);
  __decorateClass([
    SceneChangeDetection()
  ], ScalableInternal.prototype, "scalingY", 2);
  __decorateClass([
    SceneChangeDetection()
  ], ScalableInternal.prototype, "scalingCenterX", 2);
  __decorateClass([
    SceneChangeDetection()
  ], ScalableInternal.prototype, "scalingCenterY", 2);
  return ScalableInternal;
}
function Translatable(Parent) {
  var _a;
  const ParentNode = Parent;
  const TRANSLATABLE_MATRIX = Symbol("matrix_translation");
  class TranslatableInternal extends MatrixTransform(ParentNode) {
    constructor() {
      super(...arguments);
      this[_a] = new Matrix();
      this.translationX = 0;
      this.translationY = 0;
    }
    updateMatrix(matrix) {
      super.updateMatrix(matrix);
      const { translationX, translationY } = this;
      if (translationX === 0 && translationY === 0)
        return;
      Matrix.updateTransformMatrix(this[TRANSLATABLE_MATRIX], 1, 1, 0, translationX, translationY);
      matrix.multiplySelf(this[TRANSLATABLE_MATRIX]);
    }
  }
  _a = TRANSLATABLE_MATRIX;
  __decorateClass([
    SceneChangeDetection()
  ], TranslatableInternal.prototype, "translationX", 2);
  __decorateClass([
    SceneChangeDetection()
  ], TranslatableInternal.prototype, "translationY", 2);
  return TranslatableInternal;
}
var Transformable = class {
  /**
   * Converts a BBox from canvas coordinate space into the coordinate space of the given Node.
   */
  static fromCanvas(node, bbox) {
    const parents = [];
    for (const parent of node.traverseUp()) {
      if (isMatrixTransform(parent)) {
        parents.unshift(parent);
      }
    }
    for (const parent of parents) {
      bbox = parent.fromParent(bbox);
    }
    if (isMatrixTransform(node)) {
      bbox = node.fromParent(bbox);
    }
    return bbox;
  }
  /**
   * Converts a Nodes BBox (or an arbitrary BBox if supplied) from local Node coordinate space
   * into the Canvas coordinate space.
   */
  static toCanvas(node, bbox) {
    if (bbox == null) {
      bbox = node.getBBox();
    } else if (isMatrixTransform(node)) {
      bbox = node.toParent(bbox);
    }
    for (const parent of node.traverseUp()) {
      if (isMatrixTransform(parent)) {
        bbox = parent.toParent(bbox);
      }
    }
    return bbox;
  }
  /**
   * Converts a point from canvas coordinate space into the coordinate space of the given Node.
   */
  static fromCanvasPoint(node, x, y) {
    const parents = [];
    for (const parent of node.traverseUp()) {
      if (isMatrixTransform(parent)) {
        parents.unshift(parent);
      }
    }
    for (const parent of parents) {
      ({ x, y } = parent.fromParentPoint(x, y));
    }
    if (isMatrixTransform(node)) {
      ({ x, y } = node.fromParentPoint(x, y));
    }
    return { x, y };
  }
  /**
   * Converts a point from a Nodes local coordinate space into the Canvas coordinate space.
   */
  static toCanvasPoint(node, x, y) {
    if (isMatrixTransform(node)) {
      ({ x, y } = node.toParentPoint(x, y));
    }
    for (const parent of node.traverseUp()) {
      if (isMatrixTransform(parent)) {
        ({ x, y } = parent.toParentPoint(x, y));
      }
    }
    return { x, y };
  }
};

// packages/ag-charts-community/src/scene/group.ts
var sharedOffscreenCanvas;
var _Group = /*#__PURE__*/ (() => { var _c$6 = class _Group extends Node {
  // optimizeForInfrequentRedraws: true
  constructor(opts) {
    super(opts);
    this.childNodes = /* @__PURE__ */ new Set();
    this.dirty = false;
    this.dirtyZIndex = false;
    this.clipRect = void 0;
    this.opacity = 1;
    this._childFontDirty = true;
    // Used when renderToOffscreenCanvas: true
    this.layer = void 0;
    // optimizeForInfrequentRedraws: false
    this.image = void 0;
    this._lastWidth = Number.NaN;
    this._lastHeight = Number.NaN;
    this._lastDevicePixelRatio = Number.NaN;
    this.isContainerNode = true;
    this.renderToOffscreenCanvas = opts?.renderToOffscreenCanvas === true;
    this.optimizeForInfrequentRedraws = opts?.optimizeForInfrequentRedraws === true;
  }
  static is(value) {
    return value instanceof _Group;
  }
  static computeChildrenBBox(nodes, skipInvisible = true) {
    return BBox.merge(Node.extractBBoxes(nodes, skipInvisible));
  }
  static compareChildren(a, b) {
    return compareZIndex(a.__zIndex, b.__zIndex) || a.serialNumber - b.serialNumber;
  }
  // We consider a group to be boundless, thus any point belongs to it.
  containsPoint(_x, _y) {
    return true;
  }
  computeBBox() {
    return _Group.computeChildrenBBox(this.children());
  }
  computeSafeClippingBBox(pixelRatio) {
    const bbox = this.computeBBox();
    if (bbox?.isFinite() !== true)
      return;
    let strokeWidth = 0;
    const strokeMiterAmount = 4;
    for (const child of this.descendants()) {
      if (child instanceof Shape) {
        strokeWidth = Math.max(strokeWidth, child.strokeWidth);
      }
    }
    const padding = Math.max(
      // Account for anti-aliasing artefacts
      1,
      // Account for strokes (incl. miters) - this may not be the best place to include this
      strokeWidth / 2 * strokeMiterAmount
    );
    const { x: originX, y: originY } = Transformable.toCanvasPoint(this, 0, 0);
    const x = alignBefore(pixelRatio, originX + bbox.x - padding) - originX;
    const y = alignBefore(pixelRatio, originY + bbox.y - padding) - originY;
    const width = Math.ceil(bbox.x + bbox.width - x + padding);
    const height = Math.ceil(bbox.y + bbox.height - y + padding);
    return new BBox(x, y, width, height);
  }
  prepareSharedCanvas(width, height, pixelRatio) {
    if (sharedOffscreenCanvas?.pixelRatio === pixelRatio) {
      sharedOffscreenCanvas.resize(width, height, pixelRatio);
    } else {
      sharedOffscreenCanvas = new HdpiOffscreenCanvas({ width, height, pixelRatio });
    }
    return sharedOffscreenCanvas;
  }
  setScene(scene) {
    const previousScene = this.scene;
    super.setScene(scene);
    if (this.layer && previousScene && previousScene !== scene) {
      previousScene.layersManager.removeLayer(this.layer);
      this.layer = void 0;
    }
    for (const child of this.children()) {
      child.setScene(scene);
    }
  }
  resolveFont() {
    if (this.renderToOffscreenCanvas)
      return void 0;
    return this.resolveChildFont();
  }
  resolveChildFont() {
    if (this._childFontDirty) {
      this._cachedChildFont = void 0;
      for (const child of this.children()) {
        const font = child.resolveFont();
        if (font != null) {
          this._cachedChildFont = font;
          break;
        }
      }
      this._childFontDirty = false;
    }
    return this._cachedChildFont;
  }
  markDirty(property) {
    this.dirty = true;
    this._childFontDirty = true;
    super.markDirty(property);
  }
  markDirtyChildrenOrder() {
    super.markDirtyChildrenOrder();
    this.dirtyZIndex = true;
    this.markDirty();
  }
  /**
   * Appends one or more new node instances to this parent.
   * If one needs to:
   * - move a child to the end of the list of children
   * - move a child from one parent to another (including parents in other scenes)
   * one should use the {@link insertBefore} method instead.
   * @param nodes A node or nodes to append.
   */
  append(nodes) {
    for (const node of toIterable(nodes)) {
      node.remove();
      this.childNodes.add(node);
      node.parentNode = this;
      node.setScene(this.scene);
    }
    this.markDirtyChildrenOrder();
    this.markDirty();
  }
  appendChild(node) {
    this.append(node);
    return node;
  }
  removeChild(node) {
    if (!this.childNodes?.delete(node)) {
      throw new Error(
        `AG Charts - internal error, unknown child node ${node.name ?? node.id} in $${this.name ?? this.id}`
      );
    }
    node.parentNode = void 0;
    node.setScene();
    this.markDirtyChildrenOrder();
    this.markDirty();
  }
  clear() {
    for (const child of this.children()) {
      delete child.parentNode;
      child.setScene();
    }
    this.childNodes?.clear();
    this.markDirty();
  }
  /**
   * Hit testing method.
   * Recursively checks if the given point is inside this node or any of its children.
   * Returns the first matching node or `undefined`.
   * Nodes that render later (show on top) are hit tested first.
   */
  pickNode(x, y) {
    if (!this.visible || this.pointerEvents === 1 /* None */ || !this.containsPoint(x, y)) {
      return;
    }
    if (this.childNodes != null && this.childNodes.size !== 0) {
      const children = [...this.children()];
      for (let i = children.length - 1; i >= 0; i--) {
        const child = children[i];
        const hit = child.pickNode(x, y);
        if (hit != null) {
          return hit;
        }
      }
    } else if (!this.isContainerNode) {
      return this;
    }
  }
  pickNodes(x, y, into = []) {
    if (!this.visible || this.pointerEvents === 1 /* None */ || !this.containsPoint(x, y)) {
      return into;
    }
    if (!this.isContainerNode) {
      into.push(this);
    }
    for (const child of this.children()) {
      child.pickNodes(x, y, into);
    }
    return into;
  }
  isDirty(renderCtx) {
    const { width, height, devicePixelRatio } = renderCtx;
    const { dirty, layer } = this;
    const layerResized = layer != null && (this._lastWidth !== width || this._lastHeight !== height);
    const pixelRatioChanged = this._lastDevicePixelRatio !== devicePixelRatio;
    this._lastWidth = width;
    this._lastHeight = height;
    this._lastDevicePixelRatio = devicePixelRatio;
    return dirty || layerResized || pixelRatioChanged;
  }
  preRender(renderCtx) {
    let counts;
    if (this.dirty) {
      counts = super.preRender(renderCtx, 0);
      for (const child of this.children()) {
        const childCounts = child.preRender(renderCtx);
        counts.groups += childCounts.groups;
        counts.nonGroups += childCounts.nonGroups;
        counts.complexity += childCounts.complexity;
      }
      counts.groups += 1;
      counts.nonGroups -= 1;
    } else {
      counts = this.childNodeCounts;
    }
    if (this.renderToOffscreenCanvas && !this.optimizeForInfrequentRedraws && counts.nonGroups > 0 && this.getVisibility()) {
      this.layer ?? (this.layer = this.layerManager?.addLayer({ name: this.name }));
    } else if (this.layer != null) {
      this.layerManager?.removeLayer(this.layer);
      this.layer = void 0;
    }
    return counts;
  }
  render(renderCtx) {
    const { layer, renderToOffscreenCanvas } = this;
    const childRenderCtx = { ...renderCtx };
    const dirty = this.isDirty(renderCtx);
    this.dirty = false;
    if (!renderToOffscreenCanvas) {
      this.renderInContext(childRenderCtx);
      super.render(childRenderCtx);
      return;
    }
    const { ctx, stats, devicePixelRatio: pixelRatio } = renderCtx;
    let { image } = this;
    if (dirty) {
      image?.bitmap.close();
      image = void 0;
      const bbox = layer ? void 0 : this.computeSafeClippingBBox(pixelRatio);
      const renderOffscreen = (offscreenCanvas, ...transform) => {
        const offscreenCtx = offscreenCanvas.context;
        offscreenCtx.direction = childRenderCtx.direction;
        childRenderCtx.ctx = offscreenCtx;
        childRenderCtx.currentFont = void 0;
        offscreenCanvas.clear();
        offscreenCtx.save();
        try {
          offscreenCtx.setTransform(...transform);
          offscreenCtx.globalAlpha = 1;
          this.renderInContext(childRenderCtx);
        } finally {
          offscreenCtx.restore();
          offscreenCtx.verifyDepthZero?.();
        }
      };
      if (layer) {
        renderOffscreen(layer, ctx.getTransform());
      } else if (bbox) {
        const { x, y, width, height } = bbox;
        const scaledWidth = Math.floor(width * pixelRatio);
        const scaledHeight = Math.floor(height * pixelRatio);
        if (scaledWidth > 0 && scaledHeight > 0) {
          const canvas = this.prepareSharedCanvas(width, height, pixelRatio);
          renderOffscreen(canvas, pixelRatio, 0, 0, pixelRatio, -x * pixelRatio, -y * pixelRatio);
          image = { bitmap: canvas.transferToImageBitmap(), x, y, width, height };
        }
      }
      this.image = image;
      if (stats)
        stats.layersRendered++;
    } else if (stats) {
      stats.layersSkipped++;
    }
    const { globalAlpha } = ctx;
    ctx.globalAlpha = globalAlpha * this.opacity;
    if (layer) {
      ctx.save();
      try {
        ctx.resetTransform();
        layer.drawImage(ctx);
      } finally {
        ctx.restore();
      }
    } else if (image) {
      const { bitmap, x, y, width, height } = image;
      ctx.drawImage(bitmap, 0, 0, width * pixelRatio, height * pixelRatio, x, y, width, height);
    }
    ctx.globalAlpha = globalAlpha;
    super.render(childRenderCtx);
  }
  applyClip(ctx, clipRect) {
    const { x, y, width, height } = clipRect;
    ctx.beginPath();
    ctx.rect(x, y, width, height);
    ctx.clip();
  }
  renderInContext(childRenderCtx) {
    const { ctx, stats } = childRenderCtx;
    if (this.dirtyZIndex) {
      this.sortChildren(_Group.compareChildren);
      this.dirtyZIndex = false;
    }
    ctx.save();
    try {
      ctx.globalAlpha *= this.opacity;
      const childFont = this.resolveChildFont();
      if (childFont != null && childRenderCtx.currentFont !== childFont) {
        ctx.font = childFont;
        childRenderCtx.currentFont = childFont;
      }
      if (this.clipRect != null) {
        this.applyClip(ctx, this.clipRect);
        childRenderCtx.clipBBox = Transformable.toCanvas(this, this.clipRect);
      }
      for (const child of this.children()) {
        if (!child.visible) {
          if (stats) {
            stats.nodesSkipped += child.childNodeCounts.nonGroups + child.childNodeCounts.groups;
            stats.opsSkipped += child.childNodeCounts.complexity;
          }
          continue;
        }
        child.isolatedRender(childRenderCtx);
      }
    } finally {
      ctx.restore();
    }
  }
  sortChildren(compareFn) {
    if (!this.childNodes)
      return;
    const sortedChildren = [...this.childNodes].sort(compareFn);
    this.childNodes.clear();
    for (const child of sortedChildren) {
      this.childNodes.add(child);
    }
  }
  *children() {
    yield* this.childNodes;
  }
  *excludeChildren(exclude) {
    for (const child of this.children()) {
      if (exclude.instance && !(child instanceof exclude.instance) || exclude.name && child.name !== exclude.name) {
        yield child;
      }
    }
  }
  *descendants() {
    for (const child of this.children()) {
      yield child;
      if (child instanceof _Group) {
        yield* child.descendants();
      }
    }
  }
  /**
   * Transforms bbox given in the canvas coordinate space to bbox in this group's coordinate space and
   * sets this group's clipRect to the transformed bbox.
   * @param bbox clipRect bbox in the canvas coordinate space.
   */
  setClipRect(bbox) {
    this.clipRect = bbox ? Transformable.fromCanvas(this, bbox) : void 0;
  }
  /**
   * Set the clip rect within the canvas coordinate space.
   * @param bbox clipRect bbox in the canvas coordinate space.
   */
  setClipRectCanvasSpace(bbox) {
    this.clipRect = bbox;
  }
  getVisibility() {
    for (const node of this.traverseUp(true)) {
      if (!node.visible) {
        return false;
      }
    }
    return true;
  }
  toSVG() {
    if (!this.visible)
      return;
    const defs = [];
    const elements = [];
    for (const child of this.children()) {
      const svg = child.toSVG();
      if (svg != null) {
        elements.push(...svg.elements);
        if (svg.defs != null) {
          defs.push(...svg.defs);
        }
      }
    }
    return { elements, defs };
  }
}; _c$6.className = "Group"; __decorateClass([
  SceneChangeDetection({ convertor: (v) => clamp5(0, v, 1) })
], _c$6.prototype, "opacity", 2); return _c$6; })()
var Group = _Group;
var ScalableGroup = /*#__PURE__*/ Scalable(Group);
var RotatableGroup = /*#__PURE__*/ Rotatable(Group);
var TranslatableGroup = /*#__PURE__*/ Translatable(Group);
var TransformableGroup = /*#__PURE__*/ Rotatable(
  Translatable(Group)
);

// packages/ag-charts-community/src/scene/sceneDebug.ts
import { Debug as Debug2, DebugMetrics, Logger as Logger6, TextMeasurer, getWindow, isString as isString2, toArray } from "ag-charts-core";
var StatsAccumulator = class {
  // Log every 10 seconds
  constructor() {
    this.stats = /* @__PURE__ */ new Map();
    this.lastLogTime = Date.now();
    this.LOG_INTERVAL_MS = 1e4;
    this.startPeriodicLogging();
  }
  startPeriodicLogging() {
    if (!Debug2.check("scene:stats" /* SCENE_STATS */, "scene:stats:verbose" /* SCENE_STATS_VERBOSE */)) {
      return;
    }
    this.stopPeriodicLogging();
    this.intervalId = setInterval(() => {
      this.logAccumulatedStats();
    }, this.LOG_INTERVAL_MS);
  }
  stopPeriodicLogging() {
    if (this.intervalId) {
      clearInterval(this.intervalId);
      this.intervalId = void 0;
    }
  }
  recordTiming(category, duration) {
    const existing = this.stats.get(category);
    if (existing) {
      existing.min = Math.min(existing.min, duration);
      existing.max = Math.max(existing.max, duration);
      existing.sum += duration;
      existing.count += 1;
    } else {
      this.stats.set(category, {
        min: duration,
        max: duration,
        sum: duration,
        count: 1
      });
    }
  }
  recordTimings(durations) {
    for (const [category, duration] of Object.entries(durations)) {
      if (category !== "start" && typeof duration === "number") {
        this.recordTiming(category, duration);
      }
    }
  }
  logAccumulatedStats() {
    if (this.stats.size === 0)
      return;
    const timeSinceLastLog = (Date.now() - this.lastLogTime) / 1e3;
    const categories = Array.from(this.stats.keys()).sort((a, b) => {
      if (a === "\u23F1\uFE0F")
        return -1;
      if (b === "\u23F1\uFE0F")
        return 1;
      return a.localeCompare(b);
    });
    const parts = [];
    for (const category of categories) {
      const stats = this.stats.get(category);
      const avg = stats.sum / stats.count;
      parts.push(`${category}[${stats.min.toFixed(1)}/${avg.toFixed(1)}/${stats.max.toFixed(1)}]ms`);
    }
    const totalStats = this.stats.get("\u23F1\uFE0F");
    const count = totalStats?.count ?? 0;
    Logger6.log(`\u{1F4CA} Stats (${timeSinceLastLog.toFixed(0)}s, ${count} renders): ${parts.join(" ")}`);
    this.stats.clear();
    this.lastLogTime = Date.now();
  }
  destroy() {
    this.stopPeriodicLogging();
    this.stats.clear();
  }
};
var globalStatsAccumulator;
var statsAccumulatorConsumers = 0;
function getStatsAccumulator() {
  globalStatsAccumulator ?? (globalStatsAccumulator = new StatsAccumulator());
  return globalStatsAccumulator;
}
function registerDebugStatsConsumer() {
  statsAccumulatorConsumers++;
  let released = false;
  return () => {
    if (released || statsAccumulatorConsumers === 0)
      return;
    released = true;
    statsAccumulatorConsumers--;
    if (statsAccumulatorConsumers === 0) {
      cleanupDebugStats();
    }
  };
}
function formatBytes(value) {
  for (const unit of ["B", "KB", "MB", "GB"]) {
    if (value < 1536) {
      return `${value.toFixed(1)}${unit}`;
    }
    value /= 1024;
  }
  return `${value.toFixed(1)}TB}`;
}
function memoryUsage() {
  if (!("memory" in performance))
    return;
  const { totalJSHeapSize, usedJSHeapSize, jsHeapSizeLimit } = performance.memory;
  const result = [];
  for (const amount of [usedJSHeapSize, totalJSHeapSize, jsHeapSizeLimit]) {
    if (typeof amount !== "number")
      continue;
    result.push(formatBytes(amount));
  }
  return `Heap ${result.join(" / ")}`;
}
function debugStats(layersManager, debugSplitTimes, ctx, renderCtxStats, extraDebugStats = {}, seriesRect = BBox.zero, colors) {
  if (!Debug2.check("scene:stats" /* SCENE_STATS */, "scene:stats:verbose" /* SCENE_STATS_VERBOSE */))
    return;
  const {
    layersRendered = 0,
    layersSkipped = 0,
    nodesRendered = 0,
    nodesSkipped = 0,
    opsPerformed = 0,
    opsSkipped = 0
  } = renderCtxStats ?? {};
  const end2 = performance.now();
  const { start, ...durations } = debugSplitTimes;
  const totalTime = end2 - start;
  const statsAccumulator = getStatsAccumulator();
  statsAccumulator.recordTimings(durations);
  statsAccumulator.recordTiming("\u23F1\uFE0F", totalTime);
  const splits = Object.entries(durations).map(([n, t]) => time(n, t)).filter((v) => v != null).join(" + ");
  const extras = Object.entries(extraDebugStats).map(([k, v]) => `${k}: ${JSON.stringify(v)}`).join(" ; ");
  const detailedStats = Debug2.check("scene:stats:verbose" /* SCENE_STATS_VERBOSE */);
  const memUsage = detailedStats ? memoryUsage() : null;
  const metrics = detailedStats ? DebugMetrics.flush() : {};
  const metricsEntries = Object.entries(metrics);
  const aggregationMetrics = [];
  const nodeDataMetrics = [];
  for (const [k, v] of metricsEntries) {
    if (k.endsWith(":aggregation") && Array.isArray(v)) {
      aggregationMetrics.push(`${k.replace(":aggregation", "")}(${v.join(",")})`);
    } else if (k.endsWith(":nodeData") && typeof v === "number") {
      nodeDataMetrics.push(`${k.replace(":nodeData", "")}(${v})`);
    }
  }
  const aggregationText = aggregationMetrics.length > 0 ? `Aggregation: ${aggregationMetrics.join(", ")}` : null;
  const nodeDataText = nodeDataMetrics.length > 0 ? `NodeData: ${nodeDataMetrics.join(", ")}` : null;
  const stats = [
    `${time("\u23F1\uFE0F", start, end2)} (${splits})`,
    `${extras}`,
    aggregationText,
    nodeDataText,
    `Layers: ${detailedStats ? pct(layersRendered, layersSkipped) : layersManager.size}`,
    detailedStats ? `Nodes: ${pct(nodesRendered, nodesSkipped)}` : null,
    detailedStats ? `Ops: ${pct(opsPerformed, opsSkipped)}` : null,
    memUsage
  ].filter(isString2);
  const measurer = new TextMeasurer(ctx);
  const statsSize = new Map(stats.map((t) => [t, measurer.measureText(t)]));
  const width = Math.max(...Array.from(statsSize.values(), (s) => s.width));
  const height = accumulate(statsSize.values(), (s) => s.height);
  const x = 2 + seriesRect.x;
  ctx.save();
  try {
    ctx.fillStyle = colors?.background ?? "white";
    ctx.fillRect(x, 0, width, height);
    ctx.fillStyle = colors?.foreground ?? "black";
    let y = 0;
    for (const [stat, size] of statsSize.entries()) {
      y += size.height;
      ctx.fillText(stat, x, y);
    }
  } catch (e) {
    Logger6.warnOnce("Error during debug stats rendering", e);
  } finally {
    ctx.restore();
  }
}
function prepareSceneNodeHighlight(ctx) {
  const config = toArray(getWindow("agChartsSceneDebug"));
  const result = [];
  for (const name of config) {
    if (name === "layout") {
      result.push("seriesRoot", "legend", "root", /Axis-\d+-axis/);
    } else {
      result.push(name);
    }
  }
  ctx.debugNodeSearch = result;
}
function debugSceneNodeHighlight(ctx, debugNodes) {
  ctx.save();
  try {
    for (const [name, node] of Object.entries(debugNodes)) {
      const bbox = Transformable.toCanvas(node);
      if (!bbox) {
        Logger6.log(`Scene.render() - no bbox for debugged node [${name}].`);
        continue;
      }
      ctx.globalAlpha = 0.8;
      ctx.strokeStyle = "red";
      ctx.lineWidth = 1;
      ctx.strokeRect(bbox.x, bbox.y, bbox.width, bbox.height);
      ctx.fillStyle = "red";
      ctx.strokeStyle = "white";
      ctx.font = "16px sans-serif";
      ctx.textBaseline = "top";
      ctx.textAlign = "left";
      ctx.lineWidth = 2;
      ctx.strokeText(name, bbox.x, bbox.y, bbox.width);
      ctx.fillText(name, bbox.x, bbox.y, bbox.width);
    }
  } catch (e) {
    Logger6.warnOnce("Error during debug rendering", e);
  } finally {
    ctx.restore();
  }
}
var skippedProperties = /* @__PURE__ */ /*#__PURE__*/ new Set();
var allowedProperties = /* @__PURE__ */ /*#__PURE__*/ new Set([
  "gradient",
  // '_datum',
  "zIndex",
  "clipRect",
  "cachedBBox",
  "childNodeCounts",
  "path",
  "__zIndex",
  "name",
  "__scalingCenterX",
  "__scalingCenterY",
  "__rotationCenterX",
  "__rotationCenterY",
  "_previousDatum",
  "__fill",
  "__lineDash",
  "borderPath",
  "borderClipPath",
  "_clipPath"
]);
function nodeProps(node) {
  const { ...allProps } = node;
  for (const prop of Object.keys(allProps)) {
    if (allowedProperties.has(prop))
      continue;
    if (typeof allProps[prop] === "number")
      continue;
    if (typeof allProps[prop] === "string")
      continue;
    if (typeof allProps[prop] === "boolean")
      continue;
    skippedProperties.add(prop);
    delete allProps[prop];
  }
  return allProps;
}
function buildTree(node, mode) {
  if (!Debug2.check(true, "scene" /* SCENE */)) {
    return {};
  }
  let order = 0;
  return {
    node: mode === "json" ? nodeProps(node) : node,
    name: node.name ?? node.id,
    dirty: node instanceof Group ? node.dirty : void 0,
    ...Array.from(node instanceof Group ? node.children() : [], (c) => buildTree(c, mode)).reduce((result, childTree) => {
      let { name: treeNodeName } = childTree;
      const {
        node: { visible, opacity, zIndex, translationX, translationY, rotation, scalingX, scalingY },
        node: childNode
      } = childTree;
      if (!visible || opacity <= 0) {
        treeNodeName = `(${treeNodeName})`;
      }
      if (Group.is(childNode) && childNode.renderToOffscreenCanvas) {
        treeNodeName = `*${treeNodeName}*`;
      }
      const zIndexString = Array.isArray(zIndex) ? `(${zIndex.join(", ")})` : zIndex;
      const key = [
        `${(order++).toString().padStart(3, "0")}|`,
        `${treeNodeName ?? "<unknown>"}`,
        `z: ${zIndexString}`,
        translationX && `x: ${translationX}`,
        translationY && `y: ${translationY}`,
        rotation && `r: ${rotation}`,
        scalingX != null && scalingX !== 1 && `sx: ${scalingX}`,
        scalingY != null && scalingY !== 1 && `sy: ${scalingY}`
      ].filter((v) => !!v).join(" ");
      let selectedKey = key;
      let index = 1;
      while (result[selectedKey] != null && index < 100) {
        selectedKey = `${key} (${index++})`;
      }
      result[selectedKey] = childTree;
      return result;
    }, {})
  };
}
function buildDirtyTree(node) {
  const nodeDirty = node instanceof Group ? node.dirty : void 0;
  if (!nodeDirty) {
    return { dirtyTree: {}, paths: [] };
  }
  const childrenDirtyTree = Array.from(node instanceof Group ? node.children() : [], (c) => buildDirtyTree(c)).filter(
    (c) => c.paths.length > 0
  );
  const name = Group.is(node) ? node.name ?? node.id : node.id;
  const paths = childrenDirtyTree.length ? childrenDirtyTree.flatMap((c) => c.paths).map((p) => `${name}.${p}`) : [name];
  return {
    dirtyTree: {
      name,
      node,
      dirty: nodeDirty,
      ...childrenDirtyTree.map((c) => c.dirtyTree).filter((t) => t.dirty != null).reduce((result, childTree) => {
        result[childTree.name ?? "<unknown>"] = childTree;
        return result;
      }, {})
    },
    paths
  };
}
function pct(rendered, skipped) {
  const total = rendered + skipped;
  return `${rendered} / ${total} (${Math.round(100 * rendered / total)}%)`;
}
function time(name, start, end2) {
  const duration = end2 == null ? start : end2 - start;
  return `${name}: ${Math.round(duration * 100) / 100}ms`;
}
function accumulate(iterator, mapper) {
  let sum = 0;
  for (const item of iterator) {
    sum += mapper(item);
  }
  return sum;
}
function cleanupDebugStats(force = false) {
  if (!globalStatsAccumulator) {
    if (force) {
      statsAccumulatorConsumers = 0;
    }
    return;
  }
  if (!force && statsAccumulatorConsumers > 0) {
    return;
  }
  globalStatsAccumulator.destroy();
  globalStatsAccumulator = void 0;
  if (force) {
    statsAccumulatorConsumers = 0;
  }
}

// packages/ag-charts-community/src/scene/shape/imageSegmentNode.ts
import { Logger as Logger7 } from "ag-charts-core";
var ImageSegmentNode = /*#__PURE__*/ (() => { var _c$7 = class extends Node {
  constructor() {
    super(...arguments);
    this.x = 0;
    this.y = 0;
    this.boxWidth = 0;
    this.boxHeight = 0;
    this.imageWidth = 0;
    this.imageHeight = 0;
    this.paddingTop = 0;
    this.paddingRight = 0;
    this.paddingBottom = 0;
    this.paddingLeft = 0;
    this.cornerRadius = 0;
    this.opacity = 1;
    this.url = "";
  }
  setScene(scene) {
    if (scene == null && this.registeredLoader) {
      this.registeredLoader.unregisterNode(this);
      this.registeredLoader = void 0;
    }
    super.setScene(scene);
  }
  destroy() {
    if (this.registeredLoader) {
      this.registeredLoader.unregisterNode(this);
      this.registeredLoader = void 0;
    }
    super.destroy();
  }
  render(renderCtx) {
    const { ctx } = renderCtx;
    const { x, y, boxWidth, boxHeight, cornerRadius, opacity } = this;
    if (boxWidth <= 0 || boxHeight <= 0) {
      super.render(renderCtx);
      return;
    }
    const previousAlpha = ctx.globalAlpha;
    ctx.globalAlpha = previousAlpha * opacity;
    if (this.backgroundFill) {
      this.tracePath(ctx, x, y, boxWidth, boxHeight, cornerRadius);
      ctx.fillStyle = this.backgroundFill;
      ctx.fill();
    }
    if (this.url) {
      const loader = this.imageLoader;
      if (loader !== this.registeredLoader) {
        this.registeredLoader?.unregisterNode(this);
        this.registeredLoader = loader;
      }
      const image = loader?.loadImage(this.url, this, {
        width: this.imageWidth,
        height: this.imageHeight
      });
      if (image) {
        const imgX = x + this.paddingLeft;
        const imgY = y + this.paddingTop;
        const clipToCorners = cornerRadius > 0;
        if (clipToCorners) {
          ctx.save();
          this.tracePath(ctx, x, y, boxWidth, boxHeight, cornerRadius);
          ctx.clip();
        }
        ctx.drawImage(image, imgX, imgY, this.imageWidth, this.imageHeight);
        if (clipToCorners) {
          ctx.restore();
        }
      }
    } else {
      Logger7.warnOnce(
        `Image segment has an empty url; rendering background only (${boxWidth}x${boxHeight} box).`
      );
    }
    ctx.globalAlpha = previousAlpha;
    super.render(renderCtx);
  }
  tracePath(ctx, x, y, w, h, r) {
    ctx.beginPath();
    const radius = Math.max(0, Math.min(r, w / 2, h / 2));
    if (radius === 0) {
      ctx.rect(x, y, w, h);
      return;
    }
    ctx.moveTo(x + radius, y);
    ctx.arcTo(x + w, y, x + w, y + h, radius);
    ctx.arcTo(x + w, y + h, x, y + h, radius);
    ctx.arcTo(x, y + h, x, y, radius);
    ctx.arcTo(x, y, x + w, y, radius);
    ctx.closePath();
  }
  computeBBox() {
    return new BBox(this.x, this.y, this.boxWidth, this.boxHeight);
  }
}; __decorateClass([
  SceneChangeDetection()
], _c$7.prototype, "x", 2); __decorateClass([
  SceneChangeDetection()
], _c$7.prototype, "y", 2); __decorateClass([
  SceneChangeDetection()
], _c$7.prototype, "boxWidth", 2); __decorateClass([
  SceneChangeDetection()
], _c$7.prototype, "boxHeight", 2); __decorateClass([
  SceneChangeDetection()
], _c$7.prototype, "imageWidth", 2); __decorateClass([
  SceneChangeDetection()
], _c$7.prototype, "imageHeight", 2); __decorateClass([
  SceneChangeDetection()
], _c$7.prototype, "paddingTop", 2); __decorateClass([
  SceneChangeDetection()
], _c$7.prototype, "paddingRight", 2); __decorateClass([
  SceneChangeDetection()
], _c$7.prototype, "paddingBottom", 2); __decorateClass([
  SceneChangeDetection()
], _c$7.prototype, "paddingLeft", 2); __decorateClass([
  SceneChangeDetection()
], _c$7.prototype, "cornerRadius", 2); __decorateClass([
  SceneChangeDetection()
], _c$7.prototype, "opacity", 2); return _c$7; })()

// packages/ag-charts-community/src/scene/shape/rect.ts
import { DeclaredSceneChangeDetection as DeclaredSceneChangeDetection3, boxesEqual as boxesEqual3, isNumberEqual as isNumberEqual2 } from "ag-charts-core";

// packages/ag-charts-community/src/scene/util/corner.ts
var drawCorner = (path, { x0, y0, x1, y1, cx, cy }, cornerRadius, move) => {
  if (move) {
    path.moveTo(x0, y0);
  }
  if (x0 !== x1 || y0 !== y1) {
    const r0 = Math.atan2(y0 - cy, x0 - cx);
    const r1 = Math.atan2(y1 - cy, x1 - cx);
    path.arc(cx, cy, cornerRadius, r0, r1);
  } else {
    path.lineTo(x0, y0);
  }
};

// packages/ag-charts-community/src/scene/shape/path.ts
import { SceneChangeDetection as SceneChangeDetection2, createSvgElement as createSvgElement9 } from "ag-charts-core";
var Path = /*#__PURE__*/ (() => { var _c$8 = class extends Shape {
  constructor() {
    super(...arguments);
    this._clipX = Number.NaN;
    this._clipY = Number.NaN;
    this.clip = false;
    /**
     * The path only has to be updated when certain attributes change.
     * For example, if transform attributes (such as `translationX`)
     * are changed, we don't have to update the path. The `dirtyPath` flag
     * is how we keep track if the path has to be updated or not.
     */
    this._dirtyPath = true;
    this.lastPixelRatio = Number.NaN;
  }
  get path() {
    this._path ?? (this._path = new ExtendedPath2D());
    return this._path;
  }
  set path(value) {
    this._path = value;
  }
  set clipX(value) {
    this._clipX = value;
    this.dirtyPath = true;
  }
  set clipY(value) {
    this._clipY = value;
    this.dirtyPath = true;
  }
  set dirtyPath(value) {
    if (this._dirtyPath !== value) {
      this._dirtyPath = value;
      if (value) {
        this.markDirty("path");
      }
    }
  }
  get dirtyPath() {
    return this._dirtyPath;
  }
  checkPathDirty() {
    if (this._dirtyPath) {
      return;
    }
    this.dirtyPath = this.path.isDirty() || (this.fillShadow?.isDirty() ?? false) || (this._clipPath?.isDirty() ?? false);
  }
  resetPathDirty() {
    this.path.clear(true);
    this._dirtyPath = false;
  }
  isPathDirty() {
    return this.path.isDirty();
  }
  onChangeDetection(property) {
    this._dirtyPath = true;
    super.onChangeDetection(property);
  }
  computeBBox() {
    this.updatePathIfDirty();
    return this.path.computeBBox();
  }
  isPointInPath(x, y) {
    this.updatePathIfDirty();
    return this.path.closedPath && this.path.isPointInPath(x, y);
  }
  distanceSquared(x, y) {
    return this.distanceSquaredTransformedPoint(x, y);
  }
  svgPathData(transform) {
    this.updatePathIfDirty();
    return this.path.toSVG(transform);
  }
  distanceSquaredTransformedPoint(x, y) {
    this.updatePathIfDirty();
    if (this.path.closedPath && this.path.isPointInPath(x, y)) {
      return 0;
    }
    return this.path.distanceSquared(x, y);
  }
  isDirtyPath() {
    return false;
  }
  updatePath() {
  }
  updatePathIfDirty() {
    if (this.dirtyPath || this.isDirtyPath()) {
      this.updatePath();
      this.dirtyPath = false;
    }
  }
  preRender(renderCtx) {
    if (renderCtx.devicePixelRatio !== this.lastPixelRatio) {
      this.dirtyPath = true;
    }
    this.lastPixelRatio = renderCtx.devicePixelRatio;
    this.updatePathIfDirty();
    return super.preRender(renderCtx, this.pathComplexity());
  }
  /**
   * Per-render complexity hint for {@link preRender}. Subclasses with externally-managed path
   * geometry (e.g. `Marker`, which uses a shared origin-centred path from a cache) override
   * this to avoid forcing `this.path` to lazy-allocate on every render.
   */
  pathComplexity() {
    return this.path.commands.length;
  }
  render(renderCtx) {
    const { ctx } = renderCtx;
    if (this.clip && !Number.isNaN(this._clipX) && !Number.isNaN(this._clipY)) {
      ctx.save();
      try {
        const margin = this.strokeWidth / 2;
        this._clipPath ?? (this._clipPath = new ExtendedPath2D());
        this._clipPath.clear();
        this._clipPath.rect(-margin, -margin, this._clipX + margin, this._clipY + margin + margin);
        ctx.clip(this._clipPath?.getPath2D());
        if (this._clipX > 0 && this._clipY > 0) {
          this.drawPath(ctx);
        }
      } finally {
        ctx.restore();
      }
    } else {
      this._clipPath = void 0;
      this.drawPath(ctx);
    }
    this.fillShadow?.markClean();
    super.render(renderCtx);
  }
  drawPath(ctx) {
    this.fillStroke(ctx, this.path.getPath2D());
  }
  toSVG() {
    if (!this.visible)
      return;
    const element = createSvgElement9("path");
    element.setAttribute("d", this.svgPathData());
    const defs = this.applySvgFillAttributes(element, []);
    this.applySvgStrokeAttributes(element);
    return {
      elements: [element],
      defs
    };
  }
}; _c$8.className = "_c$8"; __decorateClass([
  SceneChangeDetection2()
], _c$8.prototype, "clip", 2); __decorateClass([
  SceneChangeDetection2()
], _c$8.prototype, "clipX", 1); __decorateClass([
  SceneChangeDetection2()
], _c$8.prototype, "clipY", 1); return _c$8; })()

// packages/ag-charts-community/src/scene/shape/rect.ts
function cornerEdges(leadingEdge, trailingEdge, leadingInset, trailingInset, cornerRadius) {
  let leadingClipped = false;
  let trailingClipped = false;
  let leading0 = trailingInset - Math.sqrt(Math.max(cornerRadius ** 2 - leadingInset ** 2, 0));
  let leading1 = 0;
  let trailing0 = 0;
  let trailing1 = leadingInset - Math.sqrt(Math.max(cornerRadius ** 2 - trailingInset ** 2, 0));
  if (leading0 > leadingEdge) {
    leadingClipped = true;
    leading0 = leadingEdge;
    leading1 = leadingInset - Math.sqrt(Math.max(cornerRadius ** 2 - (trailingInset - leadingEdge) ** 2));
  } else if (isNumberEqual2(leading0, 0)) {
    leading0 = 0;
  }
  if (trailing1 > trailingEdge) {
    trailingClipped = true;
    trailing0 = trailingInset - Math.sqrt(Math.max(cornerRadius ** 2 - (leadingInset - trailingEdge) ** 2));
    trailing1 = trailingEdge;
  } else if (isNumberEqual2(trailing1, 0)) {
    trailing1 = 0;
  }
  return { leading0, leading1, trailing0, trailing1, leadingClipped, trailingClipped };
}
function clippedRoundRect(path, x, y, width, height, cornerRadii, clipBBox) {
  let {
    topLeft: topLeftCornerRadius,
    topRight: topRightCornerRadius,
    bottomRight: bottomRightCornerRadius,
    bottomLeft: bottomLeftCornerRadius
  } = cornerRadii;
  const maxVerticalCornerRadius = Math.max(
    topLeftCornerRadius + bottomLeftCornerRadius,
    topRightCornerRadius + bottomRightCornerRadius
  );
  const maxHorizontalCornerRadius = Math.max(
    topLeftCornerRadius + topRightCornerRadius,
    bottomLeftCornerRadius + bottomRightCornerRadius
  );
  if (maxVerticalCornerRadius <= 0 && maxHorizontalCornerRadius <= 0) {
    if (clipBBox == null) {
      path.rect(x, y, width, height);
    } else {
      const x0 = Math.max(x, clipBBox.x);
      const x1 = Math.min(x + width, clipBBox.x + clipBBox.width);
      const y0 = Math.max(y, clipBBox.y);
      const y1 = Math.min(y + height, clipBBox.y + clipBBox.height);
      path.rect(x0, y0, x1 - x0, y1 - y0);
    }
    return;
  } else if (clipBBox == null && topLeftCornerRadius === topRightCornerRadius && topLeftCornerRadius === bottomRightCornerRadius && topLeftCornerRadius === bottomLeftCornerRadius) {
    path.roundRect(x, y, width, height, topLeftCornerRadius);
    return;
  }
  if (width < 0) {
    x += width;
    width = Math.abs(width);
  }
  if (height < 0) {
    y += height;
    height = Math.abs(height);
  }
  if (width <= 0 || height <= 0)
    return;
  if (clipBBox == null) {
    clipBBox = new BBox(x, y, width, height);
  } else {
    const x0 = Math.max(x, clipBBox.x);
    const x1 = Math.min(x + width, clipBBox.x + clipBBox.width);
    const y0 = Math.max(y, clipBBox.y);
    const y1 = Math.min(y + height, clipBBox.y + clipBBox.height);
    clipBBox = new BBox(x0, y0, x1 - x0, y1 - y0);
  }
  const borderScale = Math.max(maxVerticalCornerRadius / height, maxHorizontalCornerRadius / width, 1);
  if (borderScale > 1) {
    topLeftCornerRadius /= borderScale;
    topRightCornerRadius /= borderScale;
    bottomRightCornerRadius /= borderScale;
    bottomLeftCornerRadius /= borderScale;
  }
  let drawTopLeftCorner = true;
  let drawTopRightCorner = true;
  let drawBottomRightCorner = true;
  let drawBottomLeftCorner = true;
  let topLeftCorner;
  let topRightCorner;
  let bottomRightCorner;
  let bottomLeftCorner;
  if (drawTopLeftCorner) {
    const nodes = cornerEdges(
      clipBBox.height,
      clipBBox.width,
      Math.max(x + topLeftCornerRadius - clipBBox.x, 0),
      Math.max(y + topLeftCornerRadius - clipBBox.y, 0),
      topLeftCornerRadius
    );
    if (nodes.leadingClipped)
      drawBottomLeftCorner = false;
    if (nodes.trailingClipped)
      drawTopRightCorner = false;
    const x0 = Math.max(clipBBox.x + nodes.leading1, clipBBox.x);
    const y0 = Math.max(clipBBox.y + nodes.leading0, clipBBox.y);
    const x1 = Math.max(clipBBox.x + nodes.trailing1, clipBBox.x);
    const y1 = Math.max(clipBBox.y + nodes.trailing0, clipBBox.y);
    const cx = x + topLeftCornerRadius;
    const cy = y + topLeftCornerRadius;
    topLeftCorner = { x0, y0, x1, y1, cx, cy };
  }
  if (drawTopRightCorner) {
    const nodes = cornerEdges(
      clipBBox.width,
      clipBBox.height,
      Math.max(y + topRightCornerRadius - clipBBox.y, 0),
      Math.max(clipBBox.x + clipBBox.width - (x + width - topRightCornerRadius), 0),
      topRightCornerRadius
    );
    if (nodes.leadingClipped)
      drawTopLeftCorner = false;
    if (nodes.trailingClipped)
      drawBottomRightCorner = false;
    const x0 = Math.min(clipBBox.x + clipBBox.width - nodes.leading0, clipBBox.x + clipBBox.width);
    const y0 = Math.max(clipBBox.y + nodes.leading1, clipBBox.y);
    const x1 = Math.min(clipBBox.x + clipBBox.width - nodes.trailing0, clipBBox.x + clipBBox.width);
    const y1 = Math.max(clipBBox.y + nodes.trailing1, clipBBox.y);
    const cx = x + width - topRightCornerRadius;
    const cy = y + topRightCornerRadius;
    topRightCorner = { x0, y0, x1, y1, cx, cy };
  }
  if (drawBottomRightCorner) {
    const nodes = cornerEdges(
      clipBBox.height,
      clipBBox.width,
      Math.max(clipBBox.x + clipBBox.width - (x + width - bottomRightCornerRadius), 0),
      Math.max(clipBBox.y + clipBBox.height - (y + height - bottomRightCornerRadius), 0),
      bottomRightCornerRadius
    );
    if (nodes.leadingClipped)
      drawTopRightCorner = false;
    if (nodes.trailingClipped)
      drawBottomLeftCorner = false;
    const x0 = Math.min(clipBBox.x + clipBBox.width - nodes.leading1, clipBBox.x + clipBBox.width);
    const y0 = Math.min(clipBBox.y + clipBBox.height - nodes.leading0, clipBBox.y + clipBBox.height);
    const x1 = Math.min(clipBBox.x + clipBBox.width - nodes.trailing1, clipBBox.x + clipBBox.width);
    const y1 = Math.min(clipBBox.y + clipBBox.height - nodes.trailing0, clipBBox.y + clipBBox.height);
    const cx = x + width - bottomRightCornerRadius;
    const cy = y + height - bottomRightCornerRadius;
    bottomRightCorner = { x0, y0, x1, y1, cx, cy };
  }
  if (drawBottomLeftCorner) {
    const nodes = cornerEdges(
      clipBBox.width,
      clipBBox.height,
      Math.max(clipBBox.y + clipBBox.height - (y + height - bottomLeftCornerRadius), 0),
      Math.max(x + bottomLeftCornerRadius - clipBBox.x, 0),
      bottomLeftCornerRadius
    );
    if (nodes.leadingClipped)
      drawBottomRightCorner = false;
    if (nodes.trailingClipped)
      drawTopLeftCorner = false;
    const x0 = Math.max(clipBBox.x + nodes.leading0, clipBBox.x);
    const y0 = Math.min(clipBBox.y + clipBBox.height - nodes.leading1, clipBBox.y + clipBBox.height);
    const x1 = Math.max(clipBBox.x + nodes.trailing0, clipBBox.x);
    const y1 = Math.min(clipBBox.y + clipBBox.height - nodes.trailing1, clipBBox.y + clipBBox.height);
    const cx = x + bottomLeftCornerRadius;
    const cy = y + height - bottomLeftCornerRadius;
    bottomLeftCorner = { x0, y0, x1, y1, cx, cy };
  }
  let didMove = false;
  if (drawTopLeftCorner && topLeftCorner != null) {
    drawCorner(path, topLeftCorner, topLeftCornerRadius, !didMove);
    didMove || (didMove = true);
  }
  if (drawTopRightCorner && topRightCorner != null) {
    drawCorner(path, topRightCorner, topRightCornerRadius, !didMove);
    didMove || (didMove = true);
  }
  if (drawBottomRightCorner && bottomRightCorner != null) {
    drawCorner(path, bottomRightCorner, bottomRightCornerRadius, !didMove);
    didMove || (didMove = true);
  }
  if (drawBottomLeftCorner && bottomLeftCorner != null) {
    drawCorner(path, bottomLeftCorner, bottomLeftCornerRadius, !didMove);
  }
  path.closePath();
}
var Rect = /*#__PURE__*/ (() => { var _c$9 = class extends Path {
  constructor() {
    super(...arguments);
    this.borderPath = new ExtendedPath2D();
    this.x = 0;
    this.y = 0;
    this.width = 10;
    this.height = 10;
    this.topLeftCornerRadius = 0;
    this.topRightCornerRadius = 0;
    this.bottomRightCornerRadius = 0;
    this.bottomLeftCornerRadius = 0;
    this.clipBBox = void 0;
    this.crisp = false;
    this.lastUpdatePathStrokeWidth = this.__strokeWidth;
    this.effectiveStrokeWidth = this.__strokeWidth;
    this.hittester = super.isPointInPath.bind(this);
    this.distanceCalculator = super.distanceSquaredTransformedPoint.bind(this);
    /**
     * When the rectangle's width or height is less than a pixel
     * and crisp mode is on, the rectangle will still fit into the pixel,
     * but will be less opaque to make an effect of holding less space.
     */
    this.microPixelEffectOpacity = 1;
  }
  // optimised field accessor
  set cornerRadius(cornerRadius) {
    this.topLeftCornerRadius = cornerRadius;
    this.topRightCornerRadius = cornerRadius;
    this.bottomRightCornerRadius = cornerRadius;
    this.bottomLeftCornerRadius = cornerRadius;
  }
  isDirtyPath() {
    return this.lastUpdatePathStrokeWidth !== this.__strokeWidth || Boolean(this.path.isDirty() || this.borderPath.isDirty());
  }
  updatePath() {
    const {
      path,
      borderPath,
      __crisp: crisp,
      __topLeftCornerRadius: topLeft,
      __topRightCornerRadius: topRight,
      __bottomRightCornerRadius: bottomRight,
      __bottomLeftCornerRadius: bottomLeft
    } = this;
    let { __x: x, __y: y, __width: w, __height: h, __strokeWidth: strokeWidth, __clipBBox: clipBBox } = this;
    const pixelRatio = this.layerManager?.canvas.pixelRatio ?? 1;
    const pixelSize = 1 / pixelRatio;
    let microPixelEffectOpacity = 1;
    path.clear();
    borderPath.clear();
    if (w === 0 || h === 0) {
      this.effectiveStrokeWidth = 0;
      this.lastUpdatePathStrokeWidth = 0;
      this.microPixelEffectOpacity = 0;
      return;
    }
    if (crisp) {
      if (w <= pixelSize) {
        microPixelEffectOpacity *= w / pixelSize;
      }
      if (h <= pixelSize) {
        microPixelEffectOpacity *= h / pixelSize;
      }
      w = this.align(x, w);
      h = this.align(y, h);
      x = this.align(x);
      y = this.align(y);
      clipBBox = clipBBox == null ? void 0 : new BBox(
        this.align(clipBBox.x),
        this.align(clipBBox.y),
        this.align(clipBBox.x, clipBBox.width),
        this.align(clipBBox.y, clipBBox.height)
      );
    }
    if (strokeWidth) {
      if (w < pixelSize) {
        const lx = x + pixelSize / 2;
        borderPath.moveTo(lx, y);
        borderPath.lineTo(lx, y + h);
        strokeWidth = pixelSize;
        this.borderClipPath = void 0;
      } else if (h < pixelSize) {
        const ly = y + pixelSize / 2;
        borderPath.moveTo(x, ly);
        borderPath.lineTo(x + w, ly);
        strokeWidth = pixelSize;
        this.borderClipPath = void 0;
      } else if (strokeWidth < w && strokeWidth < h) {
        const halfStrokeWidth = strokeWidth / 2;
        x += halfStrokeWidth;
        y += halfStrokeWidth;
        w -= strokeWidth;
        h -= strokeWidth;
        const adjustedClipBBox = clipBBox?.clone().shrink(halfStrokeWidth);
        const cornerRadii = {
          topLeft: topLeft > 0 ? topLeft - strokeWidth : 0,
          topRight: topRight > 0 ? topRight - strokeWidth : 0,
          bottomRight: bottomRight > 0 ? bottomRight - strokeWidth : 0,
          bottomLeft: bottomLeft > 0 ? bottomLeft - strokeWidth : 0
        };
        this.borderClipPath = void 0;
        if (w > 0 && h > 0 && (adjustedClipBBox == null || adjustedClipBBox?.width > 0 && adjustedClipBBox?.height > 0)) {
          clippedRoundRect(path, x, y, w, h, cornerRadii, adjustedClipBBox);
          clippedRoundRect(borderPath, x, y, w, h, cornerRadii, adjustedClipBBox);
        }
      } else {
        this.borderClipPath = this.borderClipPath ?? new ExtendedPath2D();
        this.borderClipPath.clear();
        this.borderClipPath.rect(x, y, w, h);
        borderPath.rect(x, y, w, h);
      }
    } else {
      const cornerRadii = { topLeft, topRight, bottomRight, bottomLeft };
      this.borderClipPath = void 0;
      clippedRoundRect(path, x, y, w, h, cornerRadii, clipBBox);
    }
    if ([topLeft, topRight, bottomRight, bottomLeft].every(areCornersZero)) {
      let distanceSquaredFromRect2 = function(hitX, hitY) {
        return rectInstance.getBBox().distanceSquared(hitX, hitY);
      };
      var distanceSquaredFromRect = distanceSquaredFromRect2;
      const bbox = this.getBBox();
      this.hittester = bbox.containsPoint.bind(bbox);
      const rectInstance = this;
      this.distanceSquared = distanceSquaredFromRect2;
    } else {
      this.hittester = super.isPointInPath;
      this.distanceCalculator = super.distanceSquaredTransformedPoint;
    }
    this.effectiveStrokeWidth = strokeWidth;
    this.lastUpdatePathStrokeWidth = strokeWidth;
    this.microPixelEffectOpacity = microPixelEffectOpacity;
  }
  computeBBox() {
    const { __x: x, __y: y, __width: width, __height: height, __clipBBox: clipBBox } = this;
    return clipBBox?.clone() ?? new BBox(x, y, width, height);
  }
  isPointInPath(x, y) {
    return this.hittester(x, y);
  }
  get midPoint() {
    return { x: this.__x + this.__width / 2, y: this.__y + this.__height / 2 };
  }
  /**
   * High-performance static property setter that bypasses the decorator system entirely.
   * Writes directly to backing fields (__propertyName) to avoid:
   * - Decorator setter chains and equality checks
   * - Multiple onChangeDetection calls per property
   * - Object.keys() iteration in assignIfNotStrictlyEqual
   * - Object allocation overhead
   *
   * A single markDirty() call at the end ensures the scene graph is properly invalidated.
   * WARNING: Only use for hot paths where performance is critical and properties don't need
   * individual change detection (e.g., when updating many nodes in a loop).
   */
  setStaticProperties(drawingMode, topLeftCornerRadius, topRightCornerRadius, bottomRightCornerRadius, bottomLeftCornerRadius, visible, crisp, fillShadow) {
    this.__drawingMode = drawingMode;
    this.__topLeftCornerRadius = topLeftCornerRadius;
    this.__topRightCornerRadius = topRightCornerRadius;
    this.__bottomRightCornerRadius = bottomRightCornerRadius;
    this.__bottomLeftCornerRadius = bottomLeftCornerRadius;
    this.__visible = visible;
    this.__crisp = crisp;
    this.__fillShadow = fillShadow;
    this.dirtyPath = true;
    this.markDirty();
  }
  /**
   * High-performance animation reset that bypasses the decorator system entirely.
   * Writes directly to backing fields (__x, __y, etc.) to avoid:
   * - Decorator setter chains and equality checks
   * - Multiple onChangeDetection calls
   * - Object.keys() iteration
   *
   * A single markDirty() call at the end ensures the scene graph is properly invalidated.
   * WARNING: Only use for animation hot paths where performance is critical.
   */
  resetAnimationProperties(x, y, width, height, opacity, clipBBox) {
    this.__x = x;
    this.__y = y;
    this.__width = width;
    this.__height = height;
    this.__opacity = opacity;
    this.__clipBBox = clipBBox;
    this.dirtyPath = true;
    this.markDirty();
  }
  distanceSquared(x, y) {
    return this.distanceCalculator(x, y);
  }
  applyFillAndAlpha(ctx) {
    super.applyFillAndAlpha(ctx);
    ctx.globalAlpha *= this.microPixelEffectOpacity;
  }
  applyStrokeAndAlpha(ctx) {
    super.applyStrokeAndAlpha(ctx);
    ctx.globalAlpha *= this.microPixelEffectOpacity;
  }
  renderStroke(ctx) {
    const { stroke, effectiveStrokeWidth } = this;
    if (stroke && effectiveStrokeWidth) {
      const { globalAlpha } = ctx;
      const { lineDash, lineDashOffset, lineCap, lineJoin, borderPath, borderClipPath } = this;
      if (borderClipPath) {
        ctx.clip(borderClipPath.getPath2D());
      }
      this.applyStrokeAndAlpha(ctx);
      ctx.lineWidth = effectiveStrokeWidth;
      if (lineDash) {
        ctx.setLineDash(lineDash);
      }
      if (lineDashOffset) {
        ctx.lineDashOffset = lineDashOffset;
      }
      if (lineCap) {
        ctx.lineCap = lineCap;
      }
      if (lineJoin) {
        ctx.lineJoin = lineJoin;
      }
      ctx.stroke(borderPath.getPath2D());
      ctx.globalAlpha = globalAlpha;
    }
  }
}; _c$9.className = "_c$9"; __decorateClass([
  DeclaredSceneChangeDetection3()
], _c$9.prototype, "x", 2); __decorateClass([
  DeclaredSceneChangeDetection3()
], _c$9.prototype, "y", 2); __decorateClass([
  DeclaredSceneChangeDetection3()
], _c$9.prototype, "width", 2); __decorateClass([
  DeclaredSceneChangeDetection3()
], _c$9.prototype, "height", 2); __decorateClass([
  DeclaredSceneChangeDetection3()
], _c$9.prototype, "topLeftCornerRadius", 2); __decorateClass([
  DeclaredSceneChangeDetection3()
], _c$9.prototype, "topRightCornerRadius", 2); __decorateClass([
  DeclaredSceneChangeDetection3()
], _c$9.prototype, "bottomRightCornerRadius", 2); __decorateClass([
  DeclaredSceneChangeDetection3()
], _c$9.prototype, "bottomLeftCornerRadius", 2); __decorateClass([
  DeclaredSceneChangeDetection3({ equals: boxesEqual3 })
], _c$9.prototype, "clipBBox", 2); __decorateClass([
  DeclaredSceneChangeDetection3()
], _c$9.prototype, "crisp", 2); return _c$9; })()
function areCornersZero(cornerRadius) {
  return cornerRadius === 0;
}

// packages/ag-charts-community/src/scene/shape/text.ts
var _Text = /*#__PURE__*/ (() => { var _c$10 = class _Text extends Shape {
  constructor(options) {
    super(options);
    this.generatingTextMap = false;
    this.suppressedDirtyDuringGenerate = false;
    this.x = 0;
    this.y = 0;
    this.lines = [];
    this.text = void 0;
    this.fontCache = void 0;
    this.fontSize = _Text.defaultFontSize;
    this.fontFamily = "sans-serif";
    this.textAlign = "start";
    this.textBaseline = "alphabetic";
    this.boxPadding = 0;
    this.trimText = options?.trimText ?? true;
  }
  onTextChange() {
    this.richText?.clear();
    this.textMap?.clear();
    this.segmentMetrics = void 0;
    if (isArray(this.text)) {
      this.lines = [];
      this.richText ?? (this.richText = new Group());
      this.richText.parentNode = this;
      this.richText.setScene(this.scene);
      const children = [];
      for (const segment of this.text) {
        if (segment.type === "image") {
          children.push(new ImageSegmentNode());
        } else {
          for (const line of toTextString(segment.text).split(LineSplitter)) {
            if (line)
              children.push(new _Text({ trimText: false }));
          }
        }
      }
      this.richText.append(children);
    } else {
      if (this.richText) {
        this.richText.parentNode = void 0;
        this.richText.setScene();
        this.richText = void 0;
      }
      const lines = toTextString(this.text).split(LineSplitter);
      this.lines = this.trimText ? lines.map((line) => line.trim()) : lines;
    }
  }
  get font() {
    this.fontCache ?? (this.fontCache = toFontString(this));
    return this.fontCache;
  }
  resolveFont() {
    if (!this.hasRenderableText())
      return void 0;
    return this.font;
  }
  static measureBBox(text, x, y, options) {
    if (isArray(text)) {
      const { font, lineHeight, textAlign, textBaseline } = options;
      const { width, height, lineMetrics } = measureTextSegments(text, font);
      const totalHeight = lineHeight ? lineHeight * lineMetrics.length : height;
      const offsetTop = _Text.calcTopOffset(totalHeight, lineMetrics[0], textBaseline);
      const offsetLeft = _Text.calcLeftOffset(width, textAlign);
      return new BBox(x - offsetLeft, y - offsetTop, width, totalHeight);
    } else {
      return _Text.computeBBox(toTextString(text).split(LineSplitter), x, y, options);
    }
  }
  static computeBBox(lines, x, y, opts) {
    const { font, lineHeight, textAlign, textBaseline, isRtl } = opts;
    const { width, height, lineMetrics } = cachedTextMeasurer(font).measureLines(lines);
    const totalHeight = lineHeight ? lineHeight * lineMetrics.length : height;
    const offsetTop = _Text.calcTopOffset(totalHeight, lineMetrics[0], textBaseline);
    const offsetLeft = _Text.calcLeftOffset(width, textAlign, isRtl);
    return new BBox(x - offsetLeft, y - offsetTop, width, totalHeight);
  }
  static calcTopOffset(height, textMetrics, textBaseline) {
    switch (textBaseline) {
      case "alphabetic":
        return textMetrics?.ascent ?? 0;
      case "middle":
        return height / 2;
      case "bottom":
        return height;
      default:
        return 0;
    }
  }
  static calcSegmentedTopOffset(height, lineMetrics, textBaseline) {
    switch (textBaseline) {
      case "alphabetic":
        return lineMetrics[0]?.ascent ?? 0;
      case "middle": {
        const line = lineMetrics[0];
        const isPureTextLine = lineMetrics.length === 1 && line.segments.length > 0 && !line.blockImages?.length && line.segments.every((s) => s.type !== "image");
        if (isPureTextLine) {
          return line.ascent + line.segments.reduce(
            (offsetY, segment) => segment.type === "image" ? offsetY : Math.min(offsetY, cachedTextMeasurer(segment).baselineDistance("middle")),
            0
          );
        }
        return height / 2;
      }
      case "bottom":
        return height;
      default:
        return 0;
    }
  }
  static calcLeftOffset(width, textAlign, isRtl) {
    let offset = 0;
    switch (textAlign) {
      case "center":
        offset = 0.5;
        break;
      case "right":
      case (isRtl ? "start" : "end"):
        offset = 1;
    }
    return width * offset;
  }
  getBBox() {
    const bbox = super.getBBox();
    if (!this.textMap?.size || !isArray(this.text))
      return bbox;
    const { height, lineMetrics } = this.getSegmentMetrics(this.text);
    const offsetTop = _Text.calcSegmentedTopOffset(height, lineMetrics, this.textBaseline);
    const y = this.y - offsetTop;
    if (bbox.y === y)
      return bbox;
    return new BBox(bbox.x, y, bbox.width, bbox.height);
  }
  computeBBox() {
    if (!this.hasRenderableText()) {
      return new BBox(this.x, this.y, 0, 0);
    }
    this.generateTextMap();
    if (this.textMap?.size) {
      const bbox = BBox.merge(this.textMap.values());
      bbox.x = this.x - _Text.calcLeftOffset(bbox.width, this.textAlign);
      bbox.y = this.y;
      return bbox;
    }
    const isRtl = this.scene?.isRtl;
    const { x, y, lines, textBaseline, textAlign } = this;
    const measuredTextBounds = _Text.computeBBox(lines, x, y, { font: this, textBaseline, textAlign, isRtl });
    if (this.boxing != null)
      measuredTextBounds.grow(this.boxPadding);
    return measuredTextBounds;
  }
  getTextMeasureBBox() {
    return this.computeBBox();
  }
  getPlainText() {
    return toPlainText(this.text);
  }
  isPointInPath(x, y) {
    return this.getBBox()?.containsPoint(x, y) ?? false;
  }
  setScene(scene) {
    this.richText?.setScene(scene);
    super.setScene(scene);
  }
  generateTextMap() {
    if (!isArray(this.text) || this.textMap?.size)
      return;
    this.textMap ?? (this.textMap = /* @__PURE__ */ new Map());
    this.generatingTextMap = true;
    this.suppressedDirtyDuringGenerate = false;
    try {
      this.buildTextMap(this.text);
    } finally {
      this.generatingTextMap = false;
      if (this.suppressedDirtyDuringGenerate) {
        this.suppressedDirtyDuringGenerate = false;
        super.markDirty();
      }
    }
  }
  getSegmentMetrics(text) {
    this.segmentMetrics ?? (this.segmentMetrics = measureTextSegments(text, this));
    return this.segmentMetrics;
  }
  buildTextMap(text) {
    const childNodes = this.richText.children();
    const { width: totalWidth, lineMetrics } = this.getSegmentMetrics(text);
    const labelLeft = this.x - totalWidth / 2;
    let offsetY = 0;
    for (let lineIndex = 0; lineIndex < lineMetrics.length; ) {
      const line = lineMetrics[lineIndex];
      if (line.blockImages?.length) {
        const span = line.blockRowSpan ?? 1;
        const nextOffsetY = this.layoutBlockRow(lineMetrics, lineIndex, span, offsetY, labelLeft, childNodes);
        if (nextOffsetY == null)
          return;
        offsetY = nextOffsetY;
        lineIndex += span;
        continue;
      }
      offsetY = this.renderLine(line, this.x - line.width / 2, offsetY, childNodes);
      lineIndex += 1;
    }
  }
  // Lay out a block-image row: the leading image strip anchored at `labelLeft`, then the text
  // column (`span` wrapped lines) flowing to its right. Returns the advanced offsetY, or null
  // if the child-node supply diverged from the line metrics (caller abandons the map).
  layoutBlockRow(lineMetrics, lineIndex, span, offsetY, labelLeft, childNodes) {
    const strip = lineMetrics[lineIndex].blockImages;
    const stripWidth = blockStripWidth(strip);
    const stripHeight = blockStripHeight(strip);
    let innerColHeight = 0;
    for (let k = 0; k < span; k++) {
      innerColHeight += lineMetrics[lineIndex + k].height;
    }
    const rowHeight = Math.max(stripHeight, innerColHeight);
    let stripX = labelLeft;
    for (let s = 0; s < strip.length; s++) {
      const blockSeg = strip[s];
      const blockBox = blockSeg.textMetrics;
      const imageAlign = toCanvasTextBaseline(blockSeg.verticalAlign) ?? "middle";
      const imageOffset = _Text.calcAnchoredOffset(imageAlign, rowHeight, blockBox.height);
      const imageChild = childNodes.next().value;
      if (!imageChild) {
        this.abandonTextMap();
        return null;
      }
      _Text.applyImageSegment(imageChild, blockSeg, stripX, offsetY + imageOffset);
      this.textMap.set(imageChild, imageChild.getBBox());
      stripX += blockBox.width + (s < strip.length - 1 ? BLOCK_IMAGE_SPACING : 0);
    }
    const firstTextSegment = _Text.findFirstTextSegment(lineMetrics, lineIndex, span);
    const columnLeft = labelLeft + stripWidth + BLOCK_IMAGE_SPACING;
    let innerOffsetY = offsetY + _Text.calcAnchoredOffset(
      toCanvasTextBaseline(firstTextSegment?.verticalAlign) ?? "alphabetic",
      rowHeight,
      innerColHeight
    );
    for (let k = 0; k < span; k++) {
      innerOffsetY = this.renderLine(lineMetrics[lineIndex + k], columnLeft, innerOffsetY, childNodes);
    }
    return offsetY + rowHeight;
  }
  static findFirstTextSegment(lineMetrics, startIndex, span) {
    for (let k = 0; k < span; k++) {
      const seg = lineMetrics[startIndex + k].segments.find((s) => s.type !== "image");
      if (seg)
        return seg;
    }
    return void 0;
  }
  renderLine(line, lineLeft, offsetY, childNodes) {
    const { height, ascent, textAscent, textDescent, segments } = line;
    const baseline = offsetY + ascent;
    let offsetX = 0;
    for (const measured of segments) {
      const node = childNodes.next().value;
      if (!node) {
        this.abandonTextMap();
        return offsetY + height;
      }
      if (measured.type === "image") {
        const boxWidth = measured.textMetrics.width;
        const boxHeight = measured.textMetrics.height;
        const { above } = imageBoxAroundBaseline(
          toCanvasTextBaseline(measured.verticalAlign),
          boxHeight,
          textAscent,
          textDescent
        );
        const imageNode = node;
        _Text.applyImageSegment(imageNode, measured, lineLeft + offsetX, baseline - above);
        this.textMap.set(imageNode, imageNode.getBBox());
        offsetX += boxWidth;
        continue;
      }
      const { color, textMetrics, verticalAlign, ...segment } = measured;
      const textNode = node;
      const segmentBaseline = toCanvasTextBaseline(verticalAlign) ?? "alphabetic";
      textNode.x = lineLeft + offsetX;
      textNode.y = _Text.calcSegmentY(segmentBaseline, offsetY, ascent, height);
      textNode.setProperties({ ...segment, textBaseline: segmentBaseline, fill: color ?? this.fill });
      const textBBox = textNode.getBBox();
      this.textMap.set(textNode, textBBox);
      offsetX += textMetrics.width;
    }
    return offsetY + height;
  }
  abandonTextMap() {
    this.textMap?.clear();
    this.segmentMetrics = void 0;
  }
  // Anchor a child of `childHeight` inside a container of `totalHeight` according to verticalAlign.
  // Used to position the block-leading image and its text column independently within the label.
  static calcAnchoredOffset(verticalAlign, totalHeight, childHeight) {
    const slack = Math.max(0, totalHeight - childHeight);
    switch (verticalAlign) {
      case "middle":
        return slack / 2;
      case "bottom":
      case "ideographic":
      case "alphabetic":
        return slack;
      case "top":
      case "hanging":
      default:
        return 0;
    }
  }
  static applyImageSegment(node, segment, x, y) {
    const { top, right, bottom, left } = resolvePadding(segment.padding);
    node.x = x;
    node.y = y;
    node.boxWidth = segment.textMetrics.width;
    node.boxHeight = segment.textMetrics.height;
    node.imageWidth = segment.width;
    node.imageHeight = segment.height;
    node.paddingTop = top;
    node.paddingRight = right;
    node.paddingBottom = bottom;
    node.paddingLeft = left;
    node.cornerRadius = segment.cornerRadius ?? 0;
    node.backgroundFill = segment.backgroundFill;
    node.url = segment.url;
  }
  static calcSegmentY(verticalAlign, lineTop, ascent, height) {
    switch (verticalAlign) {
      case "top":
      case "hanging":
        return lineTop;
      case "middle":
        return lineTop + height / 2;
      case "bottom":
      case "ideographic":
        return lineTop + height;
      case "alphabetic":
      default:
        return lineTop + ascent;
    }
  }
  render(renderCtx) {
    const { ctx, stats } = renderCtx;
    if (!this.layerManager || !this.hasRenderableText()) {
      if (stats)
        stats.nodesSkipped += 1;
      return;
    }
    if (isArray(this.text) && this.richText) {
      this.generateTextMap();
      const richTextBBox = this.richText.getBBox();
      const { width, height, lineMetrics } = this.getSegmentMetrics(this.text);
      let translateX = 0;
      switch (this.textAlign) {
        case "left":
        case "start":
          translateX = width / 2;
          break;
        case "right":
        case "end":
          translateX = width / -2;
      }
      const translateY = this.y - _Text.calcSegmentedTopOffset(height, lineMetrics, this.textBaseline);
      this.renderBoxing(renderCtx, richTextBBox.clone().translate(translateX, translateY));
      ctx.save();
      ctx.translate(translateX, translateY);
      this.richText.opacity = this.opacity;
      this.richText.render(renderCtx);
      ctx.restore();
    } else {
      this.renderText(renderCtx);
    }
    if (_Text.debug.check()) {
      const bbox = this.getBBox();
      ctx.lineWidth = this.textMap?.size ? 2 : 1;
      ctx.strokeStyle = this.textMap?.size ? "blue" : "red";
      ctx.strokeRect(bbox.x, bbox.y, bbox.width, bbox.height);
    }
    super.render(renderCtx);
  }
  markDirty(property) {
    if (this.generatingTextMap) {
      this.suppressedDirtyDuringGenerate = true;
      return;
    }
    this.textMap?.clear();
    this.segmentMetrics = void 0;
    return super.markDirty(property);
  }
  renderText(renderCtx) {
    const { fill, stroke, strokeWidth, font, textAlign } = this;
    if (!fill && !(stroke && strokeWidth) || !this.layerManager) {
      return super.render(renderCtx);
    }
    const { ctx } = renderCtx;
    if (renderCtx.currentFont !== font) {
      ctx.font = font;
      renderCtx.currentFont = font;
    }
    ctx.textAlign = textAlign;
    this.renderBoxing(renderCtx);
    this.fillStroke(ctx);
  }
  renderBoxing(renderCtx, bbox) {
    if (!this.boxing)
      return;
    const textBBox = bbox ?? _Text.computeBBox(this.lines, this.x, this.y, this);
    if (textBBox.width === 0 || textBBox.height === 0)
      return;
    const { x, y, width, height } = textBBox.grow(this.boxPadding);
    this.boxing.opacity = this.opacity;
    this.boxing.x = x;
    this.boxing.y = y;
    this.boxing.width = width;
    this.boxing.height = height;
    this.boxing.preRender(renderCtx);
    this.boxing.render(renderCtx);
  }
  executeFill(ctx) {
    this.renderLines((line, x, y) => ctx.fillText(line, x, y));
  }
  executeStroke(ctx) {
    this.renderLines((line, x, y) => ctx.strokeText(line, x, y));
  }
  renderLines(renderCallback) {
    const { x, y, lines } = this;
    if (!Number.isFinite(x) || !Number.isFinite(y))
      return;
    const measurer = cachedTextMeasurer(this);
    const { lineMetrics } = measurer.measureLines(lines);
    const { textBaseline, lineHeight = measurer.lineHeight() } = this;
    let offsetY = 0;
    if (textBaseline === "top") {
      offsetY = lineMetrics[0].ascent;
    } else if (textBaseline === "middle" || textBaseline === "bottom") {
      offsetY = lineHeight * (1 - lines.length);
      if (textBaseline === "middle") {
        offsetY /= 2;
        offsetY -= measurer.baselineDistance(textBaseline);
      } else {
        offsetY -= lineMetrics[0].descent;
      }
    }
    for (const line of lineMetrics) {
      renderCallback(line.text, x, y + offsetY);
      offsetY += lineHeight;
    }
  }
  setFont(props) {
    this.fontFamily = props.fontFamily;
    this.fontSize = props.fontSize;
    this.fontStyle = props.fontStyle;
    this.fontWeight = props.fontWeight;
  }
  setAlign(props) {
    this.textAlign = props.textAlign;
    this.textBaseline = props.textBaseline;
  }
  setBoxing(props) {
    const stroke = props.border?.enabled ? props.border?.stroke : void 0;
    if (props.fill != null || stroke != null) {
      this.boxing ?? (this.boxing = new Rect({ scene: this.scene }));
      this.boxing.fill = props.fill;
      this.boxing.fillOpacity = props.fillOpacity ?? 1;
      this.boxing.cornerRadius = props.cornerRadius ?? 0;
      this.boxing.stroke = stroke;
      this.boxing.strokeWidth = props.border?.strokeWidth ?? 0;
      this.boxing.strokeOpacity = props.border?.strokeOpacity ?? 1;
      this.boxPadding = props.padding ?? 0;
    } else if (this.boxing) {
      this.boxing.destroy();
      this.boxing = void 0;
    }
  }
  hasBoxing() {
    return this.boxing != null;
  }
  getBoxingProperties() {
    const { fill, fillOpacity, cornerRadius, stroke, strokeWidth, strokeOpacity } = this.boxing ?? {};
    return {
      border: { enabled: stroke != null, stroke, strokeWidth, strokeOpacity },
      cornerRadius,
      fill,
      fillOpacity,
      padding: this.boxPadding
    };
  }
  toSVG() {
    if (!this.visible || !this.hasRenderableText())
      return;
    const text = this.text;
    if (text == null)
      return;
    const element = createSvgElement10("text");
    if (isArray(text)) {
      for (const segment of text) {
        if (segment.type === "image") {
          Logger8.warnOnce("SVG export drops inline image segments; text content is preserved.");
          continue;
        }
        const segmentElement = createSvgElement10("tspan");
        setSvgFontAttributes(segmentElement, {
          fontSize: segment.fontSize ?? this.fontSize,
          fontFamily: segment.fontFamily ?? this.fontFamily,
          fontWeight: segment.fontWeight ?? this.fontWeight,
          fontStyle: segment.fontStyle ?? this.fontStyle
        });
        this.applySvgFillAttributes(segmentElement);
        segmentElement.textContent = toTextString(segment.text);
        element.append(segmentElement);
      }
    } else {
      this.applySvgFillAttributes(element);
      setSvgFontAttributes(element, this);
      element.setAttribute(
        "text-anchor",
        {
          center: "middle",
          left: "start",
          right: "end",
          start: "start",
          end: "end"
        }[this.textAlign ?? "start"]
      );
      element.setAttribute("alignment-baseline", this.textBaseline);
      element.setAttribute("x", String(this.x));
      element.setAttribute("y", String(this.y));
      element.textContent = toTextString(text);
    }
    return { elements: [element] };
  }
  hasRenderableText() {
    const { text } = this;
    if (text == null) {
      return false;
    }
    return isArray(text) ? text.length > 0 : toTextString(text) !== "";
  }
}; _c$10.className = "Text"; _c$10.debug = Debug3.create(true, "scene:text" /* SCENE_TEXT */); _c$10.defaultFontSize = 10; __decorateClass([
  SceneChangeDetection()
], _c$10.prototype, "x", 2); __decorateClass([
  SceneChangeDetection()
], _c$10.prototype, "y", 2); __decorateClass([
  SceneRefChangeDetection({
    changeCb: (o) => o.onTextChange()
  })
], _c$10.prototype, "text", 2); __decorateClass([
  SceneChangeDetection({
    changeCb: (o) => {
      o.fontCache = void 0;
    }
  })
], _c$10.prototype, "fontStyle", 2); __decorateClass([
  SceneChangeDetection({
    changeCb: (o) => {
      o.fontCache = void 0;
    }
  })
], _c$10.prototype, "fontWeight", 2); __decorateClass([
  SceneChangeDetection({
    changeCb: (o) => {
      o.fontCache = void 0;
    }
  })
], _c$10.prototype, "fontSize", 2); __decorateClass([
  SceneChangeDetection({
    changeCb: (o) => {
      o.fontCache = void 0;
    }
  })
], _c$10.prototype, "fontFamily", 2); __decorateClass([
  SceneChangeDetection()
], _c$10.prototype, "textAlign", 2); __decorateClass([
  SceneChangeDetection()
], _c$10.prototype, "textBaseline", 2); __decorateClass([
  SceneChangeDetection()
], _c$10.prototype, "lineHeight", 2); return _c$10; })()
var Text = _Text;
var RotatableText = /*#__PURE__*/ Rotatable(Text);
var TransformableText = /*#__PURE__*/ Rotatable(Translatable(Text));

// packages/ag-charts-community/src/chart/caption.ts
var CaptionTooltipProperties = /*#__PURE__*/ (() => { var _c$11 = class extends BaseProperties2 {
}; __decorateClass([
  Property2
], _c$11.prototype, "visible", 2); __decorateClass([
  Property2
], _c$11.prototype, "text", 2); __decorateClass([
  Property2
], _c$11.prototype, "renderer", 2); return _c$11; })()
var Caption = /*#__PURE__*/ (() => { var _c$12 = class extends BaseProperties2 {
  constructor() {
    super(...arguments);
    this.id = createId2(this);
    this.node = new RotatableText({ zIndex: 1 }).setProperties({
      textAlign: "center",
      pointerEvents: 1 /* None */
    });
    this.enabled = false;
    this.textAlign = "center";
    this.fontSize = FONT_SIZE.SMALLER;
    this.fontFamily = "sans-serif";
    this.wrapping = "always";
    this.truncate = true;
    this.padding = 0;
    this.layoutStyle = "block";
    this.tooltip = new CaptionTooltipProperties();
    this.truncated = false;
  }
  registerInteraction(moduleCtx, where) {
    return moduleCtx.eventsHub.on("layout:complete", () => this.updateA11yText(moduleCtx, where));
  }
  computeTextWrap(containerWidth, containerHeight) {
    const { text, padding, wrapping, truncate } = this;
    const effectiveContainerWidth = truncate ? containerWidth : Infinity;
    const effectiveContainerHeight = truncate ? containerHeight : Infinity;
    const maxWidth = Math.min(this.maxWidth ?? Infinity, effectiveContainerWidth) - padding * 2;
    const maxHeight = this.maxHeight ?? effectiveContainerHeight - padding * 2;
    const options = { maxWidth, maxHeight, font: this, textWrap: wrapping };
    if (!Number.isFinite(maxWidth) && !Number.isFinite(maxHeight)) {
      this.node.text = text;
      return;
    }
    let wrappedText;
    if (isArray2(text)) {
      wrappedText = wrapTextSegments(text, options);
      this.truncated = wrappedText.some(isSegmentTruncated);
    } else {
      wrappedText = wrapText(toTextString2(text), options);
      this.truncated = isTextTruncated(wrappedText);
    }
    this.node.text = wrappedText;
  }
  updateA11yText(moduleCtx, where) {
    const { proxyInteractionService } = moduleCtx;
    if (!this.enabled || !this.text) {
      this.destroyProxyText();
      return;
    }
    const bbox = Transformable.toCanvas(this.node);
    if (!bbox)
      return;
    const { id: domManagerId } = this;
    if (this.proxyText == null) {
      this.proxyText = proxyInteractionService.createProxyElement({ type: "text", domManagerId, where });
      this.proxyTextListeners = [
        this.proxyText.addListener("mousemove", (ev) => this.handleMouseMove(moduleCtx, ev)),
        this.proxyText.addListener("mouseleave", () => this.handleTooltipHide(moduleCtx)),
        this.proxyText.addListener("focus", () => this.handleFocus(moduleCtx)),
        this.proxyText.addListener("blur", () => this.handleTooltipHide(moduleCtx))
      ];
    }
    const textContent = toPlainText2(this.text);
    if (textContent !== this.lastProxyTextContent) {
      this.proxyText.textContent = textContent;
      this.lastProxyTextContent = textContent;
    }
    const { lastProxyBBox } = this;
    if (bbox.x !== lastProxyBBox?.x || bbox.y !== lastProxyBBox?.y || bbox.width !== lastProxyBBox?.width || bbox.height !== lastProxyBBox?.height) {
      this.proxyText.setBounds(bbox);
      this.lastProxyBBox = { x: bbox.x, y: bbox.y, width: bbox.width, height: bbox.height };
    }
  }
  getEffectiveTooltipVisible() {
    const { visible, text, renderer } = this.tooltip;
    if (visible != null)
      return visible;
    return text != null || renderer != null ? "always" : "auto";
  }
  getTooltipContent(moduleCtx) {
    const captionText = toPlainText2(this.text);
    const { renderer, text } = this.tooltip;
    if (renderer != null) {
      const params = { text: captionText };
      const result = callWithContext(moduleCtx.chartService, renderer, params);
      if (result === "")
        return void 0;
      if (result != null)
        return { type: "raw", rawHtmlString: toTextString2(result) };
    }
    const displayText = text ?? captionText;
    return { type: "structured", title: displayText };
  }
  showTooltip(moduleCtx, canvasX, canvasY) {
    if (!this.enabled)
      return;
    const effectiveVisible = this.getEffectiveTooltipVisible();
    if (effectiveVisible === "never")
      return;
    if (effectiveVisible === "auto" && !this.truncated)
      return;
    const content = this.getTooltipContent(moduleCtx);
    if (content == null)
      return;
    moduleCtx.tooltipManager.updateTooltip(this.id, { canvasX, canvasY, showArrow: false }, [content]);
  }
  handleMouseMove(moduleCtx, event) {
    if (event == null)
      return;
    const { x, y } = Transformable.toCanvas(this.node);
    const canvasX = event.sourceEvent.offsetX + x;
    const canvasY = event.sourceEvent.offsetY + y;
    this.showTooltip(moduleCtx, canvasX, canvasY);
  }
  handleFocus(moduleCtx) {
    const bbox = Transformable.toCanvas(this.node);
    if (!bbox)
      return;
    const canvasX = bbox.x + bbox.width / 2;
    const canvasY = bbox.y + bbox.height / 2;
    this.showTooltip(moduleCtx, canvasX, canvasY);
  }
  handleTooltipHide(moduleCtx) {
    moduleCtx.tooltipManager.removeTooltip(this.id, void 0, true);
  }
  destroy() {
    this.destroyProxyText();
  }
  destroyProxyText() {
    if (this.proxyText == null)
      return;
    for (const cleanup of this.proxyTextListeners ?? []) {
      cleanup();
    }
    this.proxyTextListeners = void 0;
    this.proxyText.destroy();
    this.proxyText = void 0;
    this.lastProxyTextContent = void 0;
    this.lastProxyBBox = void 0;
  }
}; _c$12.className = "_c$12"; __decorateClass([
  Property2,
  ProxyPropertyOnWrite("node", "visible")
], _c$12.prototype, "enabled", 2); __decorateClass([
  Property2,
  ProxyPropertyOnWrite("node")
], _c$12.prototype, "text", 2); __decorateClass([
  Property2,
  ProxyPropertyOnWrite("node")
], _c$12.prototype, "textAlign", 2); __decorateClass([
  Property2,
  ProxyPropertyOnWrite("node")
], _c$12.prototype, "fontStyle", 2); __decorateClass([
  Property2,
  ProxyPropertyOnWrite("node")
], _c$12.prototype, "fontWeight", 2); __decorateClass([
  Property2,
  ProxyPropertyOnWrite("node")
], _c$12.prototype, "fontSize", 2); __decorateClass([
  Property2,
  ProxyPropertyOnWrite("node")
], _c$12.prototype, "fontFamily", 2); __decorateClass([
  Property2,
  ProxyPropertyOnWrite("node", "fill")
], _c$12.prototype, "color", 2); __decorateClass([
  Property2
], _c$12.prototype, "spacing", 2); __decorateClass([
  Property2
], _c$12.prototype, "maxWidth", 2); __decorateClass([
  Property2
], _c$12.prototype, "maxHeight", 2); __decorateClass([
  Property2
], _c$12.prototype, "wrapping", 2); __decorateClass([
  Property2
], _c$12.prototype, "truncate", 2); __decorateClass([
  Property2
], _c$12.prototype, "padding", 2); __decorateClass([
  Property2
], _c$12.prototype, "layoutStyle", 2); __decorateClass([
  Property2
], _c$12.prototype, "tooltip", 2); return _c$12; })()

// packages/ag-charts-community/src/chart/marker/marker.ts
import { DeclaredSceneChangeDetection as DeclaredSceneChangeDetection4, DeclaredSceneObjectChangeDetection as DeclaredSceneObjectChangeDetection2, TRIPLE_EQ as TRIPLE_EQ2 } from "ag-charts-core";

// packages/ag-charts-community/src/chart/marker/shapes.ts
import { toRadians as toRadians2 } from "ag-charts-core";
function drawMarkerUnitPolygon(params, moves) {
  const { path, size } = params;
  const { x: x0, y: y0 } = params;
  path.clear();
  let didMove = false;
  for (const [dx, dy] of moves) {
    const x = x0 + (dx - 0.5) * size;
    const y = y0 + (dy - 0.5) * size;
    if (didMove) {
      path.lineTo(x, y);
    } else {
      path.moveTo(x, y);
    }
    didMove = true;
  }
  path.closePath();
}
var MARKER_SHAPES = {
  circle({ path, x, y, size }) {
    const r = size / 2;
    path.arc(x, y, r, 0, Math.PI * 2);
    path.closePath();
  },
  cross(params) {
    drawMarkerUnitPolygon(params, [
      [0.25, 0],
      [0.5, 0.25],
      [0.75, 0],
      [1, 0.25],
      [0.75, 0.5],
      [1, 0.75],
      [0.75, 1],
      [0.5, 0.75],
      [0.25, 1],
      [0, 0.75],
      [0.25, 0.5],
      [0, 0.25]
    ]);
  },
  diamond(params) {
    drawMarkerUnitPolygon(params, [
      [0.5, 0],
      [1, 0.5],
      [0.5, 1],
      [0, 0.5]
    ]);
  },
  heart({ path, x, y, size }) {
    const r = size / 4;
    y = y + r / 2;
    path.arc(x - r, y - r, r, toRadians2(130), toRadians2(330));
    path.arc(x + r, y - r, r, toRadians2(220), toRadians2(50));
    path.lineTo(x, y + r);
    path.closePath();
  },
  pin({ path, x, y, size: s }) {
    const cx = 0.5;
    const cy = 0.5;
    path.moveTo(x + (0.891 - cx) * s, y + (0.391 - cy) * s);
    path.cubicCurveTo(
      x + (0.891 - cx) * s,
      y + (0.606 - cy) * s,
      x + (0.5 - cx) * s,
      y + (1 - cy) * s,
      x + (0.5 - cx) * s,
      y + (1 - cy) * s
    );
    path.cubicCurveTo(
      x + (0.5 - cx) * s,
      y + (1 - cy) * s,
      x + (0.109 - cx) * s,
      y + (0.606 - cy) * s,
      x + (0.109 - cx) * s,
      y + (0.391 - cy) * s
    );
    path.cubicCurveTo(
      x + (0.109 - cx) * s,
      y + (0.175 - cy) * s,
      x + (0.284 - cx) * s,
      y + (0 - cy) * s,
      x + (0.5 - cx) * s,
      y + (0 - cy) * s
    );
    path.cubicCurveTo(
      x + (0.716 - cx) * s,
      y + (0 - cy) * s,
      x + (0.891 - cx) * s,
      y + (0.175 - cy) * s,
      x + (0.891 - cx) * s,
      y + (0.391 - cy) * s
    );
    path.closePath();
  },
  plus(params) {
    drawMarkerUnitPolygon(params, [
      [1 / 3, 0],
      [2 / 3, 0],
      [2 / 3, 1 / 3],
      [1, 1 / 3],
      [1, 2 / 3],
      [2 / 3, 2 / 3],
      [2 / 3, 1],
      [1 / 3, 1],
      [1 / 3, 2 / 3],
      [0, 2 / 3],
      [0, 1 / 3],
      [1 / 3, 1 / 3]
    ]);
  },
  square({ path, x, y, size }) {
    const hs = size / 2;
    path.moveTo(x - hs, y - hs);
    path.lineTo(x + hs, y - hs);
    path.lineTo(x + hs, y + hs);
    path.lineTo(x - hs, y + hs);
    path.closePath();
  },
  star({ path, x, y, size }) {
    const spikes = 5;
    const outerRadius = size / 2;
    const innerRadius = outerRadius / 2;
    const rotation = Math.PI / 2;
    for (let i = 0; i < spikes * 2; i++) {
      const radius = i % 2 === 0 ? outerRadius : innerRadius;
      const angle = i * Math.PI / spikes - rotation;
      const xCoordinate = x + Math.cos(angle) * radius;
      const yCoordinate = y + Math.sin(angle) * radius;
      path.lineTo(xCoordinate, yCoordinate);
    }
    path.closePath();
  },
  triangle(params) {
    drawMarkerUnitPolygon(params, [
      [0.5, 0],
      [1, 0.87],
      [0, 0.87]
    ]);
  }
};

// packages/ag-charts-community/src/chart/marker/markerPathCache.ts
var MAX_CACHE_ENTRIES = 1024;
var stringShapeCache = /* @__PURE__ */ /*#__PURE__*/ new Map();
var functionShapeCache = /* @__PURE__ */ /*#__PURE__*/ new WeakMap();
function buildPath(shape, size, pixelRatio) {
  const path = new ExtendedPath2D();
  const drawParams = { path, x: 0, y: 0, size, pixelRatio };
  if (typeof shape === "string") {
    MARKER_SHAPES[shape](drawParams);
  } else {
    shape(drawParams);
  }
  return path;
}
function getSharedMarkerPath(shape, size, pixelRatio = 1) {
  if (typeof shape === "string") {
    const key = `${shape}:${size}`;
    let path = stringShapeCache.get(key);
    if (path === void 0) {
      if (stringShapeCache.size >= MAX_CACHE_ENTRIES)
        stringShapeCache.clear();
      path = buildPath(shape, size, 1);
      stringShapeCache.set(key, path);
    }
    return path;
  }
  if (typeof shape === "function") {
    let sizeMap = functionShapeCache.get(shape);
    if (sizeMap === void 0) {
      sizeMap = /* @__PURE__ */ new Map();
      functionShapeCache.set(shape, sizeMap);
    }
    const key = `${size}:${pixelRatio}`;
    let path = sizeMap.get(key);
    if (path === void 0) {
      if (sizeMap.size >= MAX_CACHE_ENTRIES)
        sizeMap.clear();
      path = buildPath(shape, size, pixelRatio);
      sizeMap.set(key, path);
    }
    return path;
  }
  return buildPath("square", size, pixelRatio);
}

// packages/ag-charts-community/src/chart/marker/marker.ts
var PIN_ANCHOR = /*#__PURE__*/ Object.freeze({ x: 0.5, y: 1 });
var CENTRE_ANCHOR = /*#__PURE__*/ Object.freeze({ x: 0.5, y: 0.5 });
var DRAW_BBOX_SCRATCH = /*#__PURE__*/ new BBox(0, 0, 0, 0);
var FILL_BBOX_SCRATCH = /*#__PURE__*/ new BBox(0, 0, 0, 0);
var InternalMarker = /*#__PURE__*/ (() => { var _c$13 = class extends Path {
  constructor() {
    super(...arguments);
    this.shape = "square";
    this.x = 0;
    this.y = 0;
    this.size = 12;
  }
  // Path geometry is invariant to x/y (applied as a render-time translate), so x/y mutations
  // dirty the scene but not the path.
  onChangeDetection(property) {
    if (property === "__x" || property === "__y") {
      this.markDirty(property);
      return;
    }
    super.onChangeDetection(property);
  }
  isPointInPath(x, y) {
    return this.distanceSquaredLocal(x, y) <= 0;
  }
  // Exact hit-test against the shared origin-centred path; for subclasses (e.g. AnnotationShape)
  // that need geometry-accurate picking instead of the radius approximation in isPointInPath.
  isPointInSharedPath(x, y) {
    if (!this._sharedPath?.closedPath)
      return false;
    const anchor = Marker.anchor(this.shape);
    const tx = x - this.x + (anchor.x - 0.5) * this.size;
    const ty = y - this.y + (anchor.y - 0.5) * this.size;
    return this._sharedPath.isPointInPath(tx, ty);
  }
  get midPoint() {
    return { x: this.x, y: this.y };
  }
  distanceSquared(x, y) {
    return this.distanceSquaredLocal(x, y);
  }
  // Local-space hit-test, shared by both pick entry points so neither transforms twice: the
  // public distanceSquared() is transform-wrapped by the MatrixTransform mixin, while
  // isPointInPath() is reached via pickNode() which has already inverse-transformed the point.
  distanceSquaredLocal(x, y) {
    const anchor = Marker.anchor(this.shape);
    const dx = x - this.x + (anchor.x - 0.5) * this.size;
    const dy = y - this.y + (anchor.y - 0.5) * this.size;
    const radius = this.size / 2;
    return Math.max(dx * dx + dy * dy - radius * radius, 0);
  }
  // this.path is unused — geometry lives on _sharedPath. Override so Path.preRender doesn't
  // lazy-allocate an unused ExtendedPath2D per marker.
  pathComplexity() {
    return this._sharedPath?.commands.length ?? 0;
  }
  updatePath() {
    const { shape, size } = this;
    if (shape == null || !(size > 0)) {
      this._sharedPath = void 0;
      return;
    }
    const pixelRatio = this.layerManager?.canvas?.pixelRatio ?? 1;
    const pathSize = shape === "square" ? align(pixelRatio, size) : size;
    this._sharedPath = getSharedMarkerPath(shape, pathSize, pixelRatio);
  }
  computeBBox() {
    const { x, y, size } = this;
    const anchor = Marker.anchor(this.shape);
    return new BBox(x - size * anchor.x, y - size * anchor.y, size, size);
  }
  drawPath(ctx) {
    if (this._sharedPath === void 0)
      return;
    const { shape, x, y, size } = this;
    const anchor = Marker.anchor(shape);
    const ax = x - (anchor.x - 0.5) * size;
    const ay = y - (anchor.y - 0.5) * size;
    const pixelRatio = this.layerManager?.canvas?.pixelRatio ?? 1;
    const pathHalfSize = (shape === "square" ? align(pixelRatio, size) : size) / 2;
    const tx = shape === "square" ? align(pixelRatio, ax - pathHalfSize) + pathHalfSize : ax;
    const ty = shape === "square" ? align(pixelRatio, ay - pathHalfSize) + pathHalfSize : ay;
    const baseBBox = super.getBBox();
    DRAW_BBOX_SCRATCH.x = baseBBox.x - tx;
    DRAW_BBOX_SCRATCH.y = baseBBox.y - ty;
    DRAW_BBOX_SCRATCH.width = baseBBox.width;
    DRAW_BBOX_SCRATCH.height = baseBBox.height;
    let fillBBoxOverride;
    const originalFillBBox = this.__fillBBox;
    if (originalFillBBox) {
      FILL_BBOX_SCRATCH.x = originalFillBBox.x - tx;
      FILL_BBOX_SCRATCH.y = originalFillBBox.y - ty;
      FILL_BBOX_SCRATCH.width = originalFillBBox.width;
      FILL_BBOX_SCRATCH.height = originalFillBBox.height;
      fillBBoxOverride = FILL_BBOX_SCRATCH;
    }
    ctx.save();
    ctx.translate(tx, ty);
    try {
      this.fillStroke(ctx, this._sharedPath.getPath2D(), DRAW_BBOX_SCRATCH, fillBBoxOverride);
    } finally {
      ctx.restore();
    }
  }
  svgPathData(transform) {
    this.updatePathIfDirty();
    if (this._sharedPath === void 0)
      return "";
    const { shape, x, y, size } = this;
    const anchor = Marker.anchor(shape);
    const ax = x - (anchor.x - 0.5) * size;
    const ay = y - (anchor.y - 0.5) * size;
    if (transform) {
      return this._sharedPath.toSVG((px, py) => transform(px + ax, py + ay));
    }
    return this._sharedPath.toSVG((px, py) => ({ x: px + ax, y: py + ay }));
  }
  executeFill(ctx, path) {
    if (!path)
      return;
    return super.executeFill(ctx, path);
  }
  executeStroke(ctx, path) {
    if (!path)
      return;
    return super.executeStroke(ctx, path);
  }
}; __decorateClass([
  DeclaredSceneObjectChangeDetection2({ equals: TRIPLE_EQ2 })
], _c$13.prototype, "shape", 2); __decorateClass([
  DeclaredSceneChangeDetection4()
], _c$13.prototype, "x", 2); __decorateClass([
  DeclaredSceneChangeDetection4()
], _c$13.prototype, "y", 2); __decorateClass([
  DeclaredSceneChangeDetection4({ convertor: Math.abs })
], _c$13.prototype, "size", 2); return _c$13; })()
var Marker = /*#__PURE__*/ (() => (class extends Rotatable(Scalable(Translatable(InternalMarker))) {
  static anchor(shape) {
    if (shape === "pin") {
      return PIN_ANCHOR;
    } else if (typeof shape === "function" && "anchor" in shape) {
      return shape.anchor;
    }
    return CENTRE_ANCHOR;
  }
  constructor(options) {
    super(options);
    if (options?.shape != null) {
      this.shape = options.shape;
    }
  }
  /**
   * Optimised reset for animation hot paths.
   * Bypasses SceneChangeDetection decorators by writing directly to backing fields.
   *
   * This avoids per-property overhead from:
   * - Equality checks (comparing old vs new values)
   * - Change callbacks (triggering downstream updates)
   * - Object.keys() iteration
   *
   * A single markDirty() call at the end ensures the scene graph is properly invalidated.
   * WARNING: Only use for animation hot paths where performance is critical.
   */
  resetAnimationProperties(x, y, size, opacity, scalingX, scalingY) {
    const sizeChanged = this.__size !== size;
    this.__x = x;
    this.__y = y;
    this.__size = size;
    this.__opacity = opacity;
    this.resetScalingProperties(scalingX, scalingY, x, y);
    if (sizeChanged) {
      this.dirtyPath = true;
    }
    this.markDirty();
  }
  /**
   * Hot-path visibility/position write — bypasses change-detection setters and consolidates
   * dirtying into a single dirtyPath + markDirty() at the end (matches Path's onChangeDetection).
   */
  setVisibilityAndPosition(visible, shape, size, point) {
    let dirty = false;
    let shapeOrSizeChanged = false;
    if (this.__visible !== visible) {
      this.__visible = visible;
      dirty = true;
    }
    if (this.__shape !== shape) {
      this.__shape = shape;
      dirty = true;
      shapeOrSizeChanged = true;
    }
    const absSize = Math.abs(size);
    if (this.__size !== absSize) {
      this.__size = absSize;
      dirty = true;
      shapeOrSizeChanged = true;
    }
    if (point) {
      const { x, y } = point;
      if (this.__x !== x) {
        this.__x = x;
        dirty = true;
      }
      if (this.__y !== y) {
        this.__y = y;
        dirty = true;
      }
      if (this.__scalingCenterX !== x) {
        this.__scalingCenterX = x;
        dirty = true;
      }
      if (this.__scalingCenterY !== y) {
        this.__scalingCenterY = y;
        dirty = true;
      }
    }
    if (dirty) {
      if (shapeOrSizeChanged) {
        this.dirtyPath = true;
      }
      this.markDirty();
    }
  }
}))();

// packages/ag-charts-community/src/scale/categoryScale.ts
import { clamp as clamp7, dateToNumber, previousPowerOf2 } from "ag-charts-core";

// packages/ag-charts-community/src/scale/bandScale.ts
import { Logger as Logger9, clamp as clamp6 } from "ag-charts-core";
var _BandScale = /*#__PURE__*/ (() => { var _c$14 = class _BandScale extends AbstractScale {
  constructor() {
    super(...arguments);
    this.invalid = true;
    this.range = [0, 1];
    this.round = false;
    this._bandwidth = 1;
    this._step = 1;
    this._inset = 1;
    this._rawBandwidth = 1;
    /**
     * The ratio of the range that is reserved for space between bands.
     */
    this._paddingInner = 0;
    /**
     * The ratio of the range that is reserved for space before the first
     * and after the last band.
     */
    this._paddingOuter = 0;
  }
  static is(value) {
    return value instanceof _BandScale;
  }
  get bandwidth() {
    this.refresh();
    return this._bandwidth;
  }
  get step() {
    this.refresh();
    return this._step;
  }
  get inset() {
    this.refresh();
    return this._inset;
  }
  get rawBandwidth() {
    this.refresh();
    return this._rawBandwidth;
  }
  set padding(value) {
    value = clamp6(0, value, 1);
    this._paddingInner = value;
    this._paddingOuter = value;
  }
  get padding() {
    return this._paddingInner;
  }
  set paddingInner(value) {
    this.invalid = true;
    this._paddingInner = clamp6(0, value, 1);
  }
  get paddingInner() {
    return this._paddingInner;
  }
  set paddingOuter(value) {
    this.invalid = true;
    this._paddingOuter = clamp6(0, value, 1);
  }
  get paddingOuter() {
    return this._paddingOuter;
  }
  /** Override in subclass to provide band count without triggering full band materialization */
  getBandCountForUpdate() {
    return this.bands.length;
  }
  refresh() {
    if (!this.invalid)
      return;
    this.invalid = false;
    this.update();
    if (this.invalid) {
      Logger9.warnOnce("Expected update to not invalidate scale");
    }
  }
  convert(d, options) {
    this.refresh();
    const i = this.findIndex(d, options?.alignment, options?.alignmentExclusive);
    if (i == null || i < 0 || i >= this.getBandCountForUpdate()) {
      return Number.NaN;
    }
    return this.ordinalRange(i);
  }
  getDomainMinMax() {
    return unpackDomainMinMax(this.domain);
  }
  invertNearestIndex(position, alignment = "center") {
    this.refresh();
    const bandCount = this.getBandCountForUpdate();
    if (bandCount === 0)
      return -1;
    let low = 0;
    let high = bandCount - 1;
    let closestDistance = Infinity;
    let closestIndex = 0;
    while (low <= high) {
      const mid = Math.trunc((high + low) / 2);
      const p = this.ordinalRange(mid);
      const distance = p - position;
      if (distance === 0)
        return mid;
      if ((alignment === "center" || distance < 0) && Math.abs(distance) < closestDistance) {
        closestDistance = Math.abs(distance);
        closestIndex = mid;
      }
      if (p < position) {
        low = mid + 1;
      } else {
        high = mid - 1;
      }
    }
    return closestIndex;
  }
  update() {
    const [r0, r1] = this.range;
    let { _paddingInner: paddingInner } = this;
    const { _paddingOuter: paddingOuter } = this;
    const bandCount = this.getBandCountForUpdate();
    if (bandCount === 0)
      return;
    const rangeDistance = r1 - r0;
    let rawStep;
    if (bandCount === 1) {
      paddingInner = 0;
      rawStep = rangeDistance * (1 - paddingOuter * 2);
    } else {
      rawStep = rangeDistance / Math.max(1, bandCount - paddingInner + paddingOuter * 2);
    }
    const round = this.round && Math.floor(rawStep) > 0;
    const step = round ? Math.floor(rawStep) : rawStep;
    let inset = r0 + (rangeDistance - step * (bandCount - paddingInner)) / 2;
    let bandwidth = step * (1 - paddingInner);
    if (round) {
      inset = Math.round(inset);
      bandwidth = Math.round(bandwidth);
    }
    this._step = step;
    this._inset = inset;
    this._bandwidth = bandwidth;
    this._rawBandwidth = rawStep * (1 - paddingInner);
  }
  ordinalRange(i) {
    const { _inset: inset, _step: step, range: range2 } = this;
    const min = Math.min(range2[0], range2[1]);
    const max = Math.max(range2[0], range2[1]);
    return clamp6(min, inset + step * i, max);
  }
}; __decorateClass([
  Invalidating
], _c$14.prototype, "range", 2); __decorateClass([
  Invalidating
], _c$14.prototype, "round", 2); return _c$14; })()
var BandScale = _BandScale;

// packages/ag-charts-community/src/scale/categoryScale.ts
var CategoryScale = class _CategoryScale extends BandScale {
  constructor() {
    super(...arguments);
    this.type = "category";
    this.defaultTickCount = 0;
    /**
     * Maps datum to its index in the {@link domain} array.
     * Used to check for duplicate data (not allowed).
     */
    this.index = /* @__PURE__ */ new Map();
    this.indexInitialized = false;
    /**
     * Contains unique data only.
     */
    this._domain = [];
  }
  static is(value) {
    return value instanceof _CategoryScale;
  }
  set domain(values) {
    if (this._domain === values)
      return;
    this.invalid = true;
    this._domain = values;
    this.index.clear();
    this.indexInitialized = false;
  }
  get domain() {
    return this._domain;
  }
  get bands() {
    return this._domain;
  }
  normalizeDomains(...domains) {
    let normalizedDomain = void 0;
    const seenDomains = /* @__PURE__ */ new Set();
    let animatable = true;
    for (const input of domains) {
      const domain = input.domain;
      if (seenDomains.has(domain))
        continue;
      seenDomains.add(domain);
      if (normalizedDomain == null) {
        normalizedDomain = deduplicateCategories(domain);
      } else {
        animatable && (animatable = domainOrderedToNormalizedDomain(domain, normalizedDomain));
        normalizedDomain = deduplicateCategories([...normalizedDomain, ...domain]);
      }
    }
    normalizedDomain ?? (normalizedDomain = []);
    return { domain: normalizedDomain, animatable };
  }
  toDomain(_value) {
    return void 0;
  }
  invert(position, nearest = false) {
    this.refresh();
    const offset = nearest ? this.bandwidth / 2 : 0;
    const index = this.invertNearestIndex(Math.max(0, position - offset));
    const matches = nearest || position === this.ordinalRange(index);
    return matches ? this.domain[index] : void 0;
  }
  invertWithPercentage(position) {
    this.refresh();
    const index = this.invertNearestIndex(position, "left");
    const value = this.domain[index];
    if (value == null)
      return void 0;
    const width = this.bandwidth === 0 ? this.step : this.bandwidth;
    const bandStart = this.convert(value);
    const groupPercentage = width === 0 ? 0 : (position - bandStart) / width;
    return { value, groupPercentage };
  }
  ticks(params, domain = this.domain, visibleRange) {
    const { bands } = this;
    let { tickCount } = params;
    if (tickCount === 0) {
      const firstTickIndex2 = bands.length > 1 ? 1 : 0;
      const ticks2 = bands[firstTickIndex2] ? [bands[firstTickIndex2]] : [];
      return { ticks: ticks2, count: void 0, firstTickIndex: firstTickIndex2 };
    }
    let step = tickCount != null && tickCount !== 0 ? Math.trunc(bands.length / tickCount) : 1;
    step = previousPowerOf2(step);
    if (step <= 1) {
      return filterVisibleTicks(domain, false, visibleRange);
    }
    tickCount = Math.trunc(bands.length / step);
    const span = step * tickCount;
    const inset = previousPowerOf2(Math.trunc((bands.length - span) / 2));
    const vt0 = clamp7(0, Math.floor((visibleRange?.[0] ?? 0) * bands.length), bands.length);
    const vt1 = clamp7(0, Math.ceil((visibleRange?.[1] ?? 1) * bands.length), bands.length);
    const i0 = Math.floor((vt0 - inset) / step) * step + inset;
    const i1 = Math.ceil((vt1 - inset) / step) * step + inset;
    const ticks = [];
    for (let i = i0; i < i1; i += step) {
      if (i >= 0 && i < bands.length) {
        ticks.push(bands[i]);
      }
    }
    let firstTickIndex = ticks.length > 0 ? this.findIndex(ticks[0]) : void 0;
    if (firstTickIndex != null) {
      firstTickIndex = Math.floor((firstTickIndex - inset) / step);
    }
    return { ticks, count: void 0, firstTickIndex };
  }
  findIndex(value) {
    const { index, indexInitialized } = this;
    if (!indexInitialized) {
      const { domain } = this;
      for (let i = 0; i < domain.length; i++) {
        index.set(dateToNumber(domain[i]), i);
      }
      this.indexInitialized = true;
    }
    return index.get(dateToNumber(value));
  }
};
function deduplicateCategories(d) {
  let domain;
  const uniqueValues = /* @__PURE__ */ new Set();
  for (const value of d) {
    const key = dateToNumber(value);
    const lastSize = uniqueValues.size;
    uniqueValues.add(key);
    const isUniqueValue = uniqueValues.size !== lastSize;
    if (isUniqueValue) {
      domain?.push(value);
    } else {
      domain ?? (domain = d.slice(0, uniqueValues.size));
    }
  }
  return domain ?? d;
}
function domainOrderedToNormalizedDomain(domain, normalizedDomain) {
  let normalizedIndex = -1;
  for (const value of domain) {
    const normalizedNextIndex = normalizedDomain.indexOf(value);
    if (normalizedNextIndex === -1) {
      normalizedIndex = Infinity;
    } else if (normalizedNextIndex <= normalizedIndex) {
      return false;
    } else {
      normalizedIndex = normalizedNextIndex;
    }
  }
  return true;
}

// packages/ag-charts-community/src/scale/linearScale.ts
import {
  createBigIntTicks,
  createTicks,
  isBigInt,
  isDenseInterval,
  niceBigIntDomain,
  niceTicksDomain,
  range,
  tickStep
} from "ag-charts-core";

// packages/ag-charts-community/src/scale/continuousScale.ts
import { findMinMax, maxValue, minValue, toNumber as toNumber2 } from "ag-charts-core";
var _ContinuousScale = /*#__PURE__*/ (() => { var _c$15 = class _ContinuousScale extends AbstractScale {
  constructor(domain = [], range2 = []) {
    super();
    this.range = range2;
    this.defaultTickCount = _ContinuousScale.defaultTickCount;
    this.defaultClamp = false;
    // Domain caching to avoid repeated valueOf() calls in hot paths
    this._domain = [];
    this.domainNeedsValueOf = true;
    // Safe default
    this.d0Cache = Number.NaN;
    this.d1Cache = Number.NaN;
    // Exact bigint domain endpoints, retained for the full-precision convert() ratio (see convertBigInt).
    this.d0Big = void 0;
    this.d1Big = void 0;
    this.domain = domain;
  }
  static is(value) {
    return value instanceof _ContinuousScale;
  }
  get domain() {
    return this._domain;
  }
  set domain(values) {
    if (!values || values.length < 2) {
      this._domain = narrowStoredDomain(values);
      this.d0Big = this.d1Big = void 0;
      this.d0Cache = Number.NaN;
      this.d1Cache = Number.NaN;
      return;
    }
    const d0 = values[0];
    const d1 = values[1];
    if (typeof d0 === "bigint" || typeof d1 === "bigint") {
      this.d0Big = typeof d0 === "bigint" ? d0 : void 0;
      this.d1Big = typeof d1 === "bigint" ? d1 : void 0;
      this.domainNeedsValueOf = false;
      this.d0Cache = Number(d0);
      this.d1Cache = Number(d1);
      this._domain = narrowStoredDomain(values);
      return;
    }
    this.d0Big = this.d1Big = void 0;
    this._domain = narrowStoredDomain(values);
    this.domainNeedsValueOf = d0 != null && typeof d0 === "object";
    if (this.domainNeedsValueOf) {
      this.d0Cache = d0.valueOf();
      this.d1Cache = d1.valueOf();
    } else {
      this.d0Cache = Number(d0);
      this.d1Cache = Number(d1);
    }
  }
  normalizeDomains(...domains) {
    return normalizeContinuousDomains(...domains);
  }
  calcBandwidth(smallestInterval = 1, minWidth = 1) {
    const { domain } = this;
    const rangeDistance = this.getPixelRange();
    if (domain.length === 0)
      return rangeDistance;
    const intervals = Math.abs(this.d1Cache - this.d0Cache) / Number(smallestInterval) + 1;
    let bands = intervals;
    if (minWidth !== 0) {
      const maxBands = Math.floor(rangeDistance);
      bands = Math.min(bands, maxBands);
    }
    return rangeDistance / Math.max(1, bands);
  }
  convert(value, options) {
    const { domain } = this;
    if (!domain || domain.length < 2 || value == null) {
      return Number.NaN;
    }
    const { range: range2 } = this;
    const clamp8 = options?.clamp ?? this.defaultClamp;
    if (this.d0Big != null && this.d1Big != null && this.transform == null) {
      if (typeof value === "bigint" || typeof value === "number" && Number.isFinite(value)) {
        return convertBigInt(value, this.d0Big, this.d1Big, range2, clamp8);
      }
    }
    let d0 = this.d0Cache;
    let d1 = this.d1Cache;
    let x;
    if (typeof value === "number") {
      x = value;
    } else if (typeof value === "bigint") {
      x = Number(value);
    } else {
      x = value.valueOf();
    }
    if (this.transform) {
      d0 = this.transform(d0);
      d1 = this.transform(d1);
      x = this.transform(x);
    }
    if (clamp8) {
      const [start, stop] = findMinMax([d0, d1]);
      if (x < start) {
        return range2[0];
      } else if (x > stop) {
        return range2[1];
      }
    }
    if (d0 === d1) {
      return (range2[0] + range2[1]) / 2;
    } else if (x === d0) {
      return range2[0];
    } else if (x === d1) {
      return range2[1];
    }
    const r0 = range2[0];
    return r0 + (x - d0) / (d1 - d0) * (range2[1] - r0);
  }
  /**
   * Converts `value` after clamping it into the domain extent. Unlike `convert(value, { clamp: true })`,
   * which clamps the output by sorted range order, clamping the input keeps reversed domains oriented so
   * out-of-domain values map to the correct endpoint.
   */
  convertClamped(value) {
    const { d0Big, d1Big } = this;
    if (typeof value === "bigint" && d0Big != null && d1Big != null) {
      const lo2 = minValue(d0Big, d1Big);
      const hi2 = maxValue(d0Big, d1Big);
      return this.convert(minValue(hi2, maxValue(lo2, value)));
    }
    const { d0Cache, d1Cache } = this;
    const lo = Math.min(d0Cache, d1Cache);
    const hi = Math.max(d0Cache, d1Cache);
    return this.convert(Math.min(hi, Math.max(lo, toNumber2(value))));
  }
  invert(x, _nearest) {
    const { domain } = this;
    if (domain.length < 2)
      return;
    let d0 = this.d0Cache;
    let d1 = this.d1Cache;
    if (this.transform) {
      d0 = this.transform(d0);
      d1 = this.transform(d1);
    }
    const { range: range2 } = this;
    const [r0, r1] = range2;
    let d;
    if (r0 === r1) {
      d = this.toDomain((d0 + d1) / 2);
    } else {
      d = this.toDomain(d0 + (x - r0) / (r1 - r0) * (d1 - d0));
    }
    return this.transformInvert ? this.transformInvert(d) : d;
  }
  getDomainMinMax() {
    return unpackDomainMinMax(this.domain);
  }
  snapshotDomain() {
    const snapshot = this._domain.slice();
    if (this.d0Big != null)
      snapshot[0] = this.d0Big;
    if (this.d1Big != null)
      snapshot[1] = this.d1Big;
    return snapshot;
  }
  // Returns the exact (possibly bigint) endpoint stored at the given index, preferring the retained
  // bigint over its Number-narrowed copy.
  exactEndpoint(index) {
    return (index === 0 ? this.d0Big : this.d1Big) ?? this._domain[index];
  }
  // True when endpoint 0 is the minimum. Compares exact values so two bigints that narrow to the same
  // Number (differ below one ULP) are still ordered correctly, whatever the stored order.
  startIsMin() {
    return this.exactEndpoint(0) <= this.exactEndpoint(1);
  }
  get domainMin() {
    if (this._domain.length < 2)
      return this._domain.at(0);
    return this.exactEndpoint(this.startIsMin() ? 0 : 1);
  }
  get domainMax() {
    if (this._domain.length < 2)
      return this._domain.at(0);
    return this.exactEndpoint(this.startIsMin() ? 1 : 0);
  }
  getPixelRange() {
    const [a, b] = this.range;
    return Math.abs(b - a);
  }
}; _c$15.defaultTickCount = 5; return _c$15; })()
var ContinuousScale = _ContinuousScale;
function narrowStoredDomain(values) {
  return values.map((v) => typeof v === "bigint" ? Number(v) : v);
}
var BIGINT_RATIO_SCALE = 10n ** 12n;
function convertBigInt(value, d0, d1, range2, clamp8) {
  const r0 = range2[0];
  const r1 = range2[1];
  if (clamp8) {
    const lo = d0 < d1 ? d0 : d1;
    const hi = d0 < d1 ? d1 : d0;
    if (value < lo)
      return r0;
    if (value > hi)
      return r1;
  }
  if (d0 === d1) {
    return (r0 + r1) / 2;
  }
  let whole;
  let fraction = 0;
  if (typeof value === "number") {
    const truncated = Math.trunc(value);
    whole = BigInt(truncated);
    fraction = value - truncated;
  } else {
    whole = value;
  }
  if (fraction === 0) {
    if (whole === d0)
      return r0;
    if (whole === d1)
      return r1;
  }
  const span = d1 - d0;
  const ratioBig = (whole - d0) * BIGINT_RATIO_SCALE / span;
  const ratio = Number(ratioBig) / Number(BIGINT_RATIO_SCALE) + fraction / Number(span);
  return r0 + ratio * (r1 - r0);
}
function normalizeContinuousDomains(...domains) {
  let min;
  let max;
  for (const input of domains) {
    for (const d of input.domain) {
      if (min === void 0 || d < min) {
        min = d;
      }
      if (max === void 0 || d > max) {
        max = d;
      }
    }
  }
  if (min != null && max != null) {
    return { domain: [min, max], animatable: true };
  } else {
    return { domain: [], animatable: false };
  }
}

// packages/ag-charts-community/src/scale/linearScale.ts
var LinearScale = class _LinearScale extends ContinuousScale {
  constructor() {
    super([0, 1], [0, 1]);
    this.type = "number";
  }
  static is(value) {
    return value instanceof _LinearScale;
  }
  static getTickStep(start, stop, ticks) {
    const { interval, tickCount = ContinuousScale.defaultTickCount, minTickCount, maxTickCount } = ticks;
    return interval == null ? tickStep(start, stop, tickCount, minTickCount, maxTickCount) : Number(interval);
  }
  toDomain(d) {
    if (isBigInt(this.domainMin) && isBigInt(this.domainMax) && (isBigInt(d) || Number.isInteger(d))) {
      return BigInt(d);
    }
    return d;
  }
  ticks({ interval, tickCount = ContinuousScale.defaultTickCount, minTickCount, maxTickCount }, domain = this.domain, visibleRange) {
    if (!domain || domain.length < 2 || tickCount < 1) {
      return { ticks: [], count: 0, firstTickIndex: 0 };
    }
    const [b0, b1] = domain;
    const isBigIntDomain = typeof b0 === "bigint" && typeof b1 === "bigint";
    const fullRange = visibleRange == null || visibleRange[0] === 0 && visibleRange[1] === 1;
    if (isBigIntDomain && !interval && fullRange) {
      const ticks = createBigIntTicks(b0, b1, tickCount);
      return { ticks, count: ticks.length, firstTickIndex: 0 };
    }
    const numericDomain = domain.map(Number);
    if (!numericDomain.every(Number.isFinite)) {
      return { ticks: [], count: 0, firstTickIndex: 0 };
    }
    const [d0, d1] = numericDomain;
    if (interval) {
      const step = Math.abs(Number(interval));
      if (!isDenseInterval((d1 - d0) / step, this.getPixelRange())) {
        return range(d0, d1, step, visibleRange);
      }
    }
    return createTicks(d0, d1, tickCount, minTickCount, maxTickCount, visibleRange);
  }
  niceDomain(ticks, domain = this.domain) {
    if (domain.length < 2)
      return [];
    const { tickCount = ContinuousScale.defaultTickCount } = ticks;
    const [b0, b1] = domain;
    const isBigIntDomain = typeof b0 === "bigint" && typeof b1 === "bigint";
    if (isBigIntDomain && ticks.interval == null) {
      const [n0, n1] = niceBigIntDomain(b0, b1, tickCount);
      return [ticks.nice[0] ? n0 : b0, ticks.nice[1] ? n1 : b1];
    }
    const numericDomain = domain.map(Number);
    let [start, stop] = numericDomain;
    if (tickCount === 1) {
      [start, stop] = niceTicksDomain(start, stop);
    } else if (tickCount > 1) {
      const roundStart = start > stop ? Math.ceil : Math.floor;
      const roundStop = start > stop ? Math.floor : Math.ceil;
      const maxAttempts = 4;
      for (let i = 0; i < maxAttempts; i++) {
        const prev0 = start;
        const prev1 = stop;
        const step = _LinearScale.getTickStep(start, stop, ticks);
        const [d0, d1] = numericDomain;
        start = roundStart(d0 / step) * step;
        stop = roundStop(d1 / step) * step;
        if (start === prev0 && stop === prev1)
          break;
      }
    }
    return [ticks.nice[0] ? start : numericDomain[0], ticks.nice[1] ? stop : numericDomain[1]];
  }
};

// packages/ag-charts-community/src/scene/scene.ts
import { CleanupRegistry, Debug as Debug5, EventEmitter as EventEmitter2, Logger as Logger10, createId as createId3, downloadUrl } from "ag-charts-core";

// packages/ag-charts-community/src/scene/canvas/hdpiCanvas.ts
var HdpiCanvas = class {
  constructor(options) {
    this.width = 600;
    this.height = 300;
    this.direction = "ltr";
    const { width, height, willReadFrequently = false } = options;
    this.element = options.canvasElement;
    this.pixelRatio = options.pixelRatio;
    this.element.style.display = "block";
    this.element.style.width = (width ?? this.width) + "px";
    this.element.style.height = (height ?? this.height) + "px";
    this.element.width = deviceDimension(this.pixelRatio, width ?? this.width);
    this.element.height = deviceDimension(this.pixelRatio, height ?? this.height);
    this.context = this.element.getContext("2d", { willReadFrequently });
    this.context.direction = this.direction;
    this.resize(width ?? this.width, height ?? this.height, this.pixelRatio);
    debugContext(this.context);
  }
  // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents -- OffscreenCanvasRenderingContext2D is intentionally `any` for Angular 13+ compatibility (AG-6969)
  drawImage(context, dx = 0, dy = 0) {
    return context.drawImage(this.context.canvas, dx, dy);
  }
  toDataURL(type) {
    return this.element.toDataURL(type);
  }
  resize(width, height, pixelRatio) {
    if (!(width > 0 && height > 0))
      return;
    const { element, context } = this;
    element.width = deviceDimension(pixelRatio, width);
    element.height = deviceDimension(pixelRatio, height);
    context.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0);
    element.style.width = width + "px";
    element.style.height = height + "px";
    this.width = width;
    this.height = height;
    this.pixelRatio = pixelRatio;
  }
  setDirection(isRtl) {
    this.direction = isRtl ? "rtl" : "ltr";
    this.element.dir = this.direction;
    this.context.direction = this.direction;
  }
  clear() {
    clearContext(this);
  }
  destroy() {
    this.element.remove();
    this.element.width = 0;
    this.element.height = 0;
    this.context.clearRect(0, 0, 0, 0);
    Object.freeze(this);
  }
  reset() {
    this.context.reset();
    this.context.verifyDepthZero?.();
    this.context.direction = this.direction;
  }
};

// packages/ag-charts-community/src/scene/image/imageLoader.ts
import { EventEmitter, getImage } from "ag-charts-core";
var ImageLoader = class extends EventEmitter {
  constructor() {
    super(...arguments);
    this.cache = /* @__PURE__ */ new Map();
    this.imageLoadingCount = 0;
    this.destroyed = false;
  }
  loadImage(uri, affectedNode, sizeHint) {
    const cacheKey = computeCacheKey(uri, sizeHint);
    const entry = this.cache.get(cacheKey);
    if (entry?.image) {
      return entry.image;
    } else if (entry != null && affectedNode) {
      entry.nodes.add(affectedNode);
      return;
    }
    if (!affectedNode) {
      return;
    }
    const nextEntry = { image: void 0, nodes: /* @__PURE__ */ new Set([affectedNode]), blobUrl: void 0 };
    this.cache.set(cacheKey, nextEntry);
    this.imageLoadingCount++;
    const revokeBlob = () => {
      if (nextEntry.blobUrl != null) {
        URL.revokeObjectURL(nextEntry.blobUrl);
        nextEntry.blobUrl = void 0;
      }
    };
    const onSuccess = (image) => {
      if (this.destroyed) {
        revokeBlob();
        return;
      }
      nextEntry.image = image;
      for (const node of nextEntry.nodes) {
        node.markDirty();
      }
      nextEntry.nodes.clear();
      this.imageLoadingCount--;
      revokeBlob();
      this.emit("image-loaded", { uri });
    };
    const onFail = () => {
      if (this.destroyed) {
        revokeBlob();
        return;
      }
      this.imageLoadingCount--;
      nextEntry.nodes.clear();
      revokeBlob();
      this.cache.delete(cacheKey);
      this.emit("image-error", { uri });
    };
    this.resolveSource(uri, sizeHint).then((resolved) => {
      if (this.destroyed) {
        if (resolved.blobUrl != null)
          URL.revokeObjectURL(resolved.blobUrl);
        return;
      }
      if (resolved.blobUrl != null) {
        nextEntry.blobUrl = resolved.blobUrl;
      }
      const ImageCtor = getImage();
      const image = new ImageCtor();
      image.onload = () => onSuccess(image);
      image.onerror = onFail;
      image.src = resolved.src;
    }).catch(onFail);
    return void 0;
  }
  unregisterNode(node) {
    for (const entry of this.cache.values()) {
      entry.nodes.delete(node);
    }
  }
  async resolveSource(uri, sizeHint) {
    if (!sizeHint || typeof fetch !== "function" || typeof Blob === "undefined")
      return { src: uri };
    const pathSaysSvg = uriPathnameEndsWith(uri, ".svg");
    const dataUriSaysSvg = uri.startsWith("data:image/svg");
    if (!pathSaysSvg && !dataUriSaysSvg)
      return { src: uri };
    try {
      const res = await fetch(uri, { mode: "cors" });
      const contentType = res.headers.get("content-type") ?? "";
      const contentTypeKnown = contentType.startsWith("image/") || contentType.startsWith("application/");
      const contentTypeSaysSvg = contentType.includes("svg");
      if (contentTypeKnown && !contentTypeSaysSvg)
        return { src: uri };
      const text = await res.text();
      if (!contentTypeSaysSvg && !looksLikeSvgMarkup(text))
        return { src: uri };
      const sized = injectSvgSize(text, sizeHint.width, sizeHint.height);
      if (!sized)
        return { src: uri };
      const blob = new Blob([sized], { type: "image/svg+xml" });
      const blobUrl = URL.createObjectURL(blob);
      return { src: blobUrl, blobUrl };
    } catch {
      return { src: uri };
    }
  }
  waitingToLoad() {
    return this.imageLoadingCount > 0;
  }
  destroy() {
    this.destroyed = true;
    for (const entry of this.cache.values()) {
      entry.nodes.clear();
      if (entry.blobUrl != null) {
        URL.revokeObjectURL(entry.blobUrl);
        entry.blobUrl = void 0;
      }
    }
    this.cache.clear();
  }
};
function computeCacheKey(uri, sizeHint) {
  return sizeHint ? `${uri}@${sizeHint.width}x${sizeHint.height}` : uri;
}
function uriPathnameEndsWith(uri, suffix) {
  const queryStart = uri.search(/[?#]/);
  const path = queryStart >= 0 ? uri.slice(0, queryStart) : uri;
  return path.toLowerCase().endsWith(suffix);
}
var SVG_MARKUP_PREFIX = /^\uFEFF?\s{0,32}(?:<\?xml[^>]{0,256}\?>\s{0,32})?(?:<!DOCTYPE[^>]{0,256}>\s{0,32})?<svg[\s>]/i;
function looksLikeSvgMarkup(text) {
  return SVG_MARKUP_PREFIX.test(text);
}
var ABSOLUTE_SIZE = /^\s{0,8}\+?(\d{1,6}(?:\.\d{1,6})?(?:e[+-]?\d{1,3})?)\s{0,8}(?:px|pt|cm|mm|in|pc|q)?\s{0,8}$/i;
function hasAbsoluteSize(root, attr) {
  const raw = root.getAttribute(attr);
  if (raw == null)
    return false;
  const match = ABSOLUTE_SIZE.exec(raw);
  if (!match)
    return false;
  return Number.parseFloat(match[1]) > 0;
}
function injectSvgSize(svgText, width, height) {
  if (typeof DOMParser === "undefined" || typeof XMLSerializer === "undefined")
    return void 0;
  try {
    const doc = new DOMParser().parseFromString(svgText, "image/svg+xml");
    const root = doc.documentElement;
    if (root?.tagName.toLowerCase() !== "svg")
      return void 0;
    const hasWidth = hasAbsoluteSize(root, "width");
    const hasHeight = hasAbsoluteSize(root, "height");
    if (hasWidth && hasHeight)
      return void 0;
    if (!hasWidth)
      root.setAttribute("width", String(width));
    if (!hasHeight)
      root.setAttribute("height", String(height));
    return new XMLSerializer().serializeToString(root);
  } catch {
    return void 0;
  }
}

// packages/ag-charts-community/src/scene/layersManager.ts
import { Debug as Debug4 } from "ag-charts-core";
var LayersManager = class {
  constructor(canvas) {
    this.canvas = canvas;
    this.debug = Debug4.create(true, "scene");
    this.layersMap = /* @__PURE__ */ new Map();
    this.nextLayerId = 0;
  }
  get size() {
    return this.layersMap.size;
  }
  resize(width, height, pixelRatio) {
    this.canvas.resize(width, height, pixelRatio);
    for (const { canvas } of this.layersMap.values()) {
      canvas.resize(width, height, pixelRatio);
    }
  }
  addLayer(opts) {
    const { width, height, pixelRatio } = this.canvas;
    const { name } = opts;
    const canvas = new HdpiOffscreenCanvas({ width, height, pixelRatio });
    this.layersMap.set(canvas, {
      id: this.nextLayerId++,
      name,
      canvas
    });
    this.debug("Scene.addLayer() - layers", this.layersMap);
    return canvas;
  }
  removeLayer(canvas) {
    if (this.layersMap.has(canvas)) {
      this.layersMap.delete(canvas);
      canvas.destroy();
      this.debug("Scene.removeLayer() -  layers", this.layersMap);
    }
  }
  clear() {
    for (const layer of this.layersMap.values()) {
      layer.canvas.destroy();
    }
    this.layersMap.clear();
  }
};

// packages/ag-charts-community/src/scene/scene.ts
var Scene = /*#__PURE__*/ (() => { var _c$16 = class extends EventEmitter2 {
  constructor(canvasOptions) {
    super();
    this.debug = Debug5.create(true, "scene" /* SCENE */);
    this.id = createId3(this);
    this.imageLoader = new ImageLoader();
    this.root = null;
    this.pendingSize = null;
    this.isDirty = false;
    this.direction = "ltr";
    this.cleanup = new CleanupRegistry();
    this.updateDebugFlags();
    this.canvas = new HdpiCanvas(canvasOptions);
    this.layersManager = new LayersManager(this.canvas);
    this.cleanup.register(
      this.imageLoader.on("image-loaded", () => {
        this.emit("scene-changed", {});
      }),
      this.imageLoader.on("image-error", ({ uri }) => {
        Logger10.warnOnce(`Unable to load image ${uri}`);
      })
    );
  }
  waitingForUpdate() {
    return this.imageLoader?.waitingToLoad() ?? false;
  }
  get width() {
    return this.pendingSize?.[0] ?? this.canvas.width;
  }
  get height() {
    return this.pendingSize?.[1] ?? this.canvas.height;
  }
  get pixelRatio() {
    return this.pendingSize?.[2] ?? this.canvas.pixelRatio;
  }
  get isRtl() {
    return this.direction === "rtl";
  }
  /**
   * @deprecated v10.2.0 Only used by AG Grid Sparklines + Mini Charts
   *
   * DO NOT REMOVE WITHOUT FIXING THE GRID DEPENDENCIES.
   */
  setContainer(value) {
    const { element } = this.canvas;
    element.remove();
    value.appendChild(element);
    return this;
  }
  setRoot(node) {
    if (this.root === node) {
      return this;
    }
    this.isDirty = true;
    this.root?.setScene();
    this.root = node;
    if (node) {
      node.visible = true;
      node.setScene(this);
    }
    return this;
  }
  updateDebugFlags() {
    Debug5.inDevelopmentMode(() => Node._debugEnabled = true);
  }
  clearCanvas() {
    this.canvas.clear();
  }
  attachNode(node) {
    this.appendChild(node);
    return () => node.remove();
  }
  appendChild(node) {
    this.root?.appendChild(node);
    return this;
  }
  removeChild(node) {
    node.remove();
    return this;
  }
  download(fileName, fileFormat) {
    downloadUrl(this.canvas.toDataURL(fileFormat), fileName?.trim() ?? "image");
  }
  /** NOTE: Integrated Charts undocumented image download method. */
  getDataURL(fileFormat) {
    return this.canvas.toDataURL(fileFormat);
  }
  resize(width, height, pixelRatio) {
    width = Math.round(width);
    height = Math.round(height);
    pixelRatio ?? (pixelRatio = this.pixelRatio);
    if (width > 0 && height > 0 && (width !== this.width || height !== this.height || pixelRatio !== this.pixelRatio)) {
      this.pendingSize = [width, height, pixelRatio];
      this.isDirty = true;
      return true;
    }
    return false;
  }
  setDirection(isRtl) {
    this.direction = isRtl ? "rtl" : "ltr";
    this.canvas.setDirection(isRtl);
  }
  updateBaseFont() {
    const baseFont = this.root?.resolveFont();
    if (baseFont == null || baseFont === this._contextFont)
      return;
    this._baseFont = baseFont;
    if (this.pendingSize)
      return;
    this.canvas.context.font = baseFont;
    this._contextFont = baseFont;
  }
  applyPendingResize() {
    if (this.pendingSize) {
      this.layersManager.resize(...this.pendingSize);
      this.pendingSize = null;
      this._contextFont = void 0;
      if (this._baseFont != null) {
        this.canvas.context.font = this._baseFont;
        this._contextFont = this._baseFont;
      }
      return true;
    }
    return false;
  }
  render(opts) {
    const { debugSplitTimes = { start: performance.now() }, extraDebugStats, seriesRect, debugColors } = opts ?? {};
    const { canvas, canvas: { context: ctx } = {}, root, width, height, pixelRatio: devicePixelRatio } = this;
    if (!ctx) {
      return;
    }
    const statsEnabled = Debug5.check("scene:stats" /* SCENE_STATS */, "scene:stats:verbose" /* SCENE_STATS_VERBOSE */);
    if (statsEnabled) {
      this.ensureDebugStatsRegistration();
    }
    const renderStartTime = performance.now();
    const resized = this.applyPendingResize();
    if (root && !root.visible) {
      this.isDirty = false;
      return;
    }
    let rootDirty;
    if (root instanceof Group) {
      rootDirty = root.dirty;
    }
    if (root != null && rootDirty === false && !this.isDirty) {
      if (this.debug.check()) {
        this.debug("Scene.render() - no-op", {
          tree: buildTree(root, "console")
        });
      }
      if (statsEnabled) {
        debugStats(
          this.layersManager,
          debugSplitTimes,
          ctx,
          void 0,
          extraDebugStats,
          seriesRect,
          debugColors
        );
      }
      return;
    }
    const renderCtx = {
      ctx,
      direction: this.direction,
      width,
      height,
      devicePixelRatio,
      debugNodes: {},
      currentFont: this._contextFont
    };
    if (Debug5.check("scene:stats:verbose" /* SCENE_STATS_VERBOSE */)) {
      renderCtx.stats = {
        layersRendered: 0,
        layersSkipped: 0,
        nodesRendered: 0,
        nodesSkipped: 0,
        opsPerformed: 0,
        opsSkipped: 0
      };
    }
    prepareSceneNodeHighlight(renderCtx);
    let canvasCleared = false;
    if (rootDirty !== false || resized) {
      canvasCleared = true;
      canvas.clear();
    }
    if (root && Debug5.check("scene:dirtyTree" /* SCENE_DIRTY_TREE */)) {
      const { dirtyTree, paths } = buildDirtyTree(root);
      Debug5.create("scene:dirtyTree" /* SCENE_DIRTY_TREE */)("Scene.render() - dirtyTree", { dirtyTree, paths });
    }
    if (root && canvasCleared) {
      if (root.visible) {
        root.preRender(renderCtx);
      }
      if (this.debug.check()) {
        const tree = buildTree(root, "console");
        this.debug("Scene.render() - before", {
          canvasCleared,
          tree
        });
      }
      if (root.visible) {
        try {
          ctx.save();
          root.render(renderCtx);
          ctx.restore();
        } catch (e) {
          this.canvas.reset();
          throw e;
        }
      }
    }
    debugSplitTimes["\u270D\uFE0F"] = performance.now() - renderStartTime;
    ctx.verifyDepthZero?.();
    this.isDirty = false;
    if (statsEnabled) {
      debugStats(
        this.layersManager,
        debugSplitTimes,
        ctx,
        renderCtx.stats,
        extraDebugStats,
        seriesRect,
        debugColors
      );
    }
    debugSceneNodeHighlight(ctx, renderCtx.debugNodes);
    if (root && this.debug.check()) {
      this.debug("Scene.render() - after", {
        tree: buildTree(root, "console"),
        canvasCleared
      });
    }
  }
  ensureDebugStatsRegistration() {
    if (this.releaseDebugStats)
      return;
    const release = registerDebugStatsConsumer();
    const cleanup = () => {
      release();
      this.releaseDebugStats = void 0;
    };
    this.releaseDebugStats = cleanup;
    this.cleanup.register(cleanup);
  }
  toSVG() {
    const { root, width, height } = this;
    if (root == null)
      return;
    return Node.toSVG(root, width, height);
  }
  /** Alternative to destroy() that preserves re-usable resources. */
  strip() {
    const { context, pixelRatio } = this.canvas;
    context.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0);
    this.layersManager.clear();
    this.setRoot(null);
    this.isDirty = false;
    this.clear();
  }
  destroy() {
    if (this.canvas == null)
      return;
    this.strip();
    this.canvas.destroy();
    this.imageLoader.destroy();
    this.cleanup.flush();
    cleanupDebugStats();
    Object.assign(this, { canvas: void 0 });
  }
}; _c$16.className = "_c$16"; return _c$16; })()

// packages/ag-charts-community/src/scene/shape/arc.ts
import { SceneChangeDetection as SceneChangeDetection3, isNumberEqual as isNumberEqual3, normalizeAngle360 as normalizeAngle3602 } from "ag-charts-core";
var Arc = /*#__PURE__*/ (() => { var _c$17 = class extends Path {
  constructor() {
    super(...arguments);
    this.centerX = 0;
    this.centerY = 0;
    this.radius = 10;
    this.startAngle = 0;
    this.endAngle = Math.PI * 2;
    this.counterClockwise = false;
    this.type = 0 /* Open */;
  }
  get fullPie() {
    return isNumberEqual3(normalizeAngle3602(this.startAngle), normalizeAngle3602(this.endAngle));
  }
  updatePath() {
    const path = this.path;
    path.clear();
    path.arc(this.centerX, this.centerY, this.radius, this.startAngle, this.endAngle, this.counterClockwise);
    if (this.type === 1 /* Chord */) {
      path.closePath();
    } else if (this.type === 2 /* Round */ && !this.fullPie) {
      path.lineTo(this.centerX, this.centerY);
      path.closePath();
    }
  }
  computeBBox() {
    return new BBox(this.centerX - this.radius, this.centerY - this.radius, this.radius * 2, this.radius * 2);
  }
  isPointInPath(x, y) {
    const bbox = this.getBBox();
    return this.type !== 0 /* Open */ && bbox.containsPoint(x, y) && this.path.isPointInPath(x, y);
  }
}; _c$17.className = "_c$17"; __decorateClass([
  SceneChangeDetection3()
], _c$17.prototype, "centerX", 2); __decorateClass([
  SceneChangeDetection3()
], _c$17.prototype, "centerY", 2); __decorateClass([
  SceneChangeDetection3()
], _c$17.prototype, "radius", 2); __decorateClass([
  SceneChangeDetection3()
], _c$17.prototype, "startAngle", 2); __decorateClass([
  SceneChangeDetection3()
], _c$17.prototype, "endAngle", 2); __decorateClass([
  SceneChangeDetection3()
], _c$17.prototype, "counterClockwise", 2); __decorateClass([
  SceneChangeDetection3()
], _c$17.prototype, "type", 2); return _c$17; })()

// packages/ag-charts-community/src/scene/shape/line.ts
import { createSvgElement as createSvgElement11, lineDistanceSquared as lineDistanceSquared2 } from "ag-charts-core";
var Line = /*#__PURE__*/ (() => { var _c$18 = class extends Shape {
  constructor(opts = {}) {
    super(opts);
    this.x1 = 0;
    this.y1 = 0;
    this.x2 = 0;
    this.y2 = 0;
    this.fill = void 0;
    this.strokeWidth = 1;
  }
  set x(value) {
    this.x1 = value;
    this.x2 = value;
  }
  set y(value) {
    this.y1 = value;
    this.y2 = value;
  }
  get midPoint() {
    return { x: (this.x1 + this.x2) / 2, y: (this.y1 + this.y2) / 2 };
  }
  computeBBox() {
    return new BBox(
      Math.min(this.x1, this.x2),
      Math.min(this.y1, this.y2),
      Math.abs(this.x2 - this.x1),
      Math.abs(this.y2 - this.y1)
    );
  }
  isPointInPath(x, y) {
    if (this.x1 === this.x2 || this.y1 === this.y2) {
      return this.getBBox().clone().grow(this.strokeWidth / 2).containsPoint(x, y);
    }
    return false;
  }
  distanceSquared(px, py) {
    const { x1, y1, x2, y2 } = this;
    return lineDistanceSquared2(px, py, x1, y1, x2, y2, Infinity);
  }
  render(renderCtx) {
    const { ctx, devicePixelRatio } = renderCtx;
    let { x1, y1, x2, y2 } = this;
    if (x1 === x2) {
      const { strokeWidth } = this;
      const x = Math.round(x1 * devicePixelRatio) / devicePixelRatio + Math.trunc(strokeWidth * devicePixelRatio) % 2 / (devicePixelRatio * 2);
      x1 = x;
      x2 = x;
    } else if (y1 === y2) {
      const { strokeWidth } = this;
      const y = Math.round(y1 * devicePixelRatio) / devicePixelRatio + Math.trunc(strokeWidth * devicePixelRatio) % 2 / (devicePixelRatio * 2);
      y1 = y;
      y2 = y;
    }
    ctx.beginPath();
    ctx.moveTo(x1, y1);
    ctx.lineTo(x2, y2);
    this.fillStroke(ctx);
    this.fillShadow?.markClean();
    super.render(renderCtx);
  }
  toSVG() {
    if (!this.visible)
      return;
    const element = createSvgElement11("line");
    element.setAttribute("x1", String(this.x1));
    element.setAttribute("y1", String(this.y1));
    element.setAttribute("x2", String(this.x2));
    element.setAttribute("y2", String(this.y2));
    this.applySvgStrokeAttributes(element);
    return {
      elements: [element]
    };
  }
}; _c$18.className = "_c$18"; __decorateClass([
  SceneChangeDetection()
], _c$18.prototype, "x1", 2); __decorateClass([
  SceneChangeDetection()
], _c$18.prototype, "y1", 2); __decorateClass([
  SceneChangeDetection()
], _c$18.prototype, "x2", 2); __decorateClass([
  SceneChangeDetection()
], _c$18.prototype, "y2", 2); return _c$18; })()

// packages/ag-charts-community/src/scene/shape/radialColumnShape.ts
import { SceneChangeDetection as SceneChangeDetection4, angleBetween, isNumberEqual as isNumberEqual4, normalizeAngle360 as normalizeAngle3603 } from "ag-charts-core";
function rotatePoint(x, y, rotation) {
  const radius = Math.hypot(x, y);
  const angle = Math.atan2(y, x);
  const rotated = angle + rotation;
  return {
    x: Math.cos(rotated) * radius,
    y: Math.sin(rotated) * radius
  };
}
var RadialColumnShape = /*#__PURE__*/ (() => { var _c$19 = class extends Path {
  constructor() {
    super(...arguments);
    this.isBeveled = true;
    this.columnWidth = 0;
    this.startAngle = 0;
    this.endAngle = 0;
    this.outerRadius = 0;
    this.innerRadius = 0;
    this.axisInnerRadius = 0;
    this.axisOuterRadius = 0;
  }
  set cornerRadius(_value) {
  }
  computeBBox() {
    const { columnWidth } = this;
    const [innerRadius, outerRadius] = this.normalizeRadii(this.innerRadius, this.outerRadius);
    const rotation = this.getRotation();
    const left = -columnWidth / 2;
    const right = columnWidth / 2;
    const top = -outerRadius;
    const bottom = -innerRadius;
    let x0 = Infinity;
    let y0 = Infinity;
    let x1 = -Infinity;
    let y1 = -Infinity;
    for (let i = 0; i < 4; i += 1) {
      const { x, y } = rotatePoint(i % 2 === 0 ? left : right, i < 2 ? top : bottom, rotation);
      x0 = Math.min(x, x0);
      y0 = Math.min(y, y0);
      x1 = Math.max(x, x1);
      y1 = Math.max(y, y1);
    }
    return new BBox(x0, y0, x1 - x0, y1 - y0);
  }
  getRotation() {
    const { startAngle, endAngle } = this;
    const midAngle = angleBetween(startAngle, endAngle);
    return normalizeAngle3603(startAngle + midAngle / 2 + Math.PI / 2);
  }
  normalizeRadii(innerRadius, outerRadius) {
    if (innerRadius > outerRadius) {
      return [outerRadius, innerRadius];
    }
    return [innerRadius, outerRadius];
  }
  updatePath() {
    const { isBeveled } = this;
    if (isBeveled) {
      this.updateBeveledPath();
    } else {
      this.updateRectangularPath();
    }
    this.checkPathDirty();
  }
  updateRectangularPath() {
    const { columnWidth, path } = this;
    const [innerRadius, outerRadius] = this.normalizeRadii(this.innerRadius, this.outerRadius);
    const left = -columnWidth / 2;
    const right = columnWidth / 2;
    const top = -outerRadius;
    const bottom = -innerRadius;
    const rotation = this.getRotation();
    const points = [
      [left, bottom],
      [left, top],
      [right, top],
      [right, bottom]
    ].map(([x, y]) => rotatePoint(x, y, rotation));
    path.clear(true);
    path.moveTo(points[0].x, points[0].y);
    path.lineTo(points[1].x, points[1].y);
    path.lineTo(points[2].x, points[2].y);
    path.lineTo(points[3].x, points[3].y);
    path.closePath();
  }
  calculateCircleIntersection(x, radiusSquared) {
    const xSquared = x * x;
    if (radiusSquared < xSquared) {
      return null;
    }
    const y = -Math.sqrt(radiusSquared - xSquared);
    const angle = Math.atan2(y, x);
    return { y, angle };
  }
  calculateBothIntersections(left, right, radius) {
    const radiusSquared = radius * radius;
    const leftInt = this.calculateCircleIntersection(left, radiusSquared);
    const rightInt = this.calculateCircleIntersection(right, radiusSquared);
    if (!leftInt || !rightInt) {
      return null;
    }
    return { left: leftInt, right: rightInt };
  }
  calculateAxisOuterIntersections(left, right, axisOuterRadius) {
    const axisOuterRadiusSquared = axisOuterRadius * axisOuterRadius;
    const axisOuterLeft = this.calculateCircleIntersection(left, axisOuterRadiusSquared);
    const axisOuterRight = this.calculateCircleIntersection(right, axisOuterRadiusSquared);
    if (!axisOuterLeft || !axisOuterRight) {
      return null;
    }
    return {
      left: axisOuterLeft,
      right: axisOuterRight,
      radiusSquared: axisOuterRadiusSquared
    };
  }
  moveToRotated(x, y, rotation) {
    const point = rotatePoint(x, y, rotation);
    this.path.moveTo(point.x, point.y);
  }
  lineToRotated(x, y, rotation) {
    const point = rotatePoint(x, y, rotation);
    this.path.lineTo(point.x, point.y);
  }
  renderTopWithCornerClipping(axisOuterRadius, axisOuter, geometry) {
    const { path } = this;
    const { right, top, rotation } = geometry;
    const topSquared = top * top;
    const topIntersectionSquared = axisOuter.radiusSquared - topSquared;
    if (topIntersectionSquared <= 0) {
      this.lineToRotated(right, axisOuter.right.y, rotation);
      path.arc(0, 0, axisOuterRadius, rotation + axisOuter.right.angle, rotation + axisOuter.left.angle, true);
    } else {
      const topIntersectionX = Math.sqrt(topIntersectionSquared);
      const topRightAngle = Math.atan2(top, topIntersectionX);
      const topLeftAngle = Math.atan2(top, -topIntersectionX);
      this.lineToRotated(right, axisOuter.right.y, rotation);
      path.arc(0, 0, axisOuterRadius, rotation + axisOuter.right.angle, rotation + topRightAngle, true);
      this.lineToRotated(-topIntersectionX, top, rotation);
      path.arc(0, 0, axisOuterRadius, rotation + topLeftAngle, rotation + axisOuter.left.angle, true);
    }
  }
  updateBeveledPath() {
    const { columnWidth, path, axisInnerRadius, axisOuterRadius } = this;
    const [innerRadius, outerRadius] = this.normalizeRadii(this.innerRadius, this.outerRadius);
    const left = -columnWidth / 2;
    const right = columnWidth / 2;
    const top = -outerRadius;
    const bottom = -innerRadius;
    const rotation = this.getRotation();
    const isTouchingInner = isNumberEqual4(innerRadius, axisInnerRadius);
    const isTouchingOuter = isNumberEqual4(outerRadius, axisOuterRadius);
    const topCornersBreach = Math.hypot(left, top) > axisOuterRadius || Math.hypot(right, top) > axisOuterRadius;
    if (!isTouchingInner && !isTouchingOuter && !topCornersBreach) {
      this.updateRectangularPath();
      return;
    }
    const inner = isTouchingInner ? this.calculateBothIntersections(left, right, innerRadius) : null;
    const outer = isTouchingOuter ? this.calculateBothIntersections(left, right, outerRadius) : null;
    const axisOuter = topCornersBreach ? this.calculateAxisOuterIntersections(left, right, axisOuterRadius) : null;
    if (isTouchingInner && !inner || isTouchingOuter && !outer || topCornersBreach && !axisOuter) {
      this.updateRectangularPath();
      return;
    }
    path.clear(true);
    const geometry = { left, right, top, bottom, rotation };
    if (inner) {
      this.moveToRotated(left, inner.left.y, rotation);
    } else {
      this.moveToRotated(left, bottom, rotation);
    }
    if (inner) {
      path.arc(0, 0, innerRadius, rotation + inner.left.angle, rotation + inner.right.angle, false);
    } else {
      this.lineToRotated(right, bottom, rotation);
    }
    if (outer) {
      this.lineToRotated(right, outer.right.y, rotation);
      path.arc(0, 0, outerRadius, rotation + outer.right.angle, rotation + outer.left.angle, true);
    } else if (axisOuter) {
      this.renderTopWithCornerClipping(axisOuterRadius, axisOuter, geometry);
    } else {
      this.lineToRotated(right, top, rotation);
      this.lineToRotated(left, top, rotation);
    }
    path.closePath();
  }
}; _c$19.className = "_c$19"; __decorateClass([
  SceneChangeDetection4()
], _c$19.prototype, "isBeveled", 2); __decorateClass([
  SceneChangeDetection4()
], _c$19.prototype, "columnWidth", 2); __decorateClass([
  SceneChangeDetection4()
], _c$19.prototype, "startAngle", 2); __decorateClass([
  SceneChangeDetection4()
], _c$19.prototype, "endAngle", 2); __decorateClass([
  SceneChangeDetection4()
], _c$19.prototype, "outerRadius", 2); __decorateClass([
  SceneChangeDetection4()
], _c$19.prototype, "innerRadius", 2); __decorateClass([
  SceneChangeDetection4()
], _c$19.prototype, "axisInnerRadius", 2); __decorateClass([
  SceneChangeDetection4()
], _c$19.prototype, "axisOuterRadius", 2); return _c$19; })()
function getRadialColumnWidth(startAngle, endAngle, axisOuterRadius, columnWidthRatio, maxColumnWidthRatio) {
  const rotation = angleBetween(startAngle, endAngle);
  const pad = rotation * (1 - columnWidthRatio) / 2;
  startAngle += pad;
  endAngle -= pad;
  if (rotation < 1e-3) {
    return 2 * axisOuterRadius * maxColumnWidthRatio;
  }
  if (rotation >= 2 * Math.PI) {
    const midAngle = startAngle + rotation / 2;
    startAngle = midAngle - Math.PI;
    endAngle = midAngle + Math.PI;
  }
  const startX = axisOuterRadius * Math.cos(startAngle);
  const startY = axisOuterRadius * Math.sin(startAngle);
  const endX = axisOuterRadius * Math.cos(endAngle);
  const endY = axisOuterRadius * Math.sin(endAngle);
  const colWidth = Math.floor(Math.hypot(startX - endX, startY - endY));
  const maxWidth = 2 * axisOuterRadius * maxColumnWidthRatio;
  return Math.max(1, Math.min(maxWidth, colWidth));
}

// packages/ag-charts-community/src/scene/shape/sector.ts
import { SceneChangeDetection as SceneChangeDetection5, SceneObjectChangeDetection as SceneObjectChangeDetection2 } from "ag-charts-core";

// packages/ag-charts-community/src/scene/sectorBox.ts
var SectorBox = class _SectorBox {
  constructor(startAngle, endAngle, innerRadius, outerRadius) {
    this.startAngle = startAngle;
    this.endAngle = endAngle;
    this.innerRadius = innerRadius;
    this.outerRadius = outerRadius;
  }
  clone() {
    const { startAngle, endAngle, innerRadius, outerRadius } = this;
    return new _SectorBox(startAngle, endAngle, innerRadius, outerRadius);
  }
  equals(other) {
    return this.startAngle === other.startAngle && this.endAngle === other.endAngle && this.innerRadius === other.innerRadius && this.outerRadius === other.outerRadius;
  }
  [interpolate](other, d) {
    return new _SectorBox(
      this.startAngle * (1 - d) + other.startAngle * d,
      this.endAngle * (1 - d) + other.endAngle * d,
      this.innerRadius * (1 - d) + other.innerRadius * d,
      this.outerRadius * (1 - d) + other.outerRadius * d
    );
  }
};

// packages/ag-charts-community/src/scene/util/sector.ts
import { angleBetween as angleBetween2, isBetweenAngles, normalizeAngle180, normalizeAngle360 as normalizeAngle3604 } from "ag-charts-core";
function sectorBox({ startAngle, endAngle, innerRadius, outerRadius }) {
  let x0 = Infinity;
  let y0 = Infinity;
  let x1 = -Infinity;
  let y1 = -Infinity;
  const addPoint = (x, y) => {
    x0 = Math.min(x, x0);
    y0 = Math.min(y, y0);
    x1 = Math.max(x, x1);
    y1 = Math.max(y, y1);
  };
  addPoint(innerRadius * Math.cos(startAngle), innerRadius * Math.sin(startAngle));
  addPoint(innerRadius * Math.cos(endAngle), innerRadius * Math.sin(endAngle));
  addPoint(outerRadius * Math.cos(startAngle), outerRadius * Math.sin(startAngle));
  addPoint(outerRadius * Math.cos(endAngle), outerRadius * Math.sin(endAngle));
  if (isBetweenAngles(0, startAngle, endAngle)) {
    addPoint(outerRadius, 0);
  }
  if (isBetweenAngles(Math.PI * 0.5, startAngle, endAngle)) {
    addPoint(0, outerRadius);
  }
  if (isBetweenAngles(Math.PI, startAngle, endAngle)) {
    addPoint(-outerRadius, 0);
  }
  if (isBetweenAngles(Math.PI * 1.5, startAngle, endAngle)) {
    addPoint(0, -outerRadius);
  }
  return new BBox(x0, y0, x1 - x0, y1 - y0);
}
function isPointInSector(x, y, sector) {
  const radius = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
  const { innerRadius, outerRadius } = sector;
  if (sector.startAngle === sector.endAngle || radius < Math.min(innerRadius, outerRadius) || radius > Math.max(innerRadius, outerRadius)) {
    return false;
  }
  const startAngle = normalizeAngle180(sector.startAngle);
  const endAngle = normalizeAngle180(sector.endAngle);
  const angle = Math.atan2(y, x);
  return startAngle < endAngle ? angle <= endAngle && angle >= startAngle : angle <= endAngle && angle >= -Math.PI || angle >= startAngle && angle <= Math.PI;
}
function radiiScalingFactor(r, sweep, a, b) {
  if (a === 0 && b === 0)
    return 0;
  const fs1 = Math.asin(Math.abs(1 * a) / (r + 1 * a)) + Math.asin(Math.abs(1 * b) / (r + 1 * b)) - sweep;
  if (fs1 < 0)
    return 1;
  let start = 0;
  let end2 = 1;
  for (let i = 0; i < 8; i += 1) {
    const s = (start + end2) / 2;
    const fs = Math.asin(Math.abs(s * a) / (r + s * a)) + Math.asin(Math.abs(s * b) / (r + s * b)) - sweep;
    if (fs < 0) {
      start = s;
    } else {
      end2 = s;
    }
  }
  return start;
}
var delta2 = 1e-6;
function clockwiseAngle(angle, relativeToStartAngle) {
  if (angleBetween2(angle, relativeToStartAngle) < delta2) {
    return relativeToStartAngle;
  } else {
    return normalizeAngle3604(angle - relativeToStartAngle) + relativeToStartAngle;
  }
}
function clockwiseAngles(startAngle, endAngle, relativeToStartAngle = 0) {
  const fullPie = Math.abs(endAngle - startAngle) >= 2 * Math.PI - delta2;
  const sweepAngle = fullPie ? 2 * Math.PI : normalizeAngle3604(endAngle - startAngle);
  startAngle = clockwiseAngle(startAngle, relativeToStartAngle);
  endAngle = startAngle + sweepAngle;
  return { startAngle, endAngle };
}
function arcRadialLineIntersectionAngle(cx, cy, r, startAngle, endAngle, clipAngle) {
  const sinA = Math.sin(clipAngle);
  const cosA = Math.cos(clipAngle);
  const c = cx ** 2 + cy ** 2 - r ** 2;
  let p0x;
  let p0y;
  let p1x;
  let p1y;
  if (cosA > 0.5) {
    const tanA = sinA / cosA;
    const a = 1 + tanA ** 2;
    const b = -2 * (cx + cy * tanA);
    const d = b ** 2 - 4 * a * c;
    if (d < 0)
      return;
    const x0 = (-b + Math.sqrt(d)) / (2 * a);
    const x1 = (-b - Math.sqrt(d)) / (2 * a);
    p0x = x0;
    p0y = x0 * tanA;
    p1x = x1;
    p1y = x1 * tanA;
  } else {
    const cotA = cosA / sinA;
    const a = 1 + cotA ** 2;
    const b = -2 * (cy + cx * cotA);
    const d = b ** 2 - 4 * a * c;
    if (d < 0)
      return;
    const y0 = (-b + Math.sqrt(d)) / (2 * a);
    const y1 = (-b - Math.sqrt(d)) / (2 * a);
    p0x = y0 * cotA;
    p0y = y0;
    p1x = y1 * cotA;
    p1y = y1;
  }
  const normalisedX = cosA;
  const normalisedY = sinA;
  const p0DotNormalized = p0x * normalisedX + p0y * normalisedY;
  const p1DotNormalized = p1x * normalisedX + p1y * normalisedY;
  const a0 = p0DotNormalized > 0 ? clockwiseAngle(Math.atan2(p0y - cy, p0x - cx), startAngle) : Number.NaN;
  const a1 = p1DotNormalized > 0 ? clockwiseAngle(Math.atan2(p1y - cy, p1x - cx), startAngle) : Number.NaN;
  if (a0 >= startAngle && a0 <= endAngle) {
    return a0;
  } else if (a1 >= startAngle && a1 <= endAngle) {
    return a1;
  }
}
function arcCircleIntersectionAngle(cx, cy, r, startAngle, endAngle, circleR) {
  const d = Math.hypot(cx, cy);
  const d1 = (d ** 2 - r ** 2 + circleR ** 2) / (2 * d);
  const d2 = d - d1;
  const theta = Math.atan2(cy, cx);
  const deltaTheta = Math.acos(-d2 / r);
  const a0 = clockwiseAngle(theta + deltaTheta, startAngle);
  const a1 = clockwiseAngle(theta - deltaTheta, startAngle);
  if (a0 >= startAngle && a0 <= endAngle) {
    return a0;
  } else if (a1 >= startAngle && a1 <= endAngle) {
    return a1;
  }
}

// packages/ag-charts-community/src/scene/shape/sector.ts
var Arc2 = class {
  constructor(cx, cy, r, a0, a1) {
    this.cx = cx;
    this.cy = cy;
    this.r = r;
    this.a0 = a0;
    this.a1 = a1;
    if (this.a0 >= this.a1) {
      this.a0 = Number.NaN;
      this.a1 = Number.NaN;
    }
  }
  isValid() {
    return Number.isFinite(this.a0) && Number.isFinite(this.a1);
  }
  pointAt(a) {
    return {
      x: this.cx + this.r * Math.cos(a),
      y: this.cy + this.r * Math.sin(a)
    };
  }
  clipStart(a) {
    if (a == null || !this.isValid() || a < this.a0)
      return;
    this.a0 = a;
    if (Number.isNaN(a) || this.a0 >= this.a1) {
      this.a0 = Number.NaN;
      this.a1 = Number.NaN;
    }
  }
  clipEnd(a) {
    if (a == null || !this.isValid() || a > this.a1)
      return;
    this.a1 = a;
    if (Number.isNaN(a) || this.a0 >= this.a1) {
      this.a0 = Number.NaN;
      this.a1 = Number.NaN;
    }
  }
};
var Sector = /*#__PURE__*/ (() => { var _c$20 = class extends Path {
  constructor() {
    super(...arguments);
    this.centerX = 0;
    this.centerY = 0;
    this.innerRadius = 10;
    this.outerRadius = 20;
    this.startAngle = 0;
    this.endAngle = Math.PI * 2;
    this.clipSector = void 0;
    this.concentricEdgeInset = 0;
    this.radialEdgeInset = 0;
    this.startOuterCornerRadius = 0;
    this.endOuterCornerRadius = 0;
    this.startInnerCornerRadius = 0;
    this.endInnerCornerRadius = 0;
  }
  set inset(value) {
    this.concentricEdgeInset = value;
    this.radialEdgeInset = value;
  }
  set cornerRadius(value) {
    this.startOuterCornerRadius = value;
    this.endOuterCornerRadius = value;
    this.startInnerCornerRadius = value;
    this.endInnerCornerRadius = value;
  }
  computeBBox() {
    return sectorBox(this).translate(this.centerX, this.centerY);
  }
  normalizedRadii() {
    const { concentricEdgeInset } = this;
    let { innerRadius, outerRadius } = this;
    innerRadius = innerRadius > 0 ? innerRadius + concentricEdgeInset : 0;
    outerRadius = Math.max(outerRadius - concentricEdgeInset, 0);
    return { innerRadius, outerRadius };
  }
  normalizedClipSector() {
    const { clipSector } = this;
    if (clipSector == null)
      return;
    const { startAngle, endAngle } = clockwiseAngles(this.startAngle, this.endAngle);
    const { innerRadius, outerRadius } = this.normalizedRadii();
    const clipAngles = clockwiseAngles(clipSector.startAngle, clipSector.endAngle, startAngle);
    return new SectorBox(
      Math.max(startAngle, clipAngles.startAngle),
      Math.min(endAngle, clipAngles.endAngle),
      Math.max(innerRadius, clipSector.innerRadius),
      Math.min(outerRadius, clipSector.outerRadius)
    );
  }
  getAngleOffset(radius) {
    return radius > 0 ? this.radialEdgeInset / radius : 0;
  }
  arc(r, angleSweep, a0, a1, outerArc, innerArc, start, inner) {
    if (r <= 0)
      return;
    const { startAngle, endAngle } = clockwiseAngles(this.startAngle, this.endAngle);
    const { innerRadius, outerRadius } = this.normalizedRadii();
    const clipSector = this.normalizedClipSector();
    if (inner && innerRadius <= 0)
      return;
    const angleOffset = inner ? this.getAngleOffset(innerRadius + r) : this.getAngleOffset(outerRadius - r);
    const angle = start ? startAngle + angleOffset + angleSweep : endAngle - angleOffset - angleSweep;
    const radius = inner ? innerRadius + r : outerRadius - r;
    const cx = radius * Math.cos(angle);
    const cy = radius * Math.sin(angle);
    if (clipSector != null) {
      const delta3 = 1e-6;
      if (!start && !(angle >= startAngle - delta3 && angle <= clipSector.endAngle - delta3))
        return;
      if (start && !(angle >= clipSector.startAngle + delta3 && angle <= endAngle - delta3))
        return;
      if (inner && radius < clipSector.innerRadius - delta3)
        return;
      if (!inner && radius > clipSector.outerRadius + delta3)
        return;
    }
    const arc = new Arc2(cx, cy, r, a0, a1);
    if (clipSector != null) {
      if (inner) {
        arc.clipStart(arcRadialLineIntersectionAngle(cx, cy, r, a0, a1, clipSector.endAngle));
        arc.clipEnd(arcRadialLineIntersectionAngle(cx, cy, r, a0, a1, clipSector.startAngle));
      } else {
        arc.clipStart(arcRadialLineIntersectionAngle(cx, cy, r, a0, a1, clipSector.startAngle));
        arc.clipEnd(arcRadialLineIntersectionAngle(cx, cy, r, a0, a1, clipSector.endAngle));
      }
      let circleClipStart;
      let circleClipEnd;
      if (start) {
        circleClipStart = arcCircleIntersectionAngle(cx, cy, r, a0, a1, clipSector.innerRadius);
        circleClipEnd = arcCircleIntersectionAngle(cx, cy, r, a0, a1, clipSector.outerRadius);
      } else {
        circleClipStart = arcCircleIntersectionAngle(cx, cy, r, a0, a1, clipSector.outerRadius);
        circleClipEnd = arcCircleIntersectionAngle(cx, cy, r, a0, a1, clipSector.innerRadius);
      }
      arc.clipStart(circleClipStart);
      arc.clipEnd(circleClipEnd);
      if (circleClipStart != null) {
        const { x: x2, y: y2 } = arc.pointAt(circleClipStart);
        const theta2 = clockwiseAngle(Math.atan2(y2, x2), startAngle);
        if (start) {
          innerArc?.clipStart(theta2);
        } else {
          outerArc.clipEnd(theta2);
        }
      }
      if (circleClipEnd != null) {
        const { x: x2, y: y2 } = arc.pointAt(circleClipEnd);
        const theta2 = clockwiseAngle(Math.atan2(y2, x2), startAngle);
        if (start) {
          outerArc.clipStart(theta2);
        } else {
          innerArc?.clipEnd(theta2);
        }
      }
    }
    if (clipSector != null) {
      const { x: x2, y: y2 } = arc.pointAt((arc.a0 + arc.a1) / 2);
      if (!isPointInSector(x2, y2, clipSector))
        return;
    }
    const { x, y } = arc.pointAt(start === inner ? arc.a0 : arc.a1);
    const theta = clockwiseAngle(Math.atan2(y, x), startAngle);
    const radialArc = inner ? innerArc : outerArc;
    if (start) {
      radialArc?.clipStart(theta);
    } else {
      radialArc?.clipEnd(theta);
    }
    return arc;
  }
  updatePath() {
    const delta3 = 1e-6;
    const { path, centerX, centerY, concentricEdgeInset, radialEdgeInset } = this;
    let { startOuterCornerRadius, endOuterCornerRadius, startInnerCornerRadius, endInnerCornerRadius } = this;
    const { startAngle, endAngle } = clockwiseAngles(this.startAngle, this.endAngle);
    const { innerRadius, outerRadius } = this.normalizedRadii();
    const clipSector = this.normalizedClipSector();
    const sweepAngle = endAngle - startAngle;
    const fullPie = sweepAngle >= 2 * Math.PI - delta3;
    path.clear();
    const innerAngleOffset = this.getAngleOffset(innerRadius);
    const adjustedSweep = sweepAngle - 2 * innerAngleOffset;
    const radialLength = outerRadius - innerRadius;
    const innerCornerDistance = innerRadius > 0 && adjustedSweep > 0 ? 2 * innerRadius * Math.sin(adjustedSweep / 2) : 0;
    const outerCornerDistance = outerRadius > 0 && adjustedSweep > 0 ? 2 * outerRadius * Math.sin(adjustedSweep / 2) : 0;
    startOuterCornerRadius = Math.floor(
      Math.max(0, Math.min(startOuterCornerRadius, outerCornerDistance / 2, radialLength / 2))
    );
    endOuterCornerRadius = Math.floor(
      Math.max(0, Math.min(endOuterCornerRadius, outerCornerDistance / 2, radialLength / 2))
    );
    startInnerCornerRadius = Math.floor(
      Math.max(0, Math.min(startInnerCornerRadius, innerCornerDistance / 2, radialLength / 2))
    );
    endInnerCornerRadius = Math.floor(
      Math.max(0, Math.min(endInnerCornerRadius, innerCornerDistance / 2, radialLength / 2))
    );
    const isInvalid = innerRadius === 0 && outerRadius === 0 || innerRadius > outerRadius || innerCornerDistance < 0 || outerCornerDistance <= 0;
    if (isInvalid) {
      return;
    } else if ((clipSector?.startAngle ?? startAngle) === (clipSector?.endAngle ?? endAngle)) {
      return;
    } else if (fullPie && this.clipSector == null && startOuterCornerRadius === 0 && endOuterCornerRadius === 0 && startInnerCornerRadius === 0 && endInnerCornerRadius === 0) {
      path.moveTo(centerX + outerRadius * Math.cos(startAngle), centerY + outerRadius * Math.sin(startAngle));
      path.arc(centerX, centerY, outerRadius, startAngle, endAngle);
      if (innerRadius > concentricEdgeInset) {
        path.moveTo(centerX + innerRadius * Math.cos(endAngle), centerY + innerRadius * Math.sin(endAngle));
        path.arc(centerX, centerY, innerRadius, endAngle, startAngle, true);
      }
      path.closePath();
      return;
    } else if (this.clipSector == null && Math.abs(innerRadius - outerRadius) < 1e-6) {
      path.arc(centerX, centerY, outerRadius, startAngle, endAngle, false);
      path.arc(centerX, centerY, outerRadius, endAngle, startAngle, true);
      path.closePath();
      return;
    }
    const outerAngleOffset = this.getAngleOffset(outerRadius);
    const outerAngleExceeded = sweepAngle < 2 * outerAngleOffset;
    if (outerAngleExceeded)
      return;
    const hasInnerSweep = (clipSector?.innerRadius ?? innerRadius) > concentricEdgeInset;
    const innerAngleExceeded = innerRadius < concentricEdgeInset || sweepAngle < 2 * innerAngleOffset;
    const maxRadialLength = Math.max(
      startOuterCornerRadius,
      startInnerCornerRadius,
      endOuterCornerRadius,
      endInnerCornerRadius
    );
    const initialScalingFactor = maxRadialLength > 0 ? Math.min(radialLength / maxRadialLength, 1) : 1;
    startOuterCornerRadius *= initialScalingFactor;
    endOuterCornerRadius *= initialScalingFactor;
    startInnerCornerRadius *= initialScalingFactor;
    endInnerCornerRadius *= initialScalingFactor;
    const outerScalingFactor = radiiScalingFactor(
      outerRadius,
      sweepAngle - 2 * outerAngleOffset,
      -startOuterCornerRadius,
      -endOuterCornerRadius
    );
    startOuterCornerRadius *= outerScalingFactor;
    endOuterCornerRadius *= outerScalingFactor;
    if (!innerAngleExceeded && hasInnerSweep) {
      const innerScalingFactor = radiiScalingFactor(
        innerRadius,
        sweepAngle - 2 * innerAngleOffset,
        startInnerCornerRadius,
        endInnerCornerRadius
      );
      startInnerCornerRadius *= innerScalingFactor;
      endInnerCornerRadius *= innerScalingFactor;
    } else {
      startInnerCornerRadius = 0;
      endInnerCornerRadius = 0;
    }
    const maxCombinedRadialLength = Math.max(
      startOuterCornerRadius + startInnerCornerRadius,
      endOuterCornerRadius + endInnerCornerRadius
    );
    const edgesScalingFactor = maxCombinedRadialLength > 0 ? Math.min(radialLength / maxCombinedRadialLength, 1) : 1;
    startOuterCornerRadius *= edgesScalingFactor;
    endOuterCornerRadius *= edgesScalingFactor;
    startInnerCornerRadius *= edgesScalingFactor;
    endInnerCornerRadius *= edgesScalingFactor;
    let startOuterCornerRadiusAngleSweep = 0;
    let endOuterCornerRadiusAngleSweep = 0;
    const startOuterCornerRadiusSweep = startOuterCornerRadius / (outerRadius - startOuterCornerRadius);
    const endOuterCornerRadiusSweep = endOuterCornerRadius / (outerRadius - endOuterCornerRadius);
    if (startOuterCornerRadiusSweep >= 0 && startOuterCornerRadiusSweep < 1 - delta3) {
      startOuterCornerRadiusAngleSweep = Math.asin(startOuterCornerRadiusSweep);
    } else {
      startOuterCornerRadiusAngleSweep = sweepAngle / 2;
      const maxStartOuterCornerRadius = outerRadius / (1 / Math.sin(startOuterCornerRadiusAngleSweep) + 1);
      startOuterCornerRadius = Math.min(maxStartOuterCornerRadius, startOuterCornerRadius);
    }
    if (endOuterCornerRadiusSweep >= 0 && endOuterCornerRadiusSweep < 1 - delta3) {
      endOuterCornerRadiusAngleSweep = Math.asin(endOuterCornerRadiusSweep);
    } else {
      endOuterCornerRadiusAngleSweep = sweepAngle / 2;
      const maxEndOuterCornerRadius = outerRadius / (1 / Math.sin(endOuterCornerRadiusAngleSweep) + 1);
      endOuterCornerRadius = Math.min(maxEndOuterCornerRadius, endOuterCornerRadius);
    }
    const startInnerCornerRadiusAngleSweep = Math.asin(
      startInnerCornerRadius / (innerRadius + startInnerCornerRadius)
    );
    const endInnerCornerRadiusAngleSweep = Math.asin(endInnerCornerRadius / (innerRadius + endInnerCornerRadius));
    const outerArcRadius = clipSector?.outerRadius ?? outerRadius;
    const outerArcRadiusOffset = this.getAngleOffset(outerArcRadius);
    const outerArc = new Arc2(
      0,
      0,
      outerArcRadius,
      startAngle + outerArcRadiusOffset,
      endAngle - outerArcRadiusOffset
    );
    const innerArcRadius = clipSector?.innerRadius ?? innerRadius;
    const innerArcRadiusOffset = this.getAngleOffset(innerArcRadius);
    const innerArc = hasInnerSweep ? new Arc2(0, 0, innerArcRadius, startAngle + innerArcRadiusOffset, endAngle - innerArcRadiusOffset) : void 0;
    if (clipSector != null) {
      outerArc.clipStart(clipSector.startAngle);
      outerArc.clipEnd(clipSector.endAngle);
      innerArc?.clipStart(clipSector.startAngle);
      innerArc?.clipEnd(clipSector.endAngle);
    }
    const startOuterArc = this.arc(
      startOuterCornerRadius,
      startOuterCornerRadiusAngleSweep,
      startAngle - Math.PI * 0.5,
      startAngle + startOuterCornerRadiusAngleSweep,
      outerArc,
      innerArc,
      true,
      false
    );
    const endOuterArc = this.arc(
      endOuterCornerRadius,
      endOuterCornerRadiusAngleSweep,
      endAngle - endOuterCornerRadiusAngleSweep,
      endAngle + Math.PI * 0.5,
      outerArc,
      innerArc,
      false,
      false
    );
    const endInnerArc = this.arc(
      endInnerCornerRadius,
      endInnerCornerRadiusAngleSweep,
      endAngle + Math.PI * 0.5,
      endAngle + Math.PI - endInnerCornerRadiusAngleSweep,
      outerArc,
      innerArc,
      false,
      true
    );
    const startInnerArc = this.arc(
      startInnerCornerRadius,
      startInnerCornerRadiusAngleSweep,
      startAngle + Math.PI + startInnerCornerRadiusAngleSweep,
      startAngle + Math.PI * 1.5,
      outerArc,
      innerArc,
      true,
      true
    );
    if (innerAngleExceeded && hasInnerSweep) {
    } else if (innerAngleExceeded) {
      const x = sweepAngle < Math.PI * 0.5 ? radialEdgeInset * (1 + Math.cos(sweepAngle)) / Math.sin(sweepAngle) : Number.NaN;
      let r;
      if (x > 0 && x < outerRadius) {
        r = Math.max(Math.hypot(radialEdgeInset, x), innerRadius);
      } else {
        r = radialEdgeInset;
      }
      r = Math.max(r, innerRadius);
      const midAngle = startAngle + sweepAngle * 0.5;
      path.moveTo(centerX + r * Math.cos(midAngle), centerY + r * Math.sin(midAngle));
    } else if (startInnerArc?.isValid() === true || innerArc?.isValid() === true) {
    } else {
      const midAngle = startAngle + sweepAngle / 2;
      const cx = innerRadius * Math.cos(midAngle);
      const cy = innerRadius * Math.sin(midAngle);
      path.moveTo(centerX + cx, centerY + cy);
    }
    if (startOuterArc?.isValid() === true) {
      const { cx, cy, r, a0, a1 } = startOuterArc;
      path.arc(centerX + cx, centerY + cy, r, a0, a1);
    }
    if (outerArc.isValid()) {
      const { r, a0, a1 } = outerArc;
      path.arc(centerX, centerY, r, a0, a1);
    }
    if (endOuterArc?.isValid() === true) {
      const { cx, cy, r, a0, a1 } = endOuterArc;
      path.arc(centerX + cx, centerY + cy, r, a0, a1);
    }
    if (!innerAngleExceeded) {
      if (endInnerArc?.isValid() === true) {
        const { cx, cy, r, a0, a1 } = endInnerArc;
        path.arc(centerX + cx, centerY + cy, r, a0, a1);
      }
      if (innerArc?.isValid() === true) {
        const { r, a0, a1 } = innerArc;
        path.arc(centerX, centerY, r, a1, a0, true);
      }
      if (startInnerArc?.isValid() === true) {
        const { cx, cy, r, a0, a1 } = startInnerArc;
        path.arc(centerX + cx, centerY + cy, r, a0, a1);
      }
    }
    path.closePath();
  }
  isPointInPath(x, y) {
    const { startAngle, endAngle, innerRadius, outerRadius } = this.clipSector ?? this;
    return isPointInSector(x - this.centerX, y - this.centerY, {
      startAngle,
      endAngle,
      innerRadius: Math.min(innerRadius, outerRadius),
      outerRadius: Math.max(innerRadius, outerRadius)
    });
  }
}; _c$20.className = "_c$20"; __decorateClass([
  SceneChangeDetection5()
], _c$20.prototype, "centerX", 2); __decorateClass([
  SceneChangeDetection5()
], _c$20.prototype, "centerY", 2); __decorateClass([
  SceneChangeDetection5()
], _c$20.prototype, "innerRadius", 2); __decorateClass([
  SceneChangeDetection5()
], _c$20.prototype, "outerRadius", 2); __decorateClass([
  SceneChangeDetection5()
], _c$20.prototype, "startAngle", 2); __decorateClass([
  SceneChangeDetection5()
], _c$20.prototype, "endAngle", 2); __decorateClass([
  SceneObjectChangeDetection2({ equals: (lhs, rhs) => lhs.equals(rhs) })
], _c$20.prototype, "clipSector", 2); __decorateClass([
  SceneChangeDetection5()
], _c$20.prototype, "concentricEdgeInset", 2); __decorateClass([
  SceneChangeDetection5()
], _c$20.prototype, "radialEdgeInset", 2); __decorateClass([
  SceneChangeDetection5()
], _c$20.prototype, "startOuterCornerRadius", 2); __decorateClass([
  SceneChangeDetection5()
], _c$20.prototype, "endOuterCornerRadius", 2); __decorateClass([
  SceneChangeDetection5()
], _c$20.prototype, "startInnerCornerRadius", 2); __decorateClass([
  SceneChangeDetection5()
], _c$20.prototype, "endInnerCornerRadius", 2); return _c$20; })()

// packages/ag-charts-community/src/integrated-charts-scene.ts
import { toRadians as toRadians3 } from "ag-charts-core";
export {
  Arc,
  BBox,
  Caption,
  CategoryScale,
  Group,
  Line,
  LinearScale,
  Marker,
  Path,
  RadialColumnShape,
  Rect,
  Scene,
  Sector,
  Shape,
  TranslatableGroup,
  getRadialColumnWidth,
  toRadians3 as toRadians
};