ag-charts-core
Version:
Advanced Charting / Charts supporting Javascript / Typescript / React / Angular / Vue
1,583 lines (1,560 loc) • 57.3 kB
JavaScript
"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, {
AsyncAwaitQueue: () => AsyncAwaitQueue,
ErrorType: () => ErrorType,
EventEmitter: () => EventEmitter,
Logger: () => logger_exports,
ModuleRegistry: () => moduleRegistry_exports,
ModuleType: () => ModuleType,
UnknownError: () => UnknownError,
ValidationError: () => ValidationError,
and: () => and,
array: () => array,
arrayLength: () => arrayLength,
arrayOf: () => arrayOf,
arrayOfDefs: () => arrayOfDefs,
arraysEqual: () => arraysEqual,
attachDescription: () => attachDescription,
boolean: () => boolean,
callback: () => callback,
callbackDefs: () => callbackDefs,
callbackOf: () => callbackOf,
circularSliceArray: () => circularSliceArray,
clamp: () => clamp,
color: () => color,
colorStopsOrderValidator: () => colorStopsOrderValidator,
colorUnion: () => colorUnion,
constant: () => constant,
countFractionDigits: () => countFractionDigits,
countLines: () => countLines,
createElement: () => createElement,
createElementId: () => createElementId,
createId: () => createId,
createNumberFormatter: () => createNumberFormatter,
createSvgElement: () => createSvgElement,
date: () => date,
debounce: () => debounce,
defined: () => defined,
diffArrays: () => diffArrays,
downloadUrl: () => downloadUrl,
dropFirstWhile: () => dropFirstWhile,
dropLastWhile: () => dropLastWhile,
entries: () => entries,
fillGradientDefaults: () => fillGradientDefaults,
fillImageDefaults: () => fillImageDefaults,
fillOptionsDef: () => fillOptionsDef,
fillPatternDefaults: () => fillPatternDefaults,
findMaxIndex: () => findMaxIndex,
findMaxValue: () => findMaxValue,
findMinIndex: () => findMinIndex,
findMinValue: () => findMinValue,
first: () => first,
fontFamilyFull: () => fontFamilyFull,
fontOptionsDef: () => fontOptionsDef,
generateUUID: () => generateUUID,
geoJson: () => geoJson,
getAttribute: () => getAttribute,
getDocument: () => getDocument,
getWindow: () => getWindow,
googleFont: () => googleFont,
gradientColorStops: () => gradientColorStops,
gradientStrict: () => gradientStrict,
greaterThan: () => greaterThan,
groupBy: () => groupBy,
hasRequiredInPath: () => hasRequiredInPath,
htmlElement: () => htmlElement,
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,
isKeyOf: () => isKeyOf,
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,
pause: () => pause,
positiveNumber: () => positiveNumber,
positiveNumberNonZero: () => positiveNumberNonZero,
ratio: () => ratio,
required: () => required,
resetIds: () => resetIds,
roundTo: () => roundTo,
safeCall: () => safeCall,
setAttribute: () => setAttribute,
setAttributes: () => setAttributes,
setDocument: () => setDocument,
setElementStyle: () => setElementStyle,
setElementStyles: () => setElementStyles,
setWindow: () => setWindow,
sortBasedOnArray: () => sortBasedOnArray,
string: () => string,
stringLength: () => stringLength,
stringifyValue: () => stringifyValue,
strokeOptionsDef: () => strokeOptionsDef,
themeOperator: () => themeOperator,
throttle: () => throttle,
toArray: () => toArray,
toIterable: () => toIterable,
typeUnion: () => typeUnion,
undocumented: () => undocumented,
union: () => union,
unionSymbol: () => unionSymbol,
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 guardOnce(messageOrError, prefix, cb) {
let message;
if (messageOrError instanceof Error) {
message = messageOrError.message;
} else if (typeof messageOrError === "string") {
message = messageOrError;
} else if (typeof messageOrError === "object") {
message = JSON.stringify(messageOrError);
} else {
message = String(messageOrError);
}
const cacheKey = `${prefix}: ${message}`;
if (doOnceCache.has(cacheKey))
return;
cb(messageOrError);
doOnceCache.add(cacheKey);
}
function warnOnce(messageOrError, ...logContent) {
guardOnce(messageOrError, "Logger.warn", (message) => warn(message, ...logContent));
}
function errorOnce(messageOrError, ...logContent) {
guardOnce(messageOrError, "Logger.error", (message) => error(message, ...logContent));
}
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,
getPresetModule: () => getPresetModule,
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 (isModuleType(moduleType, definition)) {
yield definition;
}
}
}
function detectChartDefinition(options) {
for (const definition of registeredModules.values()) {
if (isModuleType("chart" /* Chart */, 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 getAxisModule(moduleName) {
const definition = registeredModules.get(moduleName);
if (isModuleType("axis" /* Axis */, definition)) {
return definition;
}
}
function getPresetModule(moduleName) {
const definition = registeredModules.get(moduleName);
if (isModuleType("preset" /* Preset */, definition)) {
return definition;
}
}
function getSeriesModule(moduleName) {
const definition = registeredModules.get(moduleName);
if (isModuleType("series" /* Series */, definition)) {
return definition;
}
}
function isModuleType(moduleType, definition) {
return definition?.type === moduleType;
}
// 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/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) && (value === "none" || parseColor(value) != null);
}
function isKeyOf(value, container) {
return value in container;
}
// 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;
}
});
}
function safeCall(callback2, args, errorPath = "") {
try {
return callback2(...args);
} catch (error2) {
const postfix = errorPath ? ` \`${errorPath}\`` : "";
warnOnce(`Uncaught exception in user callback${postfix}`, error2);
}
}
// packages/ag-charts-core/src/utils/strings.ts
function joinFormatted(values, conjunction = "and", format = String, maxItems = Infinity) {
if (values.length === 0) {
return "";
} else 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/validation.ts
var descriptionSymbol = Symbol("description");
var requiredSymbol = Symbol("required");
var markedSymbol = Symbol("marked");
var undocumentedSymbol = Symbol("undocumented");
var unionSymbol = Symbol("union");
var similarOptionsMap = [
["placement", "position"],
["padding", "spacing", "gap"],
["color", "fill", "stroke"],
["whisker", "wick"],
["nodeClick", "seriesNodeClick"],
["nodeDoubleClick", "seriesNodeDoubleClick"],
["src", "url"]
].reduce((map, words) => {
for (const word of words) {
map.set(word.toLowerCase(), new Set(words.filter((w) => w !== word)));
}
return map;
}, /* @__PURE__ */ new Map());
var ErrorType = /* @__PURE__ */ ((ErrorType2) => {
ErrorType2["Invalid"] = "invalid";
ErrorType2["Required"] = "required";
ErrorType2["Unknown"] = "unknown";
return ErrorType2;
})(ErrorType || {});
function extendPath(path, key) {
if (isFiniteNumber(key)) {
return `${path}[${key}]`;
}
return path ? `${path}.${key}` : key;
}
var ValidationError = class {
constructor(type, description, value, path, key) {
this.type = type;
this.description = description;
this.value = value;
this.path = path;
this.key = key;
}
setUnionType(unionType, path) {
if (this.path.startsWith(path)) {
const suffix = this.path.slice(path.length);
this.altPath = `${path}[type=${unionType}]${suffix}`;
}
}
getPrefix() {
const { altPath: path = this.path, key } = this;
if (!path && !key)
return "Value";
return `Option \`${key ? extendPath(path, key) : path}\``;
}
toString() {
const { description = "unknown", type, value } = this;
if (type === "required" /* Required */ && value == null) {
return `${this.getPrefix()} is required and has not been provided; expecting ${description}, ignoring.`;
}
return `${this.getPrefix()} cannot be set to \`${stringifyValue(value, 50)}\`; expecting ${description}, ignoring.`;
}
};
var UnknownError = class extends ValidationError {
constructor(suggestions, value, path, key) {
super("unknown" /* Unknown */, void 0, value, path, key);
this.suggestions = suggestions;
this.key = key;
}
getPrefix() {
return `Unknown option \`${extendPath(this.path, this.key)}\``;
}
getPostfix() {
const suggestions = joinFormatted(findSuggestions(this.key, this.suggestions), "or", (val) => `\`${val}\``);
return suggestions ? `; Did you mean ${suggestions}? Ignoring.` : ", ignoring.";
}
toString() {
return `${this.getPrefix()}${this.getPostfix()}`;
}
};
function validate(options, optionsDefs2, path = "") {
if (!isObject(options)) {
return { cleared: null, invalid: [new ValidationError("required" /* Required */, "an object", options, path)] };
}
const cleared = {};
const invalid = [];
const optionsKeys = new Set(Object.keys(options));
const unusedKeys = [];
if (unionSymbol in optionsDefs2) {
const validTypes = Object.keys(optionsDefs2);
const defaultType = optionsDefs2[unionSymbol];
if (options.type != null && validTypes.includes(options.type) || options.type == null && defaultType != null) {
const { type = defaultType, ...rest } = options;
const nestedResult = validate(rest, optionsDefs2[type], path);
Object.assign(cleared, { type }, nestedResult.cleared);
for (const error2 of nestedResult.invalid) {
error2.setUnionType(type, path);
}
invalid.push(...nestedResult.invalid);
} else {
const keywords = joinFormatted(validTypes, "or", (val) => `'${val}'`);
invalid.push(
new ValidationError("required" /* Required */, `a keyword such as ${keywords}`, options.type, path, "type")
);
}
return { cleared, invalid };
}
for (const key of Object.keys(optionsDefs2)) {
const validatorOrDefs = optionsDefs2[key];
const required2 = validatorOrDefs[requiredSymbol];
const value = options[key];
optionsKeys.delete(key);
if (typeof value === "undefined") {
if (!validatorOrDefs[undocumentedSymbol]) {
unusedKeys.push(key);
}
if (!required2)
continue;
}
const keyPath = extendPath(path, key);
if (isFunction(validatorOrDefs)) {
const context = { options, path: keyPath };
const validatorResult = validatorOrDefs(value, context);
const objectResult = typeof validatorResult === "object";
if (objectResult) {
invalid.push(...validatorResult.invalid);
if (validatorResult.valid) {
cleared[key] = validatorResult.cleared;
continue;
} else if (hasRequiredInPath(validatorResult.invalid, keyPath)) {
continue;
}
} else if (validatorResult) {
cleared[key] = value;
continue;
}
invalid.push(
new ValidationError(
required2 ? "required" /* Required */ : "invalid" /* Invalid */,
validatorOrDefs[descriptionSymbol],
value,
path,
key
)
);
} else {
const nestedResult = validate(value, validatorOrDefs, keyPath);
if (nestedResult.cleared != null) {
cleared[key] = nestedResult.cleared;
}
invalid.push(...nestedResult.invalid);
}
}
for (const key of optionsKeys) {
const value = options[key];
if (typeof value === "undefined")
continue;
invalid.push(new UnknownError(unusedKeys, value, path, key));
}
return { cleared, invalid };
}
function findSuggestions(value, suggestions, maxDistance = 2) {
const result = [];
const lowerCaseValue = value.toLowerCase();
const similarValues = similarOptionsMap.get(lowerCaseValue);
for (const key of suggestions) {
const lowerCaseKey = key.toLowerCase();
if (similarValues?.has(key) || lowerCaseKey.includes(lowerCaseValue) || levenshteinDistance(lowerCaseValue, lowerCaseKey) <= maxDistance) {
result.push(key);
}
}
return result;
}
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] }
);
}
function undocumented(validatorOrDefs) {
return Object.assign(
isFunction(validatorOrDefs) ? (value, context) => validatorOrDefs(value, context) : optionsDefs(validatorOrDefs),
{ [undocumentedSymbol]: true, [descriptionSymbol]: validatorOrDefs[descriptionSymbol] }
);
}
var optionsDefs = (defs, description = "an object") => attachDescription((value, context) => {
const result = validate(value, defs, context.path);
const valid = !hasRequiredInPath(result.invalid, context.path);
return { valid, cleared: result.cleared, invalid: result.invalid };
}, description);
var typeUnion = (defs, description, defaultType) => ({
...defs,
[descriptionSymbol]: description,
[unionSymbol]: defaultType
});
var and = (...validators) => attachDescription(
(value, context) => {
const invalid = [];
for (const validator of validators) {
const result = validator(value, context);
if (typeof result === "object") {
invalid.push(...result.invalid);
if (!result.valid) {
return { valid: false, cleared: value, invalid };
}
value = result.cleared;
} else if (!result) {
return false;
}
}
return { valid: true, cleared: value, invalid };
},
validators.map((v) => v[descriptionSymbol]).filter(Boolean).join(" and ")
);
var or = (...validators) => attachDescription(
(value, context) => {
for (const validator of validators) {
const result = validator(value, context);
if (typeof result === "object" ? result.valid : result) {
return result;
}
}
return false;
},
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 htmlElement = attachDescription(
(value) => typeof HTMLElement === "undefined" || value instanceof HTMLElement,
"an html element"
);
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 stringLength = (minLength, maxLength = Infinity) => {
let message;
if (maxLength === Infinity) {
message = `a string of at least ${minLength} characters`;
} else if (minLength === maxLength) {
message = `an string of exactly ${minLength} characters`;
} else if (minLength === 0) {
message = `an string of no more than ${maxLength} characters`;
} else {
message = `an string of at least ${minLength} and no more than ${maxLength} characters`;
}
return attachDescription(
(value) => isString(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, strict = true) => attachDescription(
(value, context) => {
if (!isArray(value))
return false;
let valid = strict;
const cleared = [];
const invalid = [];
const setValid = (result) => valid = strict ? valid && result : valid || result;
if (value.length === 0) {
return { valid: true, cleared, invalid };
}
for (let i = 0; i < value.length; i++) {
const options = value[i];
const result = validator(options, { options, path: `${context.path}[${i}]` });
if (typeof result === "object") {
valid = setValid(result.valid);
invalid.push(...result.invalid);
if (result.cleared != null) {
cleared.push(result.cleared);
}
} else {
valid = setValid(result);
if (result) {
cleared.push(options);
}
}
}
return { valid, cleared: valid || !strict ? cleared : null, invalid };
},
description ?? `${validator[descriptionSymbol]} array`
);
var arrayOfDefs = (defs, description = "an object array") => attachDescription((value, context) => {
if (!isArray(value))
return false;
const cleared = [];
const invalid = [];
for (let i = 0; i < value.length; i++) {
const indexPath = `${context.path}[${i}]`;
const result = validate(value[i], defs, indexPath);
if (!hasRequiredInPath(result.invalid, indexPath)) {
cleared.push(result.cleared);
}
invalid.push(...result.invalid);
}
return { valid: true, cleared, invalid };
}, description);
var callbackOf = (validator, description) => attachDescription((value, context) => {
if (!isFunction(value))
return false;
if (markedSymbol in value)
return true;
const cbWithValidation = Object.assign(
(...args) => {
const result = safeCall(value, args);
if (result == null)
return;
const validatorResult = validator(result, { options: result, path: "" });
if (typeof validatorResult === "object") {
validatorResult.invalid.forEach(
callbackWarnInvalid(context, description ?? validator[descriptionSymbol])
);
if (validatorResult.valid) {
return validatorResult.cleared;
}
} else if (validatorResult) {
return result;
} else {
warnOnce(
`Callback \`${context.path}\` returned an invalid value \`${stringifyValue(result, 50)}\`; expecting ${description ?? validator[descriptionSymbol]}, ignoring.`
);
}
},
{ [markedSymbol]: true }
);
return { valid: true, cleared: cbWithValidation, invalid: [] };
}, "a function");
var callbackDefs = (defs, description = "an object") => attachDescription((value, context) => {
if (!isFunction(value))
return false;
if (markedSymbol in value)
return true;
const cbWithValidation = Object.assign(
(...args) => {
const result = safeCall(value, args, context.path);
if (result == null)
return;
const validatorResult = validate(result, defs);
validatorResult.invalid.forEach(callbackWarnInvalid(context, description));
return validatorResult.cleared;
},
{ [markedSymbol]: true }
);
return { valid: true, cleared: cbWithValidation, invalid: [] };
}, "a function");
function hasRequiredInPath(errors, rootPath) {
return errors.some((error2) => error2.type === "required" /* Required */ && error2.path === rootPath);
}
function callbackWarnInvalid(context, description) {
return (error2) => {
if (error2 instanceof UnknownError) {
return warnOnce(
`Callback \`${context.path}\` returned an unknown property \`${extendPath(error2.path, error2.key)}\`${error2.getPostfix()}`
);
}
const errorValue = stringifyValue(error2.value, 50);
warnOnce(
error2.key ? `Callback \`${context.path}\` returned an invalid property \`${extendPath(error2.path, error2.key)}\`: \`${errorValue}\`; expecting ${error2.description}, ignoring.` : `Callback \`${context.path}\` returned an invalid value \`${errorValue}\`; expecting ${description ?? error2.description}, ignoring.`
);
};
}
// packages/ag-charts-core/src/options/commonOptionsDefs.ts
var themeOperator = (value) => {
if (!isObject(value))
return false;
const keys = Object.keys(value);
return keys.length === 1 && keys[0].startsWith("$");
};
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), arrayOf(colorStop), colorStopsOrderValidator);
var gradientBounds = union("axis", "item", "series");
var gradientStrict = optionsDefs(
{
type: required(constant("gradient")),
colorStops: required(gradientColorStops),
rotation: number,
// @ts-expect-error undocumented options
gradient: undocumented(union("linear", "radial", "conic")),
bounds: undocumented(gradientBounds),
reverse: undocumented(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"
)
),
path: stringLength(2),
width: required(positiveNumber),
height: required(positiveNumber),
fill: required(color),
fillOpacity: required(ratio),
backgroundFill: required(color),
backgroundFillOpacity: required(ratio),
padding: required(positiveNumber),
rotation: required(number),
scale: required(positiveNumber),
stroke: required(color),
strokeWidth: required(positiveNumber),
strokeOpacity: required(ratio)
});
var fillImageDefaults = optionsDefs({
type: required(constant("image")),
url: string,
width: positiveNumber,
height: positiveNumber,
rotation: required(number),
backgroundFill: required(color),
backgroundFillOpacity: ratio,
fit: required(union("stretch", "contain", "cover")),
repeat: required(union("repeat", "repeat-x", "repeat-y", "no-repeat"))
});
var colorObject = typeUnion(
{
gradient: {
colorStops: gradientColorStops,
rotation: number,
// @ts-expect-error undocumented option
gradient: undocumented(union("linear", "radial", "conic")),
bounds: undocumented(gradientBounds),
reverse: undocumented(boolean)
},
pattern: {
pattern: union(
"vertical-lines",
"horizontal-lines",
"forward-slanted-lines",
"backward-slanted-lines",
"circles",
"squares",
"triangles",
"diamonds",
"stars",
"hearts",
"crosses"
),
path: stringLength(2),
width: positiveNumber,
height: positiveNumber,
rotation: number,
scale: positiveNumber,
fill: color,
fillOpacity: ratio,
backgroundFill: color,
backgroundFillOpacity: ratio,
...strokeOptionsDef,
// @ts-expect-error undocumented option
padding: undocumented(positiveNumber)
},
image: {
url: required(string),
backgroundFill: color,
backgroundFillOpacity: ratio,
width: positiveNumber,
height: positiveNumber,
fit: union("stretch", "contain", "cover", "none"),
repeat: union("repeat", "repeat-x", "repeat-y", "no-repeat"),
rotation: number
}
},
"a color object"
);
var colorUnion = or(color, optionsDefs(colorObject, "a color object"));
var fillOptionsDef = {
fill: colorUnion,
fillOpacity: ratio
};
fillOptionsDef.fillGradientDefaults = undocumented(fillGradientDefaults);
fillOptionsDef.fillPatternDefaults = undocumented(fillPatternDefaults);
fillOptionsDef.fillImageDefaults = undocumented(fillImageDefaults);
var lineDashOptionsDef = {
lineDash: arrayOf(positiveNumber),
lineDashOffset: number
};
var googleFont = optionsDefs({ googleFont: string }, "google font");
var fontFamilyFull = or(string, themeOperator, googleFont, arrayOf(or(string, googleFont)));
var fontOptionsDef = {
color,
fontFamily: fontFamilyFull,
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;
});
}
function dropFirstWhile(array2, cond) {
let i = 0;
while (i < array2.length && cond(array2[i])) {
i += 1;
}
const deleteCount = i;
if (deleteCount !== 0)
array2.splice(0, deleteCount);
}
function dropLastWhile(array2, cond) {
let i = array2.length - 1;
while (i >= 0 && cond(array2[i])) {
i -= 1;
}
const deleteCount = array2.length - 1 - i;
if (deleteCount !== 0)
array2.splice(array2.length - deleteCount, deleteCount);
}
// packages/ag-charts-core/src/utils/async.ts
var AsyncAwaitQueue = class {
constructor() {
this.queue = [];
}
/** Await another async process to call notify(). */
await(timeout = 50) {
return new Promise((resolve) => {
const successFn = () => {
clearTimeout(timeoutHandle);
resolve(true);
};
const timeoutFn = () => {
const queueIndex = this.queue.indexOf(successFn);
if (queueIndex < 0)
return;
this.queue.splice(queueIndex, 1);
resolve(false);
};
const timeoutHandle = setTimeout(timeoutFn, timeout);
this.queue.push(successFn);
});
}
/** Trigger any await()ing async processes to continue. */
notify() {
this.queue.splice(0).forEach((cb) => cb());
}
};
function pause(delayMilliseconds = 0) {
return new Promise((resolve) => {
setTimeout(resolve, delayMilliseconds);
});
}
// 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/attributeUtil.ts
function booleanParser(value) {
return value === "true";
}
function numberParser(value) {
return Number(value);
}
function stringParser(value) {
return value;
}
var AttributeTypeParsers = {
role: stringParser,
"aria-checked": booleanParser,
"aria-controls": stringParser,
"aria-describedby": stringParser,
"aria-disabled": booleanParser,
"aria-expanded": booleanParser,
"aria-haspopup": stringParser,
"aria-hidden": booleanParser,
"aria-label": stringParser,
"aria-labelledby": stringParser,
"aria-live": stringParser,
"aria-orientation": stringParser,
"aria-selected": booleanParser,
"data-focus-override": booleanParser,
"data-focus-visible-override": booleanParser,
"data-preventdefault": booleanParser,
class: stringParser,
for: stringParser,
id: stringParser,
tabindex: numberParser,
title: stringParser,
placeholder: stringParser
};
function setAttribute(e, qualifiedName, value) {
if (value == null || value === "" || value === "") {
e?.removeAttribute(qualifiedName);
} else {
e?.setAttribute(qualifiedName, value.toString());
}
}
function setAttributes(e, attrs) {
if (attrs == null)
return;
for (const [key, value] of entries(attrs)) {
if (key === "class")
continue;
setAttribute(e, key, value);
}
}
function getAttribute(e, qualifiedName, defaultValue) {
if (!(e instanceof HTMLElement))
return void 0;
const value = e.getAttribute(qualifiedName);
if (value === null)
return defaultValue;
return AttributeTypeParsers[qualifiedName]?.(value) ?? void 0;
}
function setElementStyle(e, property, value) {
if (e == null)
return;
if (value == null) {
e.style.removeProperty(property);
} else {
e.style.setProperty(property, value.toString());
}
}
function setElementStyles(e, styles) {
for (const [key, value] of entries(styles)) {
setElementStyle(e, key, value);
}
}
// 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/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/geoJson.ts
function isValidCoordinate(value) {
return Array.isArray(value) && value.length >= 2 && value.every(isFiniteNumber);
}
function isValidCoordinates(value) {
return Array.isArray(value) && value.length >= 2 && value.every(isValidCoordinate);
}
function hasSameStartEndPoint(c) {
const start = c[0];
const end = c[c.length - 1];
return isNumberEqual(start[0], end[0], 1e-3) && isNumberEqual(start[1], end[1], 1e-3);
}
function isValidPolygon(value) {
return Array.isArray(value) && value.every(isValidCoordinates) && value.every(hasSameStartEndPoint);
}
function isValidGeometry(value) {
if (value === null)
return true;
if (!isObject(value) || value.type == null)
return false;
const { type, coordinates } = value;
switch (type) {
case "GeometryCollection":
return Array.isArray(value.geometries) && value.geometries.every(isValidGeometry);
case "MultiPolygon":
return Array.isArray(coordinates) && coordinates.every(isValidPolygon);
case "Polygon":
return isValidPolygon(coordinates);
case "MultiLineString":
return Array.isArray(coordinates) && coordinates.every(isValidCoordinates);
case "LineString":
return isValidCoordinates(coordinates);
case "MultiPoint":
return isValidCoordinates(coordinates);
case "Point":
return isValidCoordinate(coordinates);
default:
return false;
}
}
function isValidFeature(value) {
return isObject(value) && value.type === "Feature" && isValidGeometry(value.geometry);
}
function isValidFeatureCollection(value) {
return isObject(value) && value.type === "FeatureCollection" && Array.isArray(value.feat