UNPKG

ag-charts-core

Version:

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

1,353 lines (1,331 loc) 41.2 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); // packages/ag-charts-core/src/main.ts var main_exports = {}; __export(main_exports, { EventEmitter: () => EventEmitter, Logger: () => logger_exports, ModuleRegistry: () => moduleRegistry_exports, ModuleType: () => ModuleType, ValidationError: () => ValidationError, and: () => and, array: () => array, arrayLength: () => arrayLength, arrayOf: () => arrayOf, arrayOfDefs: () => arrayOfDefs, arraysEqual: () => arraysEqual, attachDescription: () => attachDescription, boolean: () => boolean, callback: () => callback, circularSliceArray: () => circularSliceArray, clamp: () => clamp, color: () => color, colorUnion: () => colorUnion, constant: () => constant, countFractionDigits: () => countFractionDigits, countLines: () => countLines, createElement: () => createElement, createNumberFormatter: () => createNumberFormatter, createSvgElement: () => createSvgElement, date: () => date, debounce: () => debounce, defined: () => defined, diffArrays: () => diffArrays, downloadUrl: () => downloadUrl, entries: () => entries, fillGradientDefaults: () => fillGradientDefaults, fillOptionsDef: () => fillOptionsDef, fillPatternDefaults: () => fillPatternDefaults, findMaxIndex: () => findMaxIndex, findMaxValue: () => findMaxValue, findMinIndex: () => findMinIndex, findMinValue: () => findMinValue, first: () => first, fontOptionsDef: () => fontOptionsDef, getDocument: () => getDocument, getWindow: () => getWindow, gradientColorStops: () => gradientColorStops, gradientStrict: () => gradientStrict, greaterThan: () => greaterThan, groupBy: () => groupBy, inRange: () => inRange, instanceOf: () => instanceOf, isArray: () => isArray, isBoolean: () => isBoolean, isColor: () => isColor, isDate: () => isDate, isDefined: () => isDefined, isEnumKey: () => isEnumKey, isEnumValue: () => isEnumValue, isFiniteNumber: () => isFiniteNumber, isFunction: () => isFunction, isHtmlElement: () => isHtmlElement, isInteger: () => isInteger, isNegative: () => isNegative, isNumber: () => isNumber, isNumberEqual: () => isNumberEqual, isObject: () => isObject, isObjectLike: () => isObjectLike, isPlainObject: () => isPlainObject, isRegExp: () => isRegExp, isString: () => isString, isSymbol: () => isSymbol, isValidDate: () => isValidDate, isValidNumberFormat: () => isValidNumberFormat, iterate: () => iterate, joinFormatted: () => joinFormatted, lessThan: () => lessThan, levenshteinDistance: () => levenshteinDistance, lineDashOptionsDef: () => lineDashOptionsDef, modulus: () => modulus, number: () => number, numberMin: () => numberMin, numberRange: () => numberRange, object: () => object, optionsDefs: () => optionsDefs, or: () => or, parseColor: () => parseColor, parseNumberFormat: () => parseNumberFormat, partialDefs: () => partialDefs, positiveNumber: () => positiveNumber, positiveNumberNonZero: () => positiveNumberNonZero, ratio: () => ratio, required: () => required, roundTo: () => roundTo, setDocument: () => setDocument, setWindow: () => setWindow, sortBasedOnArray: () => sortBasedOnArray, string: () => string, stringifyValue: () => stringifyValue, strokeOptionsDef: () => strokeOptionsDef, throttle: () => throttle, toArray: () => toArray, toIterable: () => toIterable, typeUnion: () => typeUnion, union: () => union, unique: () => unique, validate: () => validate }); module.exports = __toCommonJS(main_exports); // packages/ag-charts-core/src/globals/logger.ts var logger_exports = {}; __export(logger_exports, { error: () => error, errorOnce: () => errorOnce, log: () => log, logGroup: () => logGroup, reset: () => reset, table: () => table, warn: () => warn, warnOnce: () => warnOnce }); var doOnceCache = /* @__PURE__ */ new Set(); function log(...logContent) { console.log(...logContent); } function warn(message, ...logContent) { console.warn(`AG Charts - ${message}`, ...logContent); } function error(message, ...logContent) { if (typeof message === "object") { console.error(`AG Charts error`, message, ...logContent); } else { console.error(`AG Charts - ${message}`, ...logContent); } } function table(...logContent) { console.table(...logContent); } function warnOnce(message, ...logContent) { const cacheKey = `Logger.warn: ${message}`; if (doOnceCache.has(cacheKey)) return; warn(message, ...logContent); doOnceCache.add(cacheKey); } function errorOnce(message, ...logContent) { const cacheKey = `Logger.error: ${message}`; if (doOnceCache.has(cacheKey)) return; error(message, ...logContent); doOnceCache.add(cacheKey); } function reset() { doOnceCache.clear(); } function logGroup(name, cb) { console.groupCollapsed(name); try { return cb(); } finally { console.groupEnd(); } } // packages/ag-charts-core/src/globals/moduleRegistry.ts var moduleRegistry_exports = {}; __export(moduleRegistry_exports, { detectChartDefinition: () => detectChartDefinition, getAxisModule: () => getAxisModule, getSeriesModule: () => getSeriesModule, hasModule: () => hasModule, listModulesByType: () => listModulesByType, register: () => register, registerMany: () => registerMany, reset: () => reset2 }); // packages/ag-charts-core/src/interfaces/moduleDefinition.ts var ModuleType = /* @__PURE__ */ ((ModuleType2) => { ModuleType2["Axis"] = "axis"; ModuleType2["Chart"] = "chart"; ModuleType2["Preset"] = "preset"; ModuleType2["Plugin"] = "plugin"; ModuleType2["Series"] = "series"; return ModuleType2; })(ModuleType || {}); // packages/ag-charts-core/src/globals/moduleRegistry.ts var registeredModules = /* @__PURE__ */ new Map(); function register(definition) { const existingDefinition = registeredModules.get(definition.name); if (existingDefinition && (existingDefinition.enterprise || !definition.enterprise)) { throw new Error(`AG Charts - Module '${definition.name}' already registered`); } registeredModules.set(definition.name, definition); } function registerMany(definitions) { for (const definition of definitions) { register(definition); } } function reset2() { registeredModules.clear(); } function hasModule(moduleName) { return registeredModules.has(moduleName); } function* listModulesByType(moduleType) { for (const definition of registeredModules.values()) { if (definition.type === moduleType) { yield definition; } } } function detectChartDefinition(options) { for (const definition of registeredModules.values()) { if (isChartModule(definition) && definition.detect(options)) { return definition; } } throw new Error( `AG Charts - Unknown chart type; Check options are correctly structured and series types are specified` ); } function getSeriesModule(moduleName) { const definition = registeredModules.get(moduleName); if (isSeriesModule(definition)) { return definition; } } function getAxisModule(moduleName) { const definition = registeredModules.get(moduleName); if (isAxisModule(definition)) { return definition; } } function isChartModule(definition) { return definition?.type === "chart" /* Chart */; } function isAxisModule(definition) { return definition?.type === "axis" /* Axis */; } function isSeriesModule(definition) { return definition?.type === "series" /* Series */; } // packages/ag-charts-core/src/classes/eventEmitter.ts var EventEmitter = class { constructor() { this.events = /* @__PURE__ */ new Map(); } /** * Registers an event listener. * @param eventName The event name to listen for. * @param listener The callback to be invoked on the event. * @returns A function to unregister the listener. */ on(eventName, listener) { if (!this.events.has(eventName)) { this.events.set(eventName, /* @__PURE__ */ new Set()); } this.events.get(eventName)?.add(listener); return () => this.off(eventName, listener); } /** * Unregisters an event listener. * @param eventName The event name to stop listening for. * @param listener The callback to be removed. */ off(eventName, listener) { const eventListeners = this.events.get(eventName); if (eventListeners) { eventListeners.delete(listener); if (eventListeners.size === 0) { this.events.delete(eventName); } } } /** * Emits an event to all registered listeners. * @param eventName The name of the event to emit. * @param event The event payload. */ emit(eventName, event) { this.events.get(eventName)?.forEach((callback2) => callback2(event)); } /** * Clears all listeners for a specific event or all events if no event name is provided. * @param eventName (Optional) The name of the event to clear listeners for. If not provided, all listeners for all events are cleared. */ clear(eventName) { if (eventName) { this.events.delete(eventName); } else { this.events.clear(); } } }; // packages/ag-charts-core/src/utils/strings.ts function joinFormatted(values, conjunction = "and", format = String, maxItems = Infinity) { if (values.length === 1) { return format(values[0]); } values = values.map(format); const lastValue = values.pop(); if (values.length >= maxItems) { const remainingCount = values.length - (maxItems - 1); return `${values.slice(0, maxItems - 1).join(", ")}, and ${remainingCount} more ${conjunction} ${lastValue}`; } return `${values.join(", ")} ${conjunction} ${lastValue}`; } function stringifyValue(value, maxLength = Infinity) { if (typeof value === "number") { if (isNaN(value)) { return "NaN"; } else if (value === Infinity) { return "Infinity"; } else if (value === -Infinity) { return "-Infinity"; } } const strValue = JSON.stringify(value) ?? typeof value; if (strValue.length > maxLength) { return `${strValue.slice(0, maxLength)}... (+${strValue.length - maxLength} characters)`; } return strValue; } function countLines(text) { let count = 1; for (let i = 0; i < text.length; i++) { if (text.charCodeAt(i) === 10) { count++; } } return count; } function levenshteinDistance(a, b) { if (a === b) return 0; const [shorter, longer] = a.length < b.length ? [a, b] : [b, a]; const m = shorter.length; const n = longer.length; let prevRow = new Array(m + 1).fill(0).map((_, i) => i); let currRow = new Array(m + 1); for (let i = 1; i <= n; i++) { currRow[0] = i; for (let j = 1; j <= m; j++) { const cost = longer[i - 1] === shorter[j - 1] ? 0 : 1; currRow[j] = Math.min( prevRow[j] + 1, // Deletion currRow[j - 1] + 1, // Insertion prevRow[j - 1] + cost // Substitution ); } [prevRow, currRow] = [currRow, prevRow]; } return prevRow[m]; } // packages/ag-charts-core/src/utils/dom/globalsProxy.ts var verifiedGlobals = {}; if (typeof window !== "undefined") { verifiedGlobals.window = window; } else if (typeof global !== "undefined") { verifiedGlobals.window = global.window; } if (typeof document !== "undefined") { verifiedGlobals.document = document; } else if (typeof global !== "undefined") { verifiedGlobals.document = global.document; } function getDocument(propertyName) { return propertyName ? verifiedGlobals.document?.[propertyName] : verifiedGlobals.document; } function getWindow(propertyName) { return propertyName ? verifiedGlobals.window?.[propertyName] : verifiedGlobals.window; } function setDocument(document2) { verifiedGlobals.document = document2; } function setWindow(window2) { verifiedGlobals.window = window2; } // packages/ag-charts-core/src/utils/dom/domElements.ts function createElement(tagName, className, style) { const element = getDocument().createElement(tagName); if (typeof className === "object") { style = className; className = void 0; } if (className) { for (const name of className.split(" ")) { element.classList.add(name); } } if (style) { Object.assign(element.style, style); } return element; } function createSvgElement(elementName) { return getDocument().createElementNS("http://www.w3.org/2000/svg", elementName); } // packages/ag-charts-core/src/utils/dom/domDownload.ts function downloadUrl(dataUrl, fileName) { const body = getDocument("body"); const element = createElement("a", { display: "none" }); element.href = dataUrl; element.download = fileName; body.appendChild(element); element.click(); setTimeout(() => body.removeChild(element)); } // packages/ag-charts-core/src/utils/dom/domUtils.ts function parseColor(color2) { const OptionConstructor = getWindow("Option"); const { style } = new OptionConstructor(); style.color = color2; return style.color || null; } // packages/ag-charts-core/src/utils/typeGuards.ts function isDefined(val) { return val != null; } function isArray(value) { return Array.isArray(value); } function isBoolean(value) { return typeof value === "boolean"; } function isDate(value) { return value instanceof Date; } function isValidDate(value) { return isDate(value) && !isNaN(Number(value)); } function isRegExp(value) { return value instanceof RegExp; } function isFunction(value) { return typeof value === "function"; } function isObject(value) { return typeof value === "object" && value !== null && !isArray(value); } function isObjectLike(value) { return isArray(value) || isPlainObject(value); } function isPlainObject(value) { return typeof value === "object" && value !== null && value.constructor?.name === "Object"; } function isString(value) { return typeof value === "string"; } function isNumber(value) { return typeof value === "number"; } function isFiniteNumber(value) { return Number.isFinite(value); } function isHtmlElement(value) { return typeof window !== "undefined" && value instanceof HTMLElement; } function isEnumKey(enumObject, enumKey) { return isString(enumKey) && Object.keys(enumObject).includes(enumKey); } function isEnumValue(enumObject, enumValue) { return Object.values(enumObject).includes(enumValue); } function isSymbol(value) { return typeof value === "symbol"; } function isColor(value) { return isString(value) && parseColor(value) != null; } // packages/ag-charts-core/src/utils/validation.ts var descriptionSymbol = Symbol("description"); var requiredSymbol = Symbol("required"); var ValidationError = class { constructor(message, path, required2, unknown) { this.message = message; this.path = path; this.required = required2; this.unknown = unknown; } toString() { return this.message; } }; function validate(options, optionsDefs2, path = "") { if (!isObject(options)) { const message = validateMessage(path, options, "an object", true); return { valid: null, errors: [new ValidationError(message, path, true)] }; } const unusedKeys = []; const optionsKeys = new Set(Object.keys(options)); const errors = []; const valid = {}; function extendPath(key) { if (isArray(optionsDefs2)) { return `${path}[${key}]`; } return path ? `${path}.${key}` : key; } for (const key of Object.keys(optionsDefs2)) { const validatorOrDefs = optionsDefs2[key]; const value = options[key]; const required2 = validatorOrDefs[requiredSymbol]; optionsKeys.delete(key); if (typeof value === "undefined") { unusedKeys.push(key); if (!required2) continue; } const keyPath = extendPath(key); if (isFunction(validatorOrDefs)) { const context = { options, path: keyPath }; if (validatorOrDefs(value, context)) { valid[key] = context.result?.valid ?? value; } else if (!context.result) { const message = validateMessage(keyPath, value, validatorOrDefs, required2); errors.push(new ValidationError(message, path, required2)); } if (context.result) { errors.push(...context.result.errors); } } else { const nestedResult = validate(value, validatorOrDefs, keyPath); if (nestedResult.valid != null) { valid[key] = nestedResult.valid; } errors.push(...nestedResult.errors); } } for (const key of optionsKeys) { const value = options[key]; if (typeof value === "undefined") continue; const message = unknownMessage(key, extendPath(key), unusedKeys); errors.push(new ValidationError(message, path, void 0, true)); } return { valid, errors }; } function validateMessage(path, value, validatorOrDefs, required2) { const description = isString(validatorOrDefs) ? validatorOrDefs : validatorOrDefs[descriptionSymbol]; const expecting = description ? `; expecting ${description}` : ""; const prefix = path ? `Option \`${path}\`` : "Value"; return required2 && value == null ? `${prefix} is required and has not been provided${expecting}, ignoring.` : `${prefix} cannot be set to \`${stringifyValue(value, 50)}\`${expecting}, ignoring.`; } function unknownMessage(key, keyPath, unusedKeys) { const match = findSuggestion(key, unusedKeys); const postfix = match ? `; Did you mean \`${match}\`? Ignoring.` : ", ignoring."; return `Unknown option \`${keyPath}\`${postfix}`; } function findSuggestion(value, suggestions, maxDistance = 2) { let smallestDistance = Infinity; const lowerCaseValue = value.toLowerCase(); return suggestions.reduce((res, item) => { const d = levenshteinDistance(lowerCaseValue, item.toLowerCase()); if (smallestDistance > d && d <= maxDistance) { smallestDistance = d; return item; } return res; }, null); } function attachDescription(validatorOrDefs, description) { return Object.assign( isFunction(validatorOrDefs) ? (value, context) => validatorOrDefs(value, context) : { ...validatorOrDefs }, { [descriptionSymbol]: description } ); } function required(validatorOrDefs) { return Object.assign( isFunction(validatorOrDefs) ? (value, context) => validatorOrDefs(value, context) : optionsDefs(validatorOrDefs), { [requiredSymbol]: true, [descriptionSymbol]: validatorOrDefs[descriptionSymbol] } ); } var optionsDefs = (defs, description = "an object") => attachDescription((value, context) => { context.result = validate(value, defs, context.path); return !context.result.errors.some((error2) => error2.required && error2.path === context.path); }, description); var partialDefs = (defs, description = "an object") => attachDescription((value, context) => { context.result = validate(value, defs, context.path); context.result.errors = context.result.errors.filter((error2) => !error2.unknown); return !context.result.errors.some((error2) => error2.required && error2.path === context.path); }, description); var and = (...validators) => attachDescription( (value, context) => validators.every((validator) => { const result = validator(value, context); if (context.result && !result) { delete context.result; } return result; }), validators.map((v) => v[descriptionSymbol]).filter(Boolean).join(" and ") ); var or = (...validators) => attachDescription( (value, context) => validators.some((validator) => { const result = validator(value, context); if (context.result && !result) { delete context.result; } return result; }), validators.map((v) => v[descriptionSymbol]).filter(Boolean).join(" or ") ); var isComparable = (value) => isFiniteNumber(value) || isValidDate(value); var isValidDateValue = (value) => isDate(value) || (isFiniteNumber(value) || isString(value)) && isValidDate(new Date(value)); var array = attachDescription(isArray, "an array"); var boolean = attachDescription(isBoolean, "a boolean"); var callback = attachDescription(isFunction, "a function"); var color = attachDescription(isColor, "a color string"); var date = attachDescription(isValidDateValue, "a date"); var defined = attachDescription(isDefined, "a defined value"); var number = attachDescription(isFiniteNumber, "a number"); var object = attachDescription(isObject, "an object"); var string = attachDescription(isString, "a string"); var arrayLength = (minLength, maxLength = Infinity) => { let message; if (maxLength === Infinity) { message = `an array of at least ${minLength} items`; } else if (minLength === maxLength) { message = `an array of exactly ${minLength} items`; } else if (minLength === 0) { message = `an array of no more than ${maxLength} items`; } else { message = `an array of at least ${minLength} and no more than ${maxLength} items`; } return attachDescription( (value) => isArray(value) && value.length >= minLength && value.length <= maxLength, message ); }; var numberMin = (min, inclusive = true) => attachDescription( (value) => isFiniteNumber(value) && (value > min || inclusive && value === min), `a number greater than ${inclusive ? "or equal to " : ""}${min}` ); var numberRange = (min, max) => attachDescription( (value) => isFiniteNumber(value) && value >= min && value <= max, `a number between ${min} and ${max} inclusive` ); var positiveNumber = numberMin(0); var positiveNumberNonZero = numberMin(0, false); var ratio = numberRange(0, 1); var lessThan = (otherField) => attachDescription( (value, { options }) => !isComparable(value) || !isComparable(options[otherField]) || value < options[otherField], `the value to be less than \`${otherField}\`` ); var greaterThan = (otherField) => attachDescription( (value, { options }) => !isComparable(value) || !isComparable(options[otherField]) || value > options[otherField], `the value to be greater than \`${otherField}\`` ); function union(...allowed) { if (isObject(allowed[0])) { allowed = Object.values(allowed[0]); } const keywords = joinFormatted(allowed, "or", (value) => `'${value}'`); return attachDescription((value) => allowed.includes(value), `a keyword such as ${keywords}`); } var constant = (allowed) => attachDescription((value) => allowed === value, `the value ${JSON.stringify(allowed)}`); var instanceOf = (instanceType, description) => attachDescription((value) => value instanceof instanceType, description ?? `an instance of ${instanceType.name}`); var arrayOf = (validator, description) => attachDescription( (value, context) => isArray(value) && value.every((v) => { const result = validator(v, context); delete context.result; return result; }), description ?? `${validator[descriptionSymbol]} array` ); var arrayOfDefs = (defs, description = "an object array") => attachDescription((value, context) => { if (!isArray(value)) return false; const valid = []; const errors = []; for (let i = 0; i < value.length; i++) { const indexPath = `${context.path}[${i}]`; const result = validate(value[i], defs, indexPath); errors.push(...result.errors); if (!result.errors.some((error2) => error2.required && error2.path === indexPath)) { valid.push(result.valid); } } context.result = { valid, errors }; return true; }, description); var typeUnion = (defs, description = "an object") => { const typeValidator = partialDefs({ type: required(union(...Object.keys(defs))) }); return attachDescription((value, context) => { if (typeValidator(value, context)) { const type = value.type; const typeDefs = { type: required(constant(type)), ...defs[type] }; const result = optionsDefs(typeDefs)(value, context); if (context.result) { for (const error2 of context.result.errors) { error2.message += ` (type="${type}")`; } } return result; } return false; }, description); }; // packages/ag-charts-core/src/options/commonOptionsDefs.ts var colorStop = optionsDefs({ color, stop: ratio }, ""); var colorStopsOrderValidator = attachDescription((value) => { let lastStop = -Infinity; for (const item of value) { if (item?.stop != null) { if (item.stop < lastStop) { return false; } lastStop = item.stop; } } return true; }, "color stops to be defined in ascending order"); var gradientColorStops = and(arrayLength(2), and(arrayOf(colorStop), colorStopsOrderValidator)); var gradientBounds = union("axis", "item", "series"); var gradientStrict = typeUnion( { gradient: { // @ts-expect-error undocumented options gradient: union("linear", "radial", "conic"), bounds: gradientBounds, colorStops: required(gradientColorStops), rotation: number, reverse: boolean } }, "a gradient object with color stops" ); var strokeOptionsDef = { stroke: color, strokeWidth: positiveNumber, strokeOpacity: ratio }; var fillGradientDefaults = optionsDefs({ type: required(constant("gradient")), gradient: required(union("linear", "radial", "conic")), bounds: required(gradientBounds), colorStops: required(or(gradientColorStops, and(arrayLength(2), arrayOf(color)))), rotation: required(number), reverse: required(boolean) }); var fillPatternDefaults = optionsDefs({ type: required(constant("pattern")), pattern: required( union( "vertical-lines", "horizontal-lines", "forward-slanted-lines", "backward-slanted-lines", "circles", "squares", "triangles", "diamonds", "stars", "hearts", "crosses" ) ), width: required(positiveNumber), height: required(positiveNumber), fill: required(color), fillOpacity: required(ratio), backgroundFill: required(color), backgroundFillOpacity: required(ratio), padding: required(positiveNumber), rotation: required(number), stroke: required(color), strokeWidth: required(positiveNumber), strokeOpacity: required(ratio) }); var gradientUndocumentedOpts = { // @ts-expect-error undocumented option gradient: union("linear", "radial", "conic"), bounds: gradientBounds, reverse: boolean }; var patternUndocumentedOpts = { // @ts-expect-error undocumented option rotation: number, padding: positiveNumber }; var colorObject = typeUnion( { gradient: { ...gradientUndocumentedOpts, colorStops: gradientColorStops, rotation: number }, pattern: { ...patternUndocumentedOpts, pattern: union( "vertical-lines", "horizontal-lines", "forward-slanted-lines", "backward-slanted-lines", "circles", "squares", "triangles", "diamonds", "stars", "hearts", "crosses" ), width: positiveNumber, height: positiveNumber, fill: color, fillOpacity: ratio, backgroundFill: color, backgroundFillOpacity: ratio, ...strokeOptionsDef } }, "a color object" ); var colorUnion = or(color, colorObject); var fillOptionsDef = { fill: colorUnion, fillOpacity: ratio }; fillOptionsDef.fillGradientDefaults = fillGradientDefaults; fillOptionsDef.fillPatternDefaults = fillPatternDefaults; var lineDashOptionsDef = { lineDash: arrayOf(positiveNumber), lineDashOffset: number }; var fontOptionsDef = { color, fontFamily: string, fontSize: positiveNumber, fontStyle: union("normal", "italic", "oblique"), fontWeight: or(positiveNumber, union("normal", "bold", "bolder", "lighter")) }; // packages/ag-charts-core/src/utils/arrays.ts function toArray(value) { if (typeof value === "undefined") { return []; } return Array.isArray(value) ? value : [value]; } function unique(array2) { return Array.from(new Set(array2)); } function groupBy(array2, iteratee) { return array2.reduce((result, item) => { const groupKey = iteratee(item); result[groupKey] ?? (result[groupKey] = []); result[groupKey].push(item); return result; }, {}); } function arraysEqual(a, b) { if (a == null || b == null || a.length !== b.length) { return false; } for (let i = 0; i < a.length; i++) { if (Array.isArray(a[i]) && Array.isArray(b[i])) { if (!arraysEqual(a[i], b[i])) { return false; } } else if (a[i] !== b[i]) { return false; } } return true; } function circularSliceArray(data, size, offset = 0) { if (data.length === 0) { return []; } const result = []; for (let i = 0; i < size; i++) { result.push(data.at((i + offset) % data.length)); } return result; } function sortBasedOnArray(baseArray, orderArray) { const orderMap = /* @__PURE__ */ new Map(); orderArray.forEach((item, index) => { orderMap.set(item, index); }); return baseArray.sort((a, b) => { const indexA = orderMap.get(a) ?? Infinity; const indexB = orderMap.get(b) ?? Infinity; return indexA - indexB; }); } // packages/ag-charts-core/src/utils/binarySearch.ts function findMaxIndex(min, max, iteratee) { if (min > max) return; let found; while (max >= min) { const index = Math.floor((max + min) / 2); const value = iteratee(index); if (value) { found = index; min = index + 1; } else { max = index - 1; } } return found; } function findMinIndex(min, max, iteratee) { if (min > max) return; let found; while (max >= min) { const index = Math.floor((max + min) / 2); const value = iteratee(index); if (value) { found = index; max = index - 1; } else { min = index + 1; } } return found; } function findMaxValue(min, max, iteratee) { if (min > max) return; let found; while (max >= min) { const index = Math.floor((max + min) / 2); const value = iteratee(index); if (value == null) { max = index - 1; } else { found = value; min = index + 1; } } return found; } function findMinValue(min, max, iteratee) { if (min > max) return; let found; while (max >= min) { const index = Math.floor((max + min) / 2); const value = iteratee(index); if (value == null) { min = index + 1; } else { found = value; max = index - 1; } } return found; } // packages/ag-charts-core/src/utils/diff.ts function diffArrays(previous, current) { const size = Math.max(previous.length, current.length); const added = /* @__PURE__ */ new Set(); const removed = /* @__PURE__ */ new Set(); for (let i = 0; i < size; i++) { const prev = previous[i]; const curr = current[i]; if (prev === curr) continue; if (removed.has(curr)) { removed.delete(curr); } else if (curr) { added.add(curr); } if (added.has(prev)) { added.delete(prev); } else if (prev) { removed.add(prev); } } return { changed: added.size > 0 || removed.size > 0, added, removed }; } // packages/ag-charts-core/src/utils/functions.ts function debounce(callback2, waitMs = 0, options) { const { leading = false, trailing = true, maxWait = Infinity } = options ?? {}; let timerId; let startTime; if (maxWait < waitMs) { throw new Error("Value of maxWait cannot be lower than waitMs."); } function debounceCallback(...args) { if (leading && !startTime) { startTime = Date.now(); timerId = setTimeout(() => startTime = null, waitMs); callback2(...args); return; } let adjustedWaitMs = waitMs; if (maxWait !== Infinity && startTime) { const elapsedTime = Date.now() - startTime; if (waitMs > maxWait - elapsedTime) { adjustedWaitMs = maxWait - elapsedTime; } } clearTimeout(timerId); startTime ?? (startTime = Date.now()); timerId = setTimeout(() => { startTime = null; if (trailing) { callback2(...args); } }, adjustedWaitMs); } return Object.assign(debounceCallback, { cancel() { clearTimeout(timerId); startTime = null; } }); } function throttle(callback2, waitMs, options) { const { leading = true, trailing = true } = options ?? {}; let timerId; let lastArgs; let shouldWait = false; function timeoutHandler() { if (trailing && lastArgs) { timerId = setTimeout(timeoutHandler, waitMs); callback2(...lastArgs); } else { shouldWait = false; } lastArgs = null; } function throttleCallback(...args) { if (shouldWait) { lastArgs = args; } else { shouldWait = true; timerId = setTimeout(timeoutHandler, waitMs); if (leading) { callback2(...args); } else { lastArgs = args; } } } return Object.assign(throttleCallback, { cancel() { clearTimeout(timerId); shouldWait = false; lastArgs = null; } }); } // packages/ag-charts-core/src/utils/iterators.ts function* iterate(...iterators) { for (const iterator of iterators) { yield* iterator; } } function toIterable(value) { return value != null && typeof value === "object" && Symbol.iterator in value ? value : [value]; } function first(iterable) { for (const value of iterable) { return value; } throw new Error("AG Charts - no first() value found"); } function* entries(obj) { const resultTuple = [void 0, void 0]; for (const key of Object.keys(obj)) { resultTuple[0] = key; resultTuple[1] = obj[key]; yield resultTuple; } } // packages/ag-charts-core/src/utils/numbers.ts function clamp(min, value, max) { return Math.min(max, Math.max(min, value)); } function inRange(value, range, epsilon = 1e-10) { return value >= range[0] - epsilon && value <= range[1] + epsilon; } function isNumberEqual(a, b, epsilon = 1e-10) { return a === b || Math.abs(a - b) < epsilon; } function isNegative(value) { return Math.sign(value) === -1 || Object.is(value, -0); } function isInteger(value) { return value % 1 === 0; } function roundTo(value, decimals = 2) { const base = 10 ** decimals; return Math.round(value * base) / base; } function modulus(n, m) { return Math.floor(n % m + (n < 0 ? Math.abs(m) : 0)); } function countFractionDigits(value) { if (Math.floor(value) === value) { return 0; } let valueString = String(value); let exponent = 0; if (value < 1e-6 || value >= 1e21) { let exponentString; [valueString, exponentString] = valueString.split("e"); if (exponentString != null) { exponent = Number(exponentString); } } const decimalPlaces = valueString.split(".")[1]?.length ?? 0; return Math.max(decimalPlaces - exponent, 0); } // packages/ag-charts-core/src/utils/numberFormat.ts var formatRegEx = /^(?:(.)?([<>=^]))?([+\-( ])?([$€£¥₣₹#])?(0)?(\d+)?(,)?(?:\.(\d+))?(~)?([%a-z])?$/i; var surroundedRegEx = /^((?:[^#]|#[^{])*)#{([^}]+)}(.*)$/; function isValidNumberFormat(value) { if (!isString(value)) return false; const match = surroundedRegEx.exec(value); return formatRegEx.test(match ? match[2] : value); } function parseNumberFormat(format) { let prefix; let suffix; const surrounded = surroundedRegEx.exec(format); if (surrounded) { [, prefix, format, suffix] = surrounded; } const match = formatRegEx.exec(format); if (!match) { throw new Error(`The number formatter is invalid: ${format}`); } const [, fill, align, sign, symbol, zero, width, comma, precision, trim, type] = match; return { fill, align, sign, symbol, zero, width: parseInt(width), comma, precision: parseInt(precision), trim: Boolean(trim), type, prefix, suffix }; } function createNumberFormatter(format) { const options = typeof format === "string" ? parseNumberFormat(format) : format; const { fill, align, sign = "-", symbol, zero, width, comma, type, prefix = "", suffix = "", precision } = options; let { trim } = options; const precisionIsNaN = precision == null || isNaN(precision); let formatBody; if (!type) { formatBody = decimalTypes["g"]; trim = true; } else if (type in decimalTypes && type in integerTypes) { formatBody = precisionIsNaN ? integerTypes[type] : decimalTypes[type]; } else if (type in decimalTypes) { formatBody = decimalTypes[type]; } else if (type in integerTypes) { formatBody = integerTypes[type]; } else { throw new Error(`The number formatter type is invalid: ${type}`); } let formatterPrecision; if (precisionIsNaN) { formatterPrecision = type ? 6 : 12; } else { formatterPrecision = precision; } return (n) => { let result = formatBody(n, formatterPrecision); if (trim) { result = removeTrailingZeros(result); } if (comma) { result = insertSeparator(result, comma); } result = addSign(n, result, sign); if (symbol && symbol !== "#") { result = `${symbol}${result}`; } if (symbol === "#" && type === "x") { result = `0x${result}`; } if (type === "s") { result = `${result}${getSIPrefix(n)}`; } if (type === "%" || type === "p") { result = `${result}%`; } if (width != null && !isNaN(width)) { result = addPadding(result, width, fill ?? zero, align); } result = `${prefix}${result}${suffix}`; return result; }; } var integerTypes = { b: (n) => absFloor(n).toString(2), c: (n) => String.fromCharCode(n), d: (n) => Math.round(Math.abs(n)).toFixed(0), o: (n) => absFloor(n).toString(8), x: (n) => absFloor(n).toString(16), X: (n) => integerTypes.x(n).toUpperCase(), n: (n) => integerTypes.d(n), "%": (n) => `${absFloor(n * 100).toFixed(0)}` }; var decimalTypes = { e: (n, f) => Math.abs(n).toExponential(f), E: (n, f) => decimalTypes.e(n, f).toUpperCase(), f: (n, f) => Math.abs(n).toFixed(f), F: (n, f) => decimalTypes.f(n, f).toUpperCase(), g: (n, f) => { if (n === 0) { return "0"; } const a = Math.abs(n); const p = Math.floor(Math.log10(a)); if (p >= -4 && p < f) { return a.toFixed(f - 1 - p); } return a.toExponential(f - 1); }, G: (n, f) => decimalTypes.g(n, f).toUpperCase(), n: (n, f) => decimalTypes.g(n, f), p: (n, f) => decimalTypes.r(n * 100, f), r: (n, f) => { if (n === 0) { return "0"; } const a = Math.abs(n); const p = Math.floor(Math.log10(a)); const q = p - (f - 1); if (q <= 0) { return a.toFixed(-q); } const x = 10 ** q; return (Math.round(a / x) * x).toFixed(); }, s: (n, f) => { const p = getSIPrefixPower(n); return decimalTypes.r(n / 10 ** p, f); }, "%": (n, f) => decimalTypes.f(n * 100, f) }; var minSIPrefix = -24; var maxSIPrefix = 24; var siPrefixes = { [minSIPrefix]: "y", [-21]: "z", [-18]: "a", [-15]: "f", [-12]: "p", [-9]: "n", [-6]: "\xB5", [-3]: "m", [0]: "", [3]: "k", [6]: "M", [9]: "G", [12]: "T", [15]: "P", [18]: "E", [21]: "Z", [maxSIPrefix]: "Y" }; var minusSign = "\u2212"; function absFloor(n) { return Math.floor(Math.abs(n)); } function removeTrailingZeros(numString) { return numString.replace(/\.0+$/, "").replace(/(\.[1-9])0+$/, "$1"); } function insertSeparator(numString, separator) { let dotIndex = numString.indexOf("."); if (dotIndex < 0) { dotIndex = numString.length; } const integerChars = numString.substring(0, dotIndex).split(""); const fractionalPart = numString.substring(dotIndex); for (let i = integerChars.length - 3; i > 0; i -= 3) { integerChars.splice(i, 0, separator); } return `${integerChars.join("")}${fractionalPart}`; } function getSIPrefix(n) { return siPrefixes[getSIPrefixPower(n)]; } function getSIPrefixPower(n) { return clamp(minSIPrefix, n ? Math.floor(Math.log10(Math.abs(n)) / 3) * 3 : 0, maxSIPrefix); } function addSign(num, numString, signType = "") { if (signType === "(") { return num >= 0 ? numString : `(${numString})`; } const plusSign = signType === "+" ? "+" : ""; return `${num >= 0 ? plusSign : minusSign}${numString}`; } function addPadding(numString, width, fill = " ", align = ">") { let result = numString; if (align === ">" || !align) { result = result.padStart(width, fill); } else if (align === "<") { result = result.padEnd(width, fill); } else if (align === "^") { const padWidth = Math.max(0, width - result.length); const padLeft = Math.ceil(padWidth / 2); const padRight = Math.floor(padWidth / 2); result = result.padStart(padLeft + result.length, fill); result = result.padEnd(padRight + result.length, fill); } return result; }