UNPKG

ag-charts-community

Version:

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

1,648 lines (1,622 loc) 273 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); 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/integrated-charts-scene.ts var integrated_charts_scene_exports = {}; __export(integrated_charts_scene_exports, { Arc: () => Arc, BBox: () => BBox, Caption: () => Caption, CategoryScale: () => CategoryScale, Group: () => Group, Line: () => Line, LinearScale: () => LinearScale, Marker: () => Marker, Path: () => Path, RadialColumnShape: () => RadialColumnShape, Rect: () => Rect, Scene: () => Scene, Sector: () => Sector, Shape: () => Shape, TranslatableGroup: () => TranslatableGroup, getRadialColumnWidth: () => getRadialColumnWidth, toRadians: () => toRadians }); module.exports = __toCommonJS(integrated_charts_scene_exports); // packages/ag-charts-community/src/chart/caption.ts var import_ag_charts_core24 = require("ag-charts-core"); // packages/ag-charts-community/src/scene/node.ts var import_ag_charts_core4 = require("ag-charts-core"); // packages/ag-charts-community/src/util/object.ts var import_ag_charts_core = require("ag-charts-core"); // packages/ag-charts-community/src/util/decorator.ts var BREAK_TRANSFORM_CHAIN = Symbol("BREAK"); var CONFIG_KEY = "__decorator_config"; var ACCESSORS_KEY = "__decorator_accessors"; function addFakeTransformToInstanceProperty(target, propertyKeyOrSymbol) { initialiseConfig(target, propertyKeyOrSymbol).optional = true; } function initialiseConfig(target, propertyKeyOrSymbol) { if (Object.getOwnPropertyDescriptor(target, CONFIG_KEY) == null) { Object.defineProperty(target, CONFIG_KEY, { value: {} }); } if (Object.getOwnPropertyDescriptor(target, ACCESSORS_KEY) == null) { const parentAccessors = Object.getPrototypeOf(target)?.[ACCESSORS_KEY]; const accessors = parentAccessors?.slice() ?? []; Object.defineProperty(target, ACCESSORS_KEY, { value: accessors }); } const config = target[CONFIG_KEY]; const propertyKey = propertyKeyOrSymbol.toString(); if (config[propertyKey] != null) { return config[propertyKey]; } config[propertyKey] = { setters: [], getters: [], observers: [] }; const descriptor = Object.getOwnPropertyDescriptor(target, propertyKeyOrSymbol); let prevGet = descriptor?.get; let prevSet = descriptor?.set; if (prevGet == null || prevSet == null) { const accessors = target[ACCESSORS_KEY]; let index = accessors.indexOf(propertyKeyOrSymbol); if (index === -1) { index = accessors.push(propertyKeyOrSymbol) - 1; } prevGet ?? (prevGet = function() { let accessorValues = this.__accessors; if (accessorValues == null) { accessorValues = accessors.slice().fill(void 0); Object.defineProperty(this, "__accessors", { value: accessorValues }); } return accessorValues[index]; }); prevSet ?? (prevSet = function(value) { let accessorValues = this.__accessors; if (accessorValues == null) { accessorValues = accessors.slice().fill(void 0); Object.defineProperty(this, "__accessors", { value: accessorValues }); } accessorValues[index] = value; }); } const getter = function() { let value = prevGet.call(this); for (const transformFn of config[propertyKey].getters) { value = transformFn(this, propertyKeyOrSymbol, value); if (value === BREAK_TRANSFORM_CHAIN) { return; } } return value; }; const setter = function(value) { const { setters, observers } = config[propertyKey]; let oldValue; if (setters.some((f) => f.length > 2)) { oldValue = prevGet.call(this); } for (const transformFn of setters) { value = transformFn(this, propertyKeyOrSymbol, value, oldValue); if (value === BREAK_TRANSFORM_CHAIN) { return; } } prevSet.call(this, value); for (const observerFn of observers) { observerFn(this, value, oldValue); } }; Object.defineProperty(target, propertyKeyOrSymbol, { set: setter, get: getter, enumerable: true, configurable: false }); return config[propertyKey]; } function addTransformToInstanceProperty(setTransform, getTransform, configMetadata) { return (target, propertyKeyOrSymbol) => { const config = initialiseConfig(target, propertyKeyOrSymbol); config.setters.push(setTransform); if (getTransform) { config.getters.unshift(getTransform); } if (configMetadata) { Object.assign(config, configMetadata); } }; } function addObserverToInstanceProperty(setObserver) { return (target, propertyKeyOrSymbol) => { initialiseConfig(target, propertyKeyOrSymbol).observers.push(setObserver); }; } function isDecoratedObject(target) { return typeof target !== "undefined" && CONFIG_KEY in target; } function listDecoratedProperties(target) { const targets = /* @__PURE__ */ new Set(); while (isDecoratedObject(target)) { targets.add(target?.[CONFIG_KEY]); target = Object.getPrototypeOf(target); } return Array.from(targets).flatMap((configMap) => Object.keys(configMap)); } // packages/ag-charts-community/src/util/object.ts function objectsEqual(a, b) { if (Array.isArray(a)) { if (!Array.isArray(b)) return false; if (a.length !== b.length) return false; return a.every((av, i) => objectsEqual(av, b[i])); } else if ((0, import_ag_charts_core.isPlainObject)(a)) { if (!(0, import_ag_charts_core.isPlainObject)(b)) return false; return objectsEqualWith(a, b, objectsEqual); } return a === b; } function objectsEqualWith(a, b, cmp2) { if (Object.is(a, b)) return true; for (const key of Object.keys(b)) { if (!(key in a)) return false; } for (const key of Object.keys(a)) { if (!(key in b)) return false; if (!cmp2(a[key], b[key])) return false; } return true; } function merge(...sources) { const target = {}; for (const source of sources) { if (!(0, import_ag_charts_core.isObject)(source)) continue; const keys = isDecoratedObject(source) ? listDecoratedProperties(source) : Object.keys(source); for (const key of keys) { if ((0, import_ag_charts_core.isPlainObject)(target[key]) && (0, import_ag_charts_core.isPlainObject)(source[key])) { target[key] = merge(target[key], source[key]); } else if (!(key in target)) { target[key] ?? (target[key] = source[key]); } } } return target; } // packages/ag-charts-community/src/scene/bbox.ts var import_ag_charts_core2 = require("ag-charts-core"); // packages/ag-charts-community/src/util/bboxinterface.ts var BBoxValues = { containsPoint, equals, isEmpty, normalize }; function containsPoint(bbox, x, y) { return x >= bbox.x && x <= bbox.x + bbox.width && y >= bbox.y && y <= bbox.y + bbox.height; } function equals(lhs, rhs) { return lhs.x === rhs.x && lhs.y === rhs.y && lhs.width === rhs.width && lhs.height === rhs.height; } function isEmpty(bbox) { return bbox == null || bbox.height === 0 || bbox.width === 0 || isNaN(bbox.height) || isNaN(bbox.width); } function normalize(bbox) { let { x, y, width, height } = bbox; if ((width == null || width > 0) && (height == null || height > 0)) return bbox; if (x != null && width != null && width < 0) { width = -width; x = x - width; } if (y != null && height != null && height < 0) { height = -height; y = y - height; } return { x, y, width, height }; } // packages/ag-charts-community/src/util/interpolating.ts var interpolate = Symbol("interpolate"); // packages/ag-charts-community/src/util/nearest.ts function nearestSquared(x, y, objects, maxDistanceSquared = Infinity) { const result = { nearest: void 0, distanceSquared: maxDistanceSquared }; for (const obj of objects) { const thisDistance = obj.distanceSquared(x, y); if (thisDistance === 0) { return { nearest: obj, distanceSquared: 0 }; } else if (thisDistance < result.distanceSquared) { result.nearest = obj; result.distanceSquared = thisDistance; } } return result; } // packages/ag-charts-community/src/scene/bbox.ts var _BBox = class _BBox { constructor(x, y, width, height) { this.x = x; this.y = y; this.width = width; this.height = height; } static fromDOMRect({ 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 (box.x + box.width > right) { right = box.x + box.width; } if (box.y + box.height > bottom) { bottom = 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: this.x + this.width, bottom: this.y + this.height, toJSON() { return {}; } }; } clone() { const { x, y, width, height } = this; return new _BBox(x, y, width, height); } equals(other) { return BBoxValues.equals(this, other); } containsPoint(x, y) { return BBoxValues.containsPoint(this, x, y); } intersection(other) { if (!this.collidesBBox(other)) return; const newX1 = (0, import_ag_charts_core2.clamp)(other.x, this.x, other.x + other.width); const newY1 = (0, import_ag_charts_core2.clamp)(other.y, this.y, other.y + other.height); const newX2 = (0, import_ag_charts_core2.clamp)(other.x, this.x + this.width, other.x + other.width); const newY2 = (0, import_ag_charts_core2.clamp)(other.y, this.y + this.height, other.y + other.height); return new _BBox(newX1, newY1, newX2 - newX1, newY2 - newY1); } collidesBBox(other) { return this.x < other.x + other.width && this.x + this.width > other.x && this.y < other.y + other.height && 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 - (0, import_ag_charts_core2.clamp)(this.x, x, this.x + this.width); const dy = y - (0, import_ag_charts_core2.clamp)(this.y, y, 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 ); } }; _BBox.zero = Object.freeze(new _BBox(0, 0, 0, 0)); _BBox.NaN = Object.freeze(new _BBox(NaN, NaN, NaN, NaN)); var BBox = _BBox; // packages/ag-charts-community/src/scene/changeDetectable.ts var import_ag_charts_core3 = require("ag-charts-core"); var TRIPLE_EQ = (lhs, rhs) => lhs === rhs; function SceneChangeDetection(opts) { return function(target, key) { const privateKey = `__${key}`; if (target[key]) { return; } prepareGetSet(target, key, privateKey, opts); }; } function SceneObjectChangeDetection(opts) { return SceneChangeDetection(opts); } function SceneArrayChangeDetection(opts) { const baseOpts = opts ?? {}; baseOpts.equals = import_ag_charts_core3.arraysEqual; return SceneChangeDetection(opts); } function prepareGetSet(target, key, privateKey, opts) { const { changeCb, convertor, checkDirtyOnAssignment = false } = opts ?? {}; const requiredOpts = { changeCb, checkDirtyOnAssignment, convertor }; const setter = buildCheckDirtyChain( privateKey, buildChangeCallbackChain( buildConvertorChain(buildSetter(privateKey, requiredOpts), requiredOpts), requiredOpts ), requiredOpts ); const getter = function() { return this[privateKey]; }; Object.defineProperty(target, key, { set: setter, get: getter, enumerable: true, configurable: true }); } function buildConvertorChain(setterFn, opts) { const { convertor } = opts; if (convertor) { return function(value) { setterFn.call(this, convertor(value)); }; } return setterFn; } var NO_CHANGE = Symbol("no-change"); function buildChangeCallbackChain(setterFn, opts) { const { changeCb } = opts; if (changeCb) { return function(value) { const change = setterFn.call(this, value); if (change !== NO_CHANGE) { changeCb.call(this, this); } return change; }; } return setterFn; } function buildCheckDirtyChain(privateKey, setterFn, opts) { const { checkDirtyOnAssignment } = opts; if (checkDirtyOnAssignment) { return function(value) { const change = setterFn.call(this, value); if (value?._dirty === true) { this.markDirty(privateKey); } return change; }; } return setterFn; } function buildSetter(privateKey, opts) { const { equals: equals2 = TRIPLE_EQ } = opts; return function(value) { const oldValue = this[privateKey]; if (!equals2(value, oldValue)) { this[privateKey] = value; this.onChangeDetection(privateKey); return value; } return NO_CHANGE; }; } // packages/ag-charts-community/src/scene/node.ts var _Node = 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 = (0, import_ag_charts_core4.createId)(this); this.pointerEvents = 0 /* All */; this.scene = void 0; this._dirty = true; this.dirtyZIndex = false; /** * 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.name = options?.name; this.tag = options?.tag ?? NaN; this.zIndex = options?.zIndex ?? 0; 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 = (0, import_ag_charts_core4.createSvgElement)("svg"); root.setAttribute("width", String(width)); root.setAttribute("height", String(height)); root.setAttribute("viewBox", `0 0 ${width} ${height}`); if (svg.defs?.length) { const defs = (0, import_ag_charts_core4.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; } get layerManager() { return this.scene?.layersManager; } get imageLoader() { return this.scene?.imageLoader; } get dirty() { return this._dirty; } closestDatum() { for (const { datum } of this.traverseUp(true)) { if (datum != null) { return datum; } } } /** 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; for (const child of this.children()) { const childCounts = child.preRender(renderCtx); this.childNodeCounts.groups += childCounts.groups; this.childNodeCounts.nonGroups += childCounts.nonGroups; this.childNodeCounts.complexity += childCounts.complexity; } return this.childNodeCounts; } render(renderCtx) { const { stats } = renderCtx; this._dirty = false; 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; this._debug = scene?.layersManager?.debug; for (const child of this.children()) { child.setScene(scene); } } sortChildren(compareFn) { this.dirtyZIndex = false; if (!this.childNodes) return; const sortedChildren = [...this.childNodes].sort(compareFn); this.childNodes.clear(); for (const child of sortedChildren) { this.childNodes.add(child); } } *traverseUp(includeSelf) { let node = this; if (includeSelf) { yield node; } while (node = node.parentNode) { yield node; } } *children() { if (!this.childNodes) return; for (const child of this.childNodes) { yield child; } } *descendants() { for (const child of this.children()) { yield child; yield* child.descendants(); } } /** * Checks if the node is a leaf (has no children). */ isLeaf() { return !this.childNodes?.size; } /** * Checks if the node is the root (has no parent). */ isRoot() { return !this.parentNode; } /** * 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) { this.childNodes ?? (this.childNodes = /* @__PURE__ */ new Set()); for (const node of (0, import_ag_charts_core4.toIterable)(nodes)) { node.parentNode?.removeChild(node); this.childNodes.add(node); node.parentNode = this; node.setScene(this.scene); } this.invalidateCachedBBox(); this.dirtyZIndex = true; 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}` ); } delete node.parentNode; node.setScene(); this.invalidateCachedBBox(); this.dirtyZIndex = true; this.markDirty(); } remove() { this.parentNode?.removeChild(this); } clear() { for (const child of this.children()) { delete child.parentNode; child.setScene(); } this.childNodes?.clear(); this.invalidateCachedBBox(); } destroy() { this.parentNode?.removeChild(this); } setProperties(styles, pickKeys) { if (pickKeys) { for (const key of pickKeys) { this[key] = styles[key]; } } else { Object.assign(this, styles); } return this; } containsPoint(_x, _y) { return false; } /** * 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 hit = children[i].pickNode(x, y); if (hit) { 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; } invalidateCachedBBox() { if (this.cachedBBox != null) { this.cachedBBox = void 0; this.parentNode?.invalidateCachedBBox(); } } getBBox() { if (this.cachedBBox == null) { this.cachedBBox = Object.freeze(this.computeBBox()); } return this.cachedBBox; } computeBBox() { return; } onChangeDetection(property) { this.markDirty(property); } markDirty(property) { const { _dirty } = this; if (property != null && this._debugDirtyProperties) { this.markDebugProperties(property); } const noParentCachedBBox = this.cachedBBox == null; if (noParentCachedBBox && _dirty) return; this.invalidateCachedBBox(); this._dirty = true; if (this.parentNode) { this.parentNode.markDirty(); } } markClean() { if (!this._dirty) return; this._dirty = false; this.debugDirtyProperties(); for (const child of this.children()) { child.markClean(); } } markDebugProperties(property) { const sources = this._debugDirtyProperties?.get(property) ?? []; const caller = new Error().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__")) { this._debugDirtyProperties.forEach((sources, property) => { if (sources.length > 1) { console.groupCollapsed( `Property changed multiple times before render: ${this.constructor.name}.${property} (${sources.length}x)` ); sources.forEach((source) => console.log(source)); console.groupEnd(); } }); } this._debugDirtyProperties.clear(); } onZIndexChange() { const { parentNode } = this; if (parentNode) { parentNode.dirtyZIndex = true; } } toSVG() { return; } }; _Node._nextSerialNumber = 0; // eslint-disable-next-line sonarjs/public-static-readonly _Node._debugEnabled = false; __decorateClass([ SceneChangeDetection() ], _Node.prototype, "visible", 2); __decorateClass([ SceneObjectChangeDetection({ equals: objectsEqual, changeCb: (target) => target.onZIndexChange() }) ], _Node.prototype, "zIndex", 2); var Node = _Node; // packages/ag-charts-community/src/scene/shape/text.ts var import_ag_charts_core22 = require("ag-charts-core"); // packages/ag-charts-community/src/util/canvas.util.ts function createCanvasContext(width = 0, height = 0) { return new OffscreenCanvas(width, height).getContext("2d"); } // packages/ag-charts-community/src/util/lruCache.ts var LRUCache = class { constructor(maxCacheSize = 5) { this.maxCacheSize = maxCacheSize; this.store = /* @__PURE__ */ new Map(); } get(key) { if (!this.store.has(key)) return void 0; const hit = this.store.get(key); this.store.delete(key); this.store.set(key, hit); return hit; } has(key) { return this.store.has(key); } set(key, value) { this.store.set(key, value); if (this.store.size > this.maxCacheSize) { const iterator = this.store.keys(); let evictCount = this.store.size - this.maxCacheSize; while (evictCount > 0) { const evictKeyIterator = iterator.next(); if (!evictKeyIterator.done) { this.store.delete(evictKeyIterator.value); } evictCount--; } } return value; } clear() { this.store.clear(); } }; // packages/ag-charts-community/src/util/textMeasurer.ts var CachedTextMeasurerPool = class { // Measures the dimensions of the provided text, handling multiline if needed. static measureText(text, options) { const textMeasurer = this.getMeasurer(options); return textMeasurer.measureText(text); } static measureLines(text, options) { const textMeasurer = this.getMeasurer(options); return textMeasurer.measureLines(text); } // Gets a TextMeasurer instance, configuring text alignment and baseline if provided. static getMeasurer(options) { const font = typeof options.font === "string" ? options.font : TextUtils.toFontString(options.font); const key = `${font}-${options.textAlign ?? "start"}-${options.textBaseline ?? "alphabetic"}`; return this.instanceMap.get(key) ?? this.createFontMeasurer(font, options, key); } static clear() { this.instanceMap.clear(); } // Creates or retrieves a TextMeasurer instance for a specific font. static createFontMeasurer(font, options, key) { const ctx = createCanvasContext(); ctx.font = font; ctx.textAlign = options.textAlign ?? "start"; ctx.textBaseline = options.textBaseline ?? "alphabetic"; const measurer = new CachedTextMeasurer(ctx, options); this.instanceMap.set(key, measurer); return measurer; } }; CachedTextMeasurerPool.instanceMap = new LRUCache(10); var CachedTextMeasurer = class { constructor(ctx, options) { this.ctx = ctx; // cached text measurements this.measureMap = new LRUCache(100); if (options.textAlign) { ctx.textAlign = options.textAlign; } if (options.textBaseline) { ctx.textBaseline = options.textBaseline; } ctx.font = typeof options.font === "string" ? options.font : TextUtils.toFontString(options.font); this.textMeasurer = new SimpleTextMeasurer( (t) => this.cachedCtxMeasureText(t), options.textBaseline ?? "alphabetic" ); } textWidth(text, estimate) { return this.textMeasurer.textWidth(text, estimate); } measureText(text) { return this.textMeasurer.measureText(text); } measureLines(text) { return this.textMeasurer.measureLines(text); } cachedCtxMeasureText(text) { if (!this.measureMap.has(text)) { const rawResult = this.ctx.measureText(text); this.measureMap.set(text, { actualBoundingBoxAscent: rawResult.actualBoundingBoxAscent, emHeightAscent: rawResult.emHeightAscent, emHeightDescent: rawResult.emHeightDescent, actualBoundingBoxDescent: rawResult.actualBoundingBoxDescent, actualBoundingBoxLeft: rawResult.actualBoundingBoxLeft, actualBoundingBoxRight: rawResult.actualBoundingBoxRight, alphabeticBaseline: rawResult.alphabeticBaseline, fontBoundingBoxAscent: rawResult.fontBoundingBoxAscent, fontBoundingBoxDescent: rawResult.fontBoundingBoxDescent, hangingBaseline: rawResult.hangingBaseline, ideographicBaseline: rawResult.ideographicBaseline, width: rawResult.width }); } return this.measureMap.get(text); } }; var TextUtils = class { static toFontString({ fontSize = 10, fontStyle, fontWeight, fontFamily, lineHeight }) { let fontString = ""; if (fontStyle) { fontString += `${fontStyle} `; } if (fontWeight) { fontString += `${fontWeight} `; } fontString += `${fontSize}px`; if (lineHeight) { fontString += `/${lineHeight}px`; } fontString += ` ${fontFamily}`; return fontString.trim(); } static getLineHeight(fontSize) { return Math.ceil(fontSize * this.defaultLineHeight); } // Determines vertical offset modifier based on text baseline. static getVerticalModifier(textBaseline) { switch (textBaseline) { case "hanging": case "top": return 0; case "middle": return 0.5; case "alphabetic": case "bottom": case "ideographic": default: return 1; } } }; TextUtils.EllipsisChar = "\u2026"; // Representation for text clipping. TextUtils.defaultLineHeight = 1.15; // Normally between 1.1 and 1.2 TextUtils.lineSplitter = /\r?\n/g; var SimpleTextMeasurer = class { constructor(measureTextFn, textBaseline = "alphabetic") { this.measureTextFn = measureTextFn; this.textBaseline = textBaseline; // local chars width cache per TextMeasurer this.charMap = /* @__PURE__ */ new Map(); } // Measures metrics for a single line of text. getMetrics(text) { const m = this.measureTextFn(text); m.fontBoundingBoxAscent ?? (m.fontBoundingBoxAscent = m.emHeightAscent); m.fontBoundingBoxDescent ?? (m.fontBoundingBoxDescent = m.emHeightDescent); return { width: m.width, height: m.actualBoundingBoxAscent + m.actualBoundingBoxDescent, lineHeight: m.fontBoundingBoxAscent + m.fontBoundingBoxDescent, offsetTop: m.actualBoundingBoxAscent, offsetLeft: m.actualBoundingBoxLeft }; } // Calculates aggregated metrics for multiline text. getMultilineMetrics(lines) { let width = 0; let height = 0; let offsetTop = 0; let offsetLeft = 0; let baselineDistance = 0; const verticalModifier = TextUtils.getVerticalModifier(this.textBaseline); const lineMetrics = []; let index = 0; const length = lines.length; for (const line of lines) { const m = this.measureTextFn(line); m.fontBoundingBoxAscent ?? (m.fontBoundingBoxAscent = m.emHeightAscent); m.fontBoundingBoxDescent ?? (m.fontBoundingBoxDescent = m.emHeightDescent); if (width < m.width) { width = m.width; } if (offsetLeft < m.actualBoundingBoxLeft) { offsetLeft = m.actualBoundingBoxLeft; } if (index === 0) { height += m.actualBoundingBoxAscent; offsetTop += m.actualBoundingBoxAscent; } else { baselineDistance += m.fontBoundingBoxAscent; } if (index === length - 1) { height += m.actualBoundingBoxDescent; } else { baselineDistance += m.fontBoundingBoxDescent; } lineMetrics.push({ text: line, width: m.width, height: m.actualBoundingBoxAscent + m.actualBoundingBoxDescent, lineHeight: m.fontBoundingBoxAscent + m.fontBoundingBoxDescent, offsetTop: m.actualBoundingBoxAscent, offsetLeft: m.actualBoundingBoxLeft }); index++; } height += baselineDistance; offsetTop += baselineDistance * verticalModifier; return { width, height, offsetTop, offsetLeft, lineMetrics }; } textWidth(text, estimate) { if (estimate) { let estimatedWidth = 0; for (let i = 0; i < text.length; i++) { estimatedWidth += this.textWidth(text.charAt(i)); } return estimatedWidth; } if (text.length > 1) { return this.measureTextFn(text).width; } return this.charMap.get(text) ?? this.charWidth(text); } measureText(text) { return this.getMetrics(text); } // Measures the dimensions of the provided text, handling multiline if needed. measureLines(text) { const lines = typeof text === "string" ? text.split(TextUtils.lineSplitter) : text; return this.getMultilineMetrics(lines); } charWidth(char) { const { width } = this.measureTextFn(char); this.charMap.set(char, width); return width; } }; // packages/ag-charts-community/src/scene/transformable.ts var import_ag_charts_core6 = require("ag-charts-core"); // packages/ag-charts-community/src/scene/matrix.ts var import_ag_charts_core5 = require("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 (0, import_ag_charts_core5.isNumberEqual)(e[0], 1) && (0, import_ag_charts_core5.isNumberEqual)(e[1], 0) && (0, import_ag_charts_core5.isNumberEqual)(e[2], 0) && (0, import_ag_charts_core5.isNumberEqual)(e[3], 1) && (0, import_ag_charts_core5.isNumberEqual)(e[4], 0) && (0, import_ag_charts_core5.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 = new Array(6); 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 = 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; } markDirtyTransform() { this._dirtyTransform = true; super.markDirty(); } onChangeDetection(property) { super.onChangeDetection(property); this.markDirtyTransform(); } 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); } render(renderCtx) { this.computeTransformMatrix(); const { ctx } = renderCtx; const matrix = this[TRANSFORM_MATRIX]; let performRestore = false; if (!matrix.identity) { ctx.save(); performRestore = true; matrix.toContext(ctx); } super.render(renderCtx); 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 = (0, import_ag_charts_core6.createSvgElement)("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; } 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]); } } _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/shape/shape.ts var import_ag_charts_core21 = require("ag-charts-core"); // packages/ag-charts-community/src/scene/gradient/conicGradient.ts var import_ag_charts_core10 = require("ag-charts-core"); // packages/ag-charts-community/src/util/angle.ts var twoPi = Math.PI * 2; var halfPi = Math.PI / 2; function normalizeAngle360(radians) { radians %= twoPi; radians += twoPi; radians %= twoPi; return radians; } function normalizeAngle180(radians) { radians %= twoPi; if (radians < -Math.PI) { radians += twoPi; } else if (radians >= Math.PI) { radians -= twoPi; } return radians; } function isBetweenAngles(targetAngle, startAngle, endAngle) { const t = normalizeAngle360(targetAngle); const a0 = normalizeAngle360(startAngle); const a1 = normalizeAngle360(endAngle); if (a0 < a1) { return a0 <= t && t <= a1; } else if (a0 > a1) { return a0 <= t || t <= a1; } else { return true; } } function toRadians(degrees) { return degrees / 180 * Math.PI; } function angleBetween(angle0, angle1) { angle0 = normalizeAngle360(angle0); angle1 = normalizeAngle360(angle1); return angle1 - angle0 + (angle0 > angle1 ? twoPi : 0); } function normalizeAngle360FromDegrees(degrees) { return degrees ? normalizeAngle360(toRadians(degrees)) : 0; } // packages/ag-charts-community/src/scene/gradient/gradient.ts var import_ag_charts_core9 = require("ag-charts-core"); // packages/ag-charts-community/src/scale/colorScale.ts var import_ag_charts_core8 = require("ag-charts-core"); // packages/ag-charts-community/src/util/color.ts var import_ag_charts_core7 = require("ag-charts-core"); var lerp = (x, y, t) => x * (1 - t) + y * t; var srgbToLinear = (value) => { const sign = value < 0 ? -1 : 1; co