9567 lines
285 KiB
JavaScript
Executable File
9567 lines
285 KiB
JavaScript
Executable File
var __defProp = Object.defineProperty;
|
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
var __export = (target, all) => {
|
|
for (var name in all)
|
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
};
|
|
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-core/src/modules/moduleDefinition.ts
|
|
var ModuleType = /* @__PURE__ */ ((ModuleType2) => {
|
|
ModuleType2["Chart"] = "chart";
|
|
ModuleType2["Axis"] = "axis";
|
|
ModuleType2["Series"] = "series";
|
|
ModuleType2["Plugin"] = "plugin";
|
|
ModuleType2["AxisPlugin"] = "axis:plugin";
|
|
ModuleType2["SeriesPlugin"] = "series:plugin";
|
|
ModuleType2["Preset"] = "preset";
|
|
return ModuleType2;
|
|
})(ModuleType || {});
|
|
|
|
// packages/ag-charts-core/src/types/scales.ts
|
|
function extractDomain(value) {
|
|
return value.domain;
|
|
}
|
|
var ScaleAlignment = /* @__PURE__ */ ((ScaleAlignment2) => {
|
|
ScaleAlignment2[ScaleAlignment2["Leading"] = 0] = "Leading";
|
|
ScaleAlignment2[ScaleAlignment2["Trailing"] = 1] = "Trailing";
|
|
ScaleAlignment2[ScaleAlignment2["Interpolate"] = 2] = "Interpolate";
|
|
return ScaleAlignment2;
|
|
})(ScaleAlignment || {});
|
|
|
|
// packages/ag-charts-core/src/structures/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) {
|
|
const listeners = this.events.get(eventName);
|
|
if (listeners) {
|
|
for (const callback2 of listeners) {
|
|
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/structures/lruCache.ts
|
|
var LRUCache = class {
|
|
constructor(maxCacheSize) {
|
|
this.maxCacheSize = maxCacheSize;
|
|
this.store = /* @__PURE__ */ new Map();
|
|
if (maxCacheSize <= 0) {
|
|
throw new Error("LRUCache size must be greater than 0");
|
|
}
|
|
}
|
|
get(key) {
|
|
if (!this.store.has(key))
|
|
return;
|
|
const value = this.store.get(key);
|
|
this.store.delete(key);
|
|
this.store.set(key, value);
|
|
return value;
|
|
}
|
|
has(key) {
|
|
return this.store.has(key);
|
|
}
|
|
set(key, value) {
|
|
this.store.set(key, value);
|
|
if (this.store.size > this.maxCacheSize) {
|
|
this.store.delete(this.store.keys().next().value);
|
|
}
|
|
return value;
|
|
}
|
|
clear() {
|
|
this.store.clear();
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-core/src/logging/debugLogger.ts
|
|
var debugLogger_exports = {};
|
|
__export(debugLogger_exports, {
|
|
Time: () => Time,
|
|
check: () => check,
|
|
create: () => create,
|
|
inDevelopmentMode: () => inDevelopmentMode
|
|
});
|
|
|
|
// packages/ag-charts-core/src/utils/data/arrays.ts
|
|
function toArray(value) {
|
|
if (value === void 0) {
|
|
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();
|
|
for (const [index, item] of orderArray.entries()) {
|
|
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);
|
|
}
|
|
function distribute(min, max, maxCount) {
|
|
const values = [min];
|
|
const step = Math.round((max - min) / (maxCount - 1));
|
|
if (step > 0) {
|
|
for (let i = min + step; i < max; i += step) {
|
|
const length2 = values.push(i);
|
|
if (length2 >= maxCount - 1)
|
|
break;
|
|
}
|
|
}
|
|
values.push(max);
|
|
return values;
|
|
}
|
|
|
|
// packages/ag-charts-core/src/utils/dom/globalsProxy.ts
|
|
var verifiedGlobals = {};
|
|
if (typeof globalThis.window !== "undefined") {
|
|
verifiedGlobals.window = globalThis.window;
|
|
}
|
|
if (typeof document !== "undefined") {
|
|
verifiedGlobals.document = document;
|
|
} else if (typeof globalThis.global !== "undefined") {
|
|
verifiedGlobals.document = globalThis.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(window) {
|
|
verifiedGlobals.window = window;
|
|
}
|
|
function getOffscreenCanvas() {
|
|
return verifiedGlobals.window?.OffscreenCanvas ?? globalThis.OffscreenCanvas;
|
|
}
|
|
function getPath2D() {
|
|
return verifiedGlobals.window?.Path2D ?? globalThis.Path2D;
|
|
}
|
|
function getDOMMatrix() {
|
|
return verifiedGlobals.window?.DOMMatrix ?? globalThis.DOMMatrix;
|
|
}
|
|
function getImage() {
|
|
return verifiedGlobals.window?.Image ?? globalThis.Image;
|
|
}
|
|
function getResizeObserver() {
|
|
return verifiedGlobals.window?.ResizeObserver ?? globalThis.ResizeObserver;
|
|
}
|
|
var ELEMENT_NODE = 1;
|
|
var DOCUMENT_FRAGMENT_NODE = 11;
|
|
function isNode(obj) {
|
|
return obj != null && typeof obj.nodeType === "number";
|
|
}
|
|
function isElement(obj) {
|
|
return obj != null && obj.nodeType === ELEMENT_NODE;
|
|
}
|
|
function isDocumentFragment(obj) {
|
|
return obj != null && obj.nodeType === DOCUMENT_FRAGMENT_NODE;
|
|
}
|
|
function isHTMLElement(obj) {
|
|
return obj != null && obj.nodeType === ELEMENT_NODE && "style" in obj;
|
|
}
|
|
|
|
// packages/ag-charts-core/src/logging/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/logging/debugLogger.ts
|
|
var LongTimePeriodThreshold = 2e3;
|
|
var timeOfLastLog = Date.now();
|
|
function logTimeGap() {
|
|
const timeSinceLastLog = Date.now() - timeOfLastLog;
|
|
if (timeSinceLastLog > LongTimePeriodThreshold) {
|
|
const prettyDuration = (Math.floor(timeSinceLastLog / 100) / 10).toFixed(1);
|
|
log(`**** ${prettyDuration}s since last log message ****`);
|
|
}
|
|
timeOfLastLog = Date.now();
|
|
}
|
|
function create(...debugSelectors) {
|
|
const resultFn = (...logContent) => {
|
|
if (check(...debugSelectors)) {
|
|
if (typeof logContent[0] === "function") {
|
|
logContent = toArray(logContent[0]());
|
|
}
|
|
logTimeGap();
|
|
log(...logContent);
|
|
}
|
|
};
|
|
return Object.assign(resultFn, {
|
|
check: () => check(...debugSelectors),
|
|
group: (name, cb) => {
|
|
if (check(...debugSelectors)) {
|
|
return logGroup(name, cb);
|
|
}
|
|
return cb();
|
|
}
|
|
});
|
|
}
|
|
function check(...debugSelectors) {
|
|
if (debugSelectors.length === 0) {
|
|
debugSelectors.push(true);
|
|
}
|
|
const chartDebug = toArray(getWindow("agChartsDebug"));
|
|
return chartDebug.some((selector) => debugSelectors.includes(selector));
|
|
}
|
|
function inDevelopmentMode(fn) {
|
|
if (check("dev")) {
|
|
return fn();
|
|
}
|
|
}
|
|
function Time(name, opts = {}) {
|
|
const { logResult = true, logStack = false, logArgs = false, logData } = opts;
|
|
return function(_target, _propertyKey, descriptor) {
|
|
const method = descriptor.value;
|
|
descriptor.value = function(...args) {
|
|
const start2 = performance.now();
|
|
const result = method.apply(this, args);
|
|
const duration = performance.now() - start2;
|
|
const logMessage = { duration };
|
|
if (logResult)
|
|
logMessage.result = result;
|
|
if (logArgs)
|
|
logMessage.args = args;
|
|
if (logStack)
|
|
logMessage.stack = new Error("Stack trace for timing debug").stack;
|
|
if (logData)
|
|
logMessage.logData = logData(this);
|
|
log(name, logMessage);
|
|
return result;
|
|
};
|
|
};
|
|
}
|
|
|
|
// packages/ag-charts-core/src/logging/debugMetrics.ts
|
|
var debugMetrics_exports = {};
|
|
__export(debugMetrics_exports, {
|
|
flush: () => flush,
|
|
record: () => record
|
|
});
|
|
var metrics = /* @__PURE__ */ new Map();
|
|
function record(key, value) {
|
|
if (!check("scene:stats:verbose"))
|
|
return;
|
|
metrics.set(key, value);
|
|
}
|
|
function flush() {
|
|
const result = Object.fromEntries(metrics);
|
|
metrics.clear();
|
|
return result;
|
|
}
|
|
|
|
// packages/ag-charts-core/src/modules/enterpriseRegistry.ts
|
|
var enterpriseRegistry = {};
|
|
|
|
// packages/ag-charts-core/src/modules/moduleRegistry.ts
|
|
var moduleRegistry_exports = {};
|
|
__export(moduleRegistry_exports, {
|
|
RegistryMode: () => RegistryMode,
|
|
getAxisModule: () => getAxisModule,
|
|
getChartModule: () => getChartModule,
|
|
getPresetModule: () => getPresetModule,
|
|
getSeriesModule: () => getSeriesModule,
|
|
hasModule: () => hasModule,
|
|
isEnterprise: () => isEnterprise,
|
|
isIntegrated: () => isIntegrated,
|
|
isModuleType: () => isModuleType,
|
|
isUmd: () => isUmd,
|
|
listModules: () => listModules,
|
|
listModulesByType: () => listModulesByType,
|
|
register: () => register,
|
|
registerModules: () => registerModules,
|
|
reset: () => reset2,
|
|
setRegistryMode: () => setRegistryMode
|
|
});
|
|
var RegistryMode = /* @__PURE__ */ ((RegistryMode2) => {
|
|
RegistryMode2["Enterprise"] = "enterprise";
|
|
RegistryMode2["Integrated"] = "integrated";
|
|
RegistryMode2["UMD"] = "umd";
|
|
return RegistryMode2;
|
|
})(RegistryMode || {});
|
|
var registeredModes = /* @__PURE__ */ new Set();
|
|
var registeredModules = /* @__PURE__ */ new Map();
|
|
function registerModuleDefinition(def) {
|
|
registeredModules.set(def.name, def);
|
|
if (def.dependencies) {
|
|
for (const dependency of def.dependencies) {
|
|
register(dependency);
|
|
}
|
|
}
|
|
}
|
|
function register(def) {
|
|
const existingDefinition = registeredModules.get(def.name);
|
|
if (!existingDefinition) {
|
|
registerModuleDefinition(def);
|
|
return;
|
|
}
|
|
if (existingDefinition.version === def.version) {
|
|
if (!existingDefinition.enterprise && def.enterprise) {
|
|
registerModuleDefinition(def);
|
|
}
|
|
return;
|
|
}
|
|
throw new Error(
|
|
[
|
|
`AG Charts - Module '${def.name}' already registered with different version:`,
|
|
`${existingDefinition.version} vs ${def.version}`,
|
|
``,
|
|
`Check your package.json for conflicting dependencies - depending on your package manager`,
|
|
`one of these commands may help:`,
|
|
`- npm ls ag-charts-community`,
|
|
`- yarn why ag-charts-community`
|
|
].join("\n")
|
|
);
|
|
}
|
|
function registerModules(definitions) {
|
|
for (const definition of definitions.flat()) {
|
|
register(definition);
|
|
}
|
|
}
|
|
function reset2() {
|
|
registeredModes.clear();
|
|
registeredModules.clear();
|
|
}
|
|
function hasModule(moduleName) {
|
|
return registeredModules.has(moduleName);
|
|
}
|
|
function* listModules() {
|
|
for (const definition of registeredModules.values()) {
|
|
yield definition;
|
|
}
|
|
}
|
|
function* listModulesByType(moduleType) {
|
|
for (const definition of registeredModules.values()) {
|
|
if (isModuleType(moduleType, definition)) {
|
|
yield definition;
|
|
}
|
|
}
|
|
}
|
|
function getAxisModule(moduleName) {
|
|
const definition = registeredModules.get(moduleName);
|
|
if (isModuleType("axis" /* Axis */, definition)) {
|
|
return definition;
|
|
}
|
|
}
|
|
function getChartModule(moduleName) {
|
|
const definition = registeredModules.get(moduleName);
|
|
if (isModuleType("chart" /* Chart */, definition)) {
|
|
return definition;
|
|
}
|
|
throw new Error(
|
|
`AG Charts - Unknown chart type; Check options are correctly structured and series types are specified`
|
|
);
|
|
}
|
|
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 setRegistryMode(registryFlag) {
|
|
registeredModes.add(registryFlag);
|
|
}
|
|
function isEnterprise() {
|
|
return registeredModes.has("enterprise" /* Enterprise */);
|
|
}
|
|
function isIntegrated() {
|
|
return registeredModes.has("integrated" /* Integrated */);
|
|
}
|
|
function isUmd() {
|
|
return registeredModes.has("umd" /* UMD */);
|
|
}
|
|
function isModuleType(moduleType, definition) {
|
|
return definition?.type === moduleType;
|
|
}
|
|
|
|
// packages/ag-charts-core/src/state/cleanupRegistry.ts
|
|
var CleanupRegistry = class {
|
|
constructor() {
|
|
this.callbacks = /* @__PURE__ */ new Set();
|
|
}
|
|
flush() {
|
|
for (const cb of this.callbacks) {
|
|
cb();
|
|
}
|
|
this.callbacks.clear();
|
|
}
|
|
merge(registry) {
|
|
for (const cb of registry.callbacks) {
|
|
this.callbacks.add(cb);
|
|
}
|
|
}
|
|
register(...callbacks) {
|
|
for (const cb of callbacks) {
|
|
if (!cb)
|
|
continue;
|
|
this.callbacks.add(cb);
|
|
}
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-core/src/modules/moduleInstance.ts
|
|
var AbstractModuleInstance = class {
|
|
constructor() {
|
|
this.cleanup = new CleanupRegistry();
|
|
}
|
|
destroy() {
|
|
this.cleanup.flush();
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-types/src/chart/navigatorOptions.ts
|
|
var __MINI_CHART_SERIES_OPTIONS = void 0;
|
|
var __VERIFY_MINI_CHART_SERIES_OPTIONS = void 0;
|
|
__VERIFY_MINI_CHART_SERIES_OPTIONS = __MINI_CHART_SERIES_OPTIONS;
|
|
|
|
// packages/ag-charts-types/src/chart/themeOptions.ts
|
|
var __THEME_OVERRIDES = void 0;
|
|
var __VERIFY_THEME_OVERRIDES = void 0;
|
|
__VERIFY_THEME_OVERRIDES = __THEME_OVERRIDES;
|
|
|
|
// packages/ag-charts-types/src/presets/gauge/commonOptions.ts
|
|
var __THEMEABLE_OPTIONS = void 0;
|
|
var __VERIFY_THEMEABLE_OPTIONS = void 0;
|
|
__VERIFY_THEMEABLE_OPTIONS = __THEMEABLE_OPTIONS;
|
|
var __AXIS_LABEL_OPTIONS = void 0;
|
|
var __VERIFY_AXIS_LABEL_OPTIONS = void 0;
|
|
__VERIFY_AXIS_LABEL_OPTIONS = __AXIS_LABEL_OPTIONS;
|
|
|
|
// packages/ag-charts-core/src/types/text.ts
|
|
var EllipsisChar = "\u2026";
|
|
var LineSplitter = /\r?\n/g;
|
|
var TrimEdgeGuard = "\u200B";
|
|
var TrimCharsRegex = /[\s.,;:-]{1,5}$/;
|
|
|
|
// packages/ag-charts-core/src/utils/dom/domUtils.ts
|
|
var style;
|
|
function parseColor(color2) {
|
|
if (style == null) {
|
|
const OptionConstructor = getWindow("Option");
|
|
style = new OptionConstructor().style;
|
|
}
|
|
style.color = color2;
|
|
const result = style.color || null;
|
|
style.color = "";
|
|
return result;
|
|
}
|
|
|
|
// packages/ag-charts-core/src/utils/types/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) && !Number.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 isEmptyObject(value) {
|
|
if (typeof value !== "object" || value === null)
|
|
return false;
|
|
for (const _ in value) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
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 value != null && value.nodeType === 1 && "style" in value;
|
|
}
|
|
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/text/textUtils.ts
|
|
function toFontString({ fontSize, fontStyle, fontWeight: fontWeight2, fontFamily }) {
|
|
let fontString = "";
|
|
if (fontStyle && fontStyle !== "normal") {
|
|
fontString += `${fontStyle} `;
|
|
}
|
|
if (fontWeight2 && fontWeight2 !== "normal" && fontWeight2 !== 400) {
|
|
fontString += `${fontWeight2} `;
|
|
}
|
|
fontString += `${fontSize}px`;
|
|
fontString += ` ${fontFamily}`;
|
|
return fontString;
|
|
}
|
|
function calcLineHeight(fontSize, lineHeightRatio = 1.15) {
|
|
return Math.round(fontSize * lineHeightRatio);
|
|
}
|
|
function toTextString(value) {
|
|
return String(value ?? "");
|
|
}
|
|
function appendEllipsis(text) {
|
|
return text.replace(TrimCharsRegex, "") + EllipsisChar;
|
|
}
|
|
function guardTextEdges(str) {
|
|
return TrimEdgeGuard + str + TrimEdgeGuard;
|
|
}
|
|
function unguardTextEdges(str) {
|
|
return str.replaceAll(TrimEdgeGuard, "");
|
|
}
|
|
function isTruncated(value) {
|
|
return isArray(value) ? isSegmentTruncated(value.at(-1)) : isTextTruncated(toTextString(value));
|
|
}
|
|
function isTextTruncated(str) {
|
|
return str.endsWith(EllipsisChar);
|
|
}
|
|
function isSegmentTruncated(segment) {
|
|
return toTextString(segment?.text).endsWith(EllipsisChar);
|
|
}
|
|
|
|
// packages/ag-charts-core/src/utils/data/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 (Number.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.codePointAt(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];
|
|
}
|
|
function kebabCase(a) {
|
|
return a.replaceAll(KEBAB_CASE_REGEX, (match, offset) => (offset > 0 ? "-" : "") + match.toLowerCase());
|
|
}
|
|
var KEBAB_CASE_REGEX = /[A-Z]+(?![a-z])|[A-Z]/g;
|
|
function toPlainText(text, fallback = "") {
|
|
if (text == null) {
|
|
return fallback;
|
|
} else if (isArray(text)) {
|
|
return text.map((segment) => toTextString(segment.text)).join("");
|
|
} else if (isString(text)) {
|
|
return text;
|
|
} else {
|
|
return String(text);
|
|
}
|
|
}
|
|
|
|
// 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/state/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"],
|
|
["src", "url"],
|
|
["width", "thickness"]
|
|
].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.altPath ?? 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 required3 = validatorOrDefs[requiredSymbol];
|
|
const value = options[key];
|
|
optionsKeys.delete(key);
|
|
if (value === void 0) {
|
|
if (!validatorOrDefs[undocumentedSymbol]) {
|
|
unusedKeys.push(key);
|
|
}
|
|
if (!required3)
|
|
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(
|
|
required3 ? "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 (value === void 0)
|
|
continue;
|
|
invalid.push(new UnknownError(unusedKeys, value, path, key));
|
|
}
|
|
return { cleared, invalid };
|
|
}
|
|
function findSuggestions(value, suggestions, maxDistance = 2) {
|
|
const lowerCaseValue = value.toLowerCase();
|
|
const similarValues = similarOptionsMap.get(lowerCaseValue);
|
|
return suggestions.filter((key) => {
|
|
const lowerCaseKey = key.toLowerCase();
|
|
return similarValues?.has(key) === true || lowerCaseKey.includes(lowerCaseValue) || levenshteinDistance(lowerCaseValue, lowerCaseKey) <= maxDistance;
|
|
});
|
|
}
|
|
function attachDescription(validatorOrDefs, description) {
|
|
if (isFunction(validatorOrDefs)) {
|
|
let clonedValidator2 = function(value, context) {
|
|
return validatorOrDefs(value, context);
|
|
};
|
|
var clonedValidator = clonedValidator2;
|
|
clonedValidator2[descriptionSymbol] = description;
|
|
return clonedValidator2;
|
|
} else {
|
|
return { ...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", failAll = false) => attachDescription((value, context) => {
|
|
const result = validate(value, defs, context.path);
|
|
const valid = !hasRequiredInPath(result.invalid, context.path);
|
|
return { valid, cleared: valid || !failAll ? result.cleared : null, 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 };
|
|
},
|
|
joinFormatted(
|
|
validators.filter((v) => !v[undocumentedSymbol]).map((v) => v[descriptionSymbol]).filter(isDefined),
|
|
"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;
|
|
},
|
|
joinFormatted(
|
|
validators.filter((v) => !v[undocumentedSymbol]).map((v) => v[descriptionSymbol]).filter(isDefined),
|
|
"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(isHtmlElement, "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 lessThanOrEqual = (otherField) => attachDescription(
|
|
(value, { options }) => !isComparable(value) || !isComparable(options[otherField]) || value <= options[otherField],
|
|
`the value to be less than or equal to \`${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}`);
|
|
}
|
|
function strictUnion() {
|
|
return union;
|
|
}
|
|
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 updateValidity = (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") {
|
|
updateValidity(result.valid);
|
|
invalid.push(...result.invalid);
|
|
if (result.cleared != null) {
|
|
cleared.push(result.cleared);
|
|
}
|
|
} else {
|
|
updateValidity(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 validatorDescription = description ?? validator[descriptionSymbol];
|
|
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") {
|
|
warnCallbackErrors(validatorResult, context, validatorDescription, result);
|
|
if (validatorResult.valid) {
|
|
return validatorResult.cleared;
|
|
}
|
|
} else if (validatorResult) {
|
|
return result;
|
|
} else {
|
|
warnOnce(
|
|
`Callback \`${context.path}\` returned an invalid value \`${stringifyValue(result, 50)}\`; expecting ${validatorDescription}, 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 validatorDescription = description;
|
|
const cbWithValidation = Object.assign(
|
|
(...args) => {
|
|
const result = safeCall(value, args, context.path);
|
|
if (result == null)
|
|
return;
|
|
const validatorResult = validate(result, defs);
|
|
warnCallbackErrors(validatorResult, context, validatorDescription, result);
|
|
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 warnCallbackErrors(validatorResult, context, description, result) {
|
|
if (validatorResult.invalid.length === 0)
|
|
return;
|
|
if (isArray(result)) {
|
|
const expectedDescription = description ?? validatorResult.invalid[0]?.description ?? "a valid value";
|
|
return warnOnce(
|
|
`Callback \`${context.path}\` returned an invalid value \`${stringifyValue(result, 50)}\`; expecting ${expectedDescription}, ignoring.`
|
|
);
|
|
}
|
|
for (const error2 of validatorResult.invalid) {
|
|
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/utils/data/numbers.ts
|
|
function clamp(min, value, max) {
|
|
return Math.min(max, Math.max(min, value));
|
|
}
|
|
function inRange(value, range2, epsilon = 1e-10) {
|
|
return value >= range2[0] - epsilon && value <= range2[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 ceilTo(value, decimals = 2) {
|
|
const base = 10 ** decimals;
|
|
return Math.ceil(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 decimalPlaces2 = valueString.split(".")[1]?.length ?? 0;
|
|
return Math.max(decimalPlaces2 - exponent, 0);
|
|
}
|
|
|
|
// packages/ag-charts-core/src/utils/format/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) {
|
|
warnOnce(`The number formatter is invalid: ${format}`);
|
|
return;
|
|
}
|
|
const [, fill, align, sign, symbol, zero, width2, comma, precision, trim, type] = match;
|
|
return {
|
|
fill,
|
|
align,
|
|
sign,
|
|
symbol,
|
|
zero,
|
|
width: Number.parseInt(width2),
|
|
comma,
|
|
precision: Number.parseInt(precision),
|
|
trim: Boolean(trim),
|
|
type,
|
|
prefix,
|
|
suffix
|
|
};
|
|
}
|
|
function createNumberFormatter(format) {
|
|
const options = typeof format === "string" ? parseNumberFormat(format) : format;
|
|
if (options == null)
|
|
return;
|
|
const { fill, align, sign = "-", symbol, zero, width: width2, comma, type, prefix = "", suffix = "", precision } = options;
|
|
let { trim } = options;
|
|
const precisionIsNaN = precision == null || Number.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}`);
|
|
}
|
|
const defaultFormatterPrecision = type ? 6 : 12;
|
|
let formatterPrecision;
|
|
if (!precisionIsNaN) {
|
|
formatterPrecision = precision;
|
|
}
|
|
let padAlign = align;
|
|
let padFill = fill;
|
|
if (zero) {
|
|
padFill ?? (padFill = "0");
|
|
padAlign ?? (padAlign = "=");
|
|
}
|
|
return (n, fractionDigits) => {
|
|
let effectivePrecision;
|
|
if (formatterPrecision != null) {
|
|
effectivePrecision = formatterPrecision;
|
|
} else if (type === "f" || type === "%") {
|
|
effectivePrecision = fractionDigits ?? defaultFormatterPrecision;
|
|
} else if (type) {
|
|
effectivePrecision = defaultFormatterPrecision;
|
|
} else {
|
|
effectivePrecision = fractionDigits ?? defaultFormatterPrecision;
|
|
}
|
|
let result = formatBody(n, effectivePrecision);
|
|
if (trim) {
|
|
result = removeTrailingZeros(result);
|
|
}
|
|
if (comma) {
|
|
result = insertSeparator(result, comma);
|
|
}
|
|
const symbolPrefix = getSymbolPrefix(symbol, type);
|
|
const symbolPrefixLength = symbolPrefix?.length ?? 0;
|
|
if (symbolPrefix) {
|
|
result = `${symbolPrefix}${result}`;
|
|
}
|
|
if (type === "s") {
|
|
result = `${result}${getSIPrefix(n)}`;
|
|
}
|
|
if (type === "%" || type === "p") {
|
|
result = `${result}%`;
|
|
}
|
|
const { value: signedResult, prefixLength: signPrefixLength } = addSign(n, result, sign);
|
|
const totalPrefixLength = signPrefixLength + symbolPrefixLength;
|
|
let output = signedResult;
|
|
if (width2 != null && !Number.isNaN(width2)) {
|
|
output = addPadding(output, width2, padFill ?? " ", padAlign, totalPrefixLength);
|
|
}
|
|
output = `${prefix}${output}${suffix}`;
|
|
return output;
|
|
};
|
|
}
|
|
var integerTypes = {
|
|
b: (n) => absFloor(n).toString(2),
|
|
c: (n) => String.fromCodePoint(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) {
|
|
if (!numString.endsWith("0") || !numString.includes("."))
|
|
return numString;
|
|
let endIndex = numString.length - 1;
|
|
while (endIndex > 0) {
|
|
if (numString[endIndex] == "0") {
|
|
endIndex -= 1;
|
|
} else if (numString[endIndex] == ".") {
|
|
endIndex -= 1;
|
|
break;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
return numString.substring(0, endIndex + 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 === "(") {
|
|
if (num >= 0) {
|
|
return { value: numString, prefixLength: 0 };
|
|
}
|
|
return { value: `(${numString})`, prefixLength: 1 };
|
|
}
|
|
let signPrefix = "";
|
|
if (num < 0) {
|
|
signPrefix = minusSign;
|
|
} else if (signType === "+") {
|
|
signPrefix = "+";
|
|
} else if (signType === " ") {
|
|
signPrefix = " ";
|
|
}
|
|
return { value: `${signPrefix}${numString}`, prefixLength: signPrefix.length };
|
|
}
|
|
function addPadding(numString, width2, fill = " ", align = ">", prefixLength = 0) {
|
|
const padSize = width2 - numString.length;
|
|
if (padSize <= 0) {
|
|
return numString;
|
|
}
|
|
const padding2 = fill.repeat(padSize);
|
|
if (align === "=") {
|
|
const clampedPrefix = Math.min(Math.max(prefixLength, 0), numString.length);
|
|
const start2 = numString.slice(0, clampedPrefix);
|
|
const rest = numString.slice(clampedPrefix);
|
|
return `${start2}${padding2}${rest}`;
|
|
}
|
|
if (align === ">" || !align) {
|
|
return padding2 + numString;
|
|
} else if (align === "<") {
|
|
return `${numString}${padding2}`;
|
|
} else if (align === "^") {
|
|
const padLeft = Math.ceil(padSize / 2);
|
|
const padRight = Math.floor(padSize / 2);
|
|
return `${fill.repeat(padLeft)}${numString}${fill.repeat(padRight)}`;
|
|
}
|
|
return padding2 + numString;
|
|
}
|
|
function getSymbolPrefix(symbol, type) {
|
|
if (symbol === "#") {
|
|
switch (type) {
|
|
case "b":
|
|
return "0b";
|
|
case "o":
|
|
return "0o";
|
|
case "x":
|
|
return "0x";
|
|
case "X":
|
|
return "0X";
|
|
default:
|
|
return "";
|
|
}
|
|
}
|
|
return symbol ?? "";
|
|
}
|
|
|
|
// packages/ag-charts-core/src/config/optionsDefaults.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;
|
|
}, "colour stops to be defined in ascending order");
|
|
var gradientColorStops = and(arrayLength(2), arrayOf(colorStop), colorStopsOrderValidator);
|
|
var gradientBounds = union("axis", "item", "series");
|
|
var gradientStrictDefs = {
|
|
type: required(constant("gradient")),
|
|
colorStops: required(gradientColorStops),
|
|
rotation: number,
|
|
// @ts-expect-error undocumented option
|
|
gradient: undocumented(union("linear", "radial", "conic")),
|
|
bounds: undocumented(gradientBounds),
|
|
reverse: undocumented(boolean),
|
|
colorSpace: undocumented(union("rgb", "oklch"))
|
|
};
|
|
var gradientStrict = optionsDefs(
|
|
gradientStrictDefs,
|
|
"a gradient object with colour 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),
|
|
colorSpace: required(union("rgb", "oklch"))
|
|
});
|
|
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 colorObjectDefs = {
|
|
// @ts-expect-error undocumented option
|
|
gradient: {
|
|
colorStops: gradientColorStops,
|
|
rotation: number,
|
|
gradient: undocumented(union("linear", "radial", "conic")),
|
|
bounds: undocumented(gradientBounds),
|
|
reverse: undocumented(boolean),
|
|
colorSpace: undocumented(union("rgb", "oklch"))
|
|
},
|
|
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,
|
|
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
|
|
}
|
|
};
|
|
var colorObject = typeUnion(colorObjectDefs, "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 barHighlightOptionsDef = {
|
|
...fillOptionsDef,
|
|
...strokeOptionsDef,
|
|
...lineDashOptionsDef,
|
|
opacity: ratio,
|
|
cornerRadius: positiveNumber
|
|
};
|
|
var lineHighlightOptionsDef = {
|
|
...strokeOptionsDef,
|
|
...lineDashOptionsDef,
|
|
opacity: ratio
|
|
};
|
|
var shapeHighlightOptionsDef = {
|
|
...fillOptionsDef,
|
|
...strokeOptionsDef,
|
|
...lineDashOptionsDef,
|
|
opacity: ratio
|
|
};
|
|
function highlightOptionsDef(itemHighlightOptionsDef) {
|
|
return {
|
|
enabled: boolean,
|
|
range: union("tooltip", "node"),
|
|
highlightedItem: itemHighlightOptionsDef,
|
|
unhighlightedItem: itemHighlightOptionsDef
|
|
};
|
|
}
|
|
function multiSeriesHighlightOptionsDef(itemHighlightOptionsDef, seriesHighlightOptionsDef) {
|
|
return {
|
|
enabled: boolean,
|
|
range: union("tooltip", "node"),
|
|
highlightedItem: itemHighlightOptionsDef,
|
|
unhighlightedItem: itemHighlightOptionsDef,
|
|
highlightedSeries: seriesHighlightOptionsDef,
|
|
unhighlightedSeries: seriesHighlightOptionsDef,
|
|
bringToFront: boolean
|
|
};
|
|
}
|
|
var shapeSegmentOptions = {
|
|
start: defined,
|
|
stop: defined,
|
|
...strokeOptionsDef,
|
|
...fillOptionsDef,
|
|
...lineDashOptionsDef
|
|
};
|
|
var lineSegmentOptions = {
|
|
start: defined,
|
|
stop: defined,
|
|
...strokeOptionsDef,
|
|
...lineDashOptionsDef
|
|
};
|
|
var shapeSegmentation = optionsDefs(
|
|
{
|
|
enabled: boolean,
|
|
key: required(union("x", "y")),
|
|
segments: arrayOfDefs(shapeSegmentOptions, "path segments array")
|
|
},
|
|
"a segmentation object",
|
|
true
|
|
);
|
|
var lineSegmentation = optionsDefs(
|
|
{
|
|
enabled: boolean,
|
|
key: required(union("x", "y")),
|
|
segments: arrayOfDefs(lineSegmentOptions, "path segments array")
|
|
},
|
|
"a segmentation object",
|
|
true
|
|
);
|
|
var googleFont = optionsDefs({ googleFont: string }, "google font");
|
|
var fontFamilyFull = or(string, themeOperator, googleFont, arrayOf(or(string, googleFont)));
|
|
var fontWeight = or(positiveNumber, union("normal", "bold", "bolder", "lighter"));
|
|
var fontOptionsDef = {
|
|
color,
|
|
fontFamily: fontFamilyFull,
|
|
fontSize: positiveNumber,
|
|
fontStyle: union("normal", "italic", "oblique"),
|
|
fontWeight
|
|
};
|
|
var paddingOptions = optionsDefs(
|
|
{ top: number, right: number, bottom: number, left: number },
|
|
"padding object"
|
|
);
|
|
var padding = or(number, paddingOptions);
|
|
var borderOptionsDef = {
|
|
enabled: boolean,
|
|
stroke: color,
|
|
strokeWidth: positiveNumber,
|
|
strokeOpacity: ratio
|
|
};
|
|
var labelBoxOptionsDef = {
|
|
border: borderOptionsDef,
|
|
cornerRadius: number,
|
|
padding,
|
|
...fillOptionsDef
|
|
};
|
|
|
|
// packages/ag-charts-core/src/config/chartDefaults.ts
|
|
var legendPlacementLiterals = [
|
|
"top",
|
|
"top-right",
|
|
"top-left",
|
|
"bottom",
|
|
"bottom-right",
|
|
"bottom-left",
|
|
"right",
|
|
"right-top",
|
|
"right-bottom",
|
|
"left",
|
|
"left-top",
|
|
"left-bottom"
|
|
];
|
|
var legendPositionOptionsDef = {
|
|
floating: boolean,
|
|
placement: union(...legendPlacementLiterals),
|
|
xOffset: number,
|
|
yOffset: number
|
|
};
|
|
var legendPositionValidator = attachDescription(
|
|
(value, context) => {
|
|
let result;
|
|
if (typeof value === "string") {
|
|
const allowedValues = legendPlacementLiterals;
|
|
if (allowedValues.includes(value)) {
|
|
result = true;
|
|
} else {
|
|
result = { valid: false, invalid: [], cleared: null };
|
|
result.invalid.push(
|
|
new ValidationError(
|
|
"invalid" /* Invalid */,
|
|
`a legend placement string: ["${legendPlacementLiterals.join('", "')}"]`,
|
|
value,
|
|
context.path
|
|
)
|
|
);
|
|
}
|
|
} else {
|
|
const { cleared, invalid } = validate(value, legendPositionOptionsDef);
|
|
result = { valid: invalid.length === 0, cleared, invalid };
|
|
}
|
|
return result;
|
|
},
|
|
`a legend position object or placement string`
|
|
);
|
|
var shapeValidator = or(
|
|
union("circle", "cross", "diamond", "heart", "plus", "pin", "square", "star", "triangle"),
|
|
callback
|
|
);
|
|
var textWrapValidator = union("never", "always", "hyphenate", "on-space");
|
|
var tooltipPlacementValidator = union(
|
|
"top",
|
|
"right",
|
|
"bottom",
|
|
"left",
|
|
"top-right",
|
|
"bottom-right",
|
|
"bottom-left",
|
|
"top-left",
|
|
"center"
|
|
);
|
|
var rangeValidator = or(positiveNumber, union("exact", "nearest", "area"));
|
|
var seriesTooltipRangeValidator = or(positiveNumber, union("exact", "nearest"));
|
|
var textOrSegments = or(
|
|
string,
|
|
number,
|
|
date,
|
|
arrayOfDefs(
|
|
{
|
|
text: required(string),
|
|
...fontOptionsDef
|
|
},
|
|
"text segments array"
|
|
)
|
|
);
|
|
var chartCaptionOptionsDefs = {
|
|
enabled: boolean,
|
|
text: textOrSegments,
|
|
textAlign: union("left", "center", "right"),
|
|
wrapping: union("never", "always", "hyphenate", "on-space"),
|
|
spacing: positiveNumber,
|
|
maxWidth: positiveNumber,
|
|
maxHeight: positiveNumber,
|
|
...fontOptionsDef
|
|
};
|
|
chartCaptionOptionsDefs.padding = undocumented(positiveNumber);
|
|
var chartOverlayOptionsDefs = {
|
|
enabled: boolean,
|
|
text: textOrSegments,
|
|
renderer: callbackOf(or(string, htmlElement))
|
|
};
|
|
var contextMenuItemLiterals = [
|
|
"defaults",
|
|
"download",
|
|
"zoom-to-cursor",
|
|
"pan-to-cursor",
|
|
"reset-zoom",
|
|
"toggle-series-visibility",
|
|
"toggle-other-series",
|
|
"separator"
|
|
];
|
|
var contextMenuItemObjectDef = {
|
|
type: union("action", "separator"),
|
|
showOn: union("always", "series-area", "series-node", "legend-item"),
|
|
label: required(string),
|
|
enabled: boolean,
|
|
action: callback,
|
|
items: (value, context) => contextMenuItemsArray(value, context)
|
|
};
|
|
contextMenuItemObjectDef.iconUrl = undocumented(string);
|
|
var contextMenuItemObjectValidator = optionsDefs(contextMenuItemObjectDef);
|
|
var contextMenuItemValidator = attachDescription(
|
|
(value, context) => {
|
|
let result;
|
|
if (typeof value === "string") {
|
|
const allowedValues = contextMenuItemLiterals;
|
|
if (allowedValues.includes(value)) {
|
|
result = true;
|
|
} else {
|
|
result = { valid: false, invalid: [], cleared: null };
|
|
result.invalid.push(
|
|
new ValidationError(
|
|
"invalid" /* Invalid */,
|
|
`a context menu item string alias: ["${contextMenuItemLiterals.join('", "')}"]`,
|
|
value,
|
|
context.path
|
|
)
|
|
);
|
|
}
|
|
} else {
|
|
result = contextMenuItemObjectValidator(value, context);
|
|
}
|
|
return result;
|
|
},
|
|
`a context menu item object or string alias: [${contextMenuItemLiterals.join(", ")}]`
|
|
);
|
|
var contextMenuItemsArray = arrayOf(contextMenuItemValidator, "a menu items array", false);
|
|
var toolbarButtonOptionsDefs = {
|
|
label: string,
|
|
ariaLabel: string,
|
|
tooltip: string,
|
|
icon: union(
|
|
"align-center",
|
|
"align-left",
|
|
"align-right",
|
|
"arrow-drawing",
|
|
"arrow-down-drawing",
|
|
"arrow-up-drawing",
|
|
"callout-annotation",
|
|
"candlestick-series",
|
|
"close",
|
|
"comment-annotation",
|
|
"date-range-drawing",
|
|
"date-price-range-drawing",
|
|
"delete",
|
|
"disjoint-channel-drawing",
|
|
"drag-handle",
|
|
"fill-color",
|
|
"line-style-solid",
|
|
"line-style-dashed",
|
|
"line-style-dotted",
|
|
"high-low-series",
|
|
"hlc-series",
|
|
"hollow-candlestick-series",
|
|
"horizontal-line-drawing",
|
|
"line-color",
|
|
"line-series",
|
|
"line-with-markers-series",
|
|
"locked",
|
|
"measurer-drawing",
|
|
"note-annotation",
|
|
"ohlc-series",
|
|
"pan-end",
|
|
"pan-left",
|
|
"pan-right",
|
|
"pan-start",
|
|
"parallel-channel-drawing",
|
|
"position-bottom",
|
|
"position-center",
|
|
"position-top",
|
|
"price-label-annotation",
|
|
"price-range-drawing",
|
|
"reset",
|
|
"settings",
|
|
"step-line-series",
|
|
"text-annotation",
|
|
"trend-line-drawing",
|
|
"fibonacci-retracement-drawing",
|
|
"fibonacci-retracement-trend-based-drawing",
|
|
"unlocked",
|
|
"vertical-line-drawing",
|
|
"zoom-in",
|
|
"zoom-out"
|
|
)
|
|
};
|
|
var formatter = or(string, callbackOf(textOrSegments));
|
|
var formatObjectValidator = optionsDefs({
|
|
x: formatter,
|
|
y: formatter,
|
|
angle: formatter,
|
|
radius: formatter,
|
|
size: formatter,
|
|
color: formatter,
|
|
label: formatter,
|
|
secondaryLabel: formatter,
|
|
sectorLabel: formatter,
|
|
calloutLabel: formatter,
|
|
legendItem: formatter
|
|
});
|
|
var numberFormatValidator = attachDescription(isValidNumberFormat, "a valid number format string");
|
|
var commonChartOptionsDefs = {
|
|
width: positiveNumber,
|
|
height: positiveNumber,
|
|
minWidth: positiveNumber,
|
|
minHeight: positiveNumber,
|
|
suppressFieldDotNotation: boolean,
|
|
title: chartCaptionOptionsDefs,
|
|
subtitle: chartCaptionOptionsDefs,
|
|
footnote: chartCaptionOptionsDefs,
|
|
padding: {
|
|
top: positiveNumber,
|
|
right: positiveNumber,
|
|
bottom: positiveNumber,
|
|
left: positiveNumber
|
|
},
|
|
seriesArea: {
|
|
border: borderOptionsDef,
|
|
clip: boolean,
|
|
cornerRadius: number,
|
|
padding
|
|
},
|
|
legend: {
|
|
enabled: boolean,
|
|
position: legendPositionValidator,
|
|
orientation: union("horizontal", "vertical"),
|
|
maxWidth: positiveNumber,
|
|
maxHeight: positiveNumber,
|
|
spacing: positiveNumber,
|
|
border: borderOptionsDef,
|
|
cornerRadius: number,
|
|
padding,
|
|
fill: colorUnion,
|
|
fillOpacity: ratio,
|
|
preventHidingAll: boolean,
|
|
reverseOrder: boolean,
|
|
toggleSeries: boolean,
|
|
item: {
|
|
marker: {
|
|
size: positiveNumber,
|
|
shape: shapeValidator,
|
|
padding: positiveNumber,
|
|
strokeWidth: positiveNumber
|
|
},
|
|
line: {
|
|
length: positiveNumber,
|
|
strokeWidth: positiveNumber
|
|
},
|
|
label: {
|
|
maxLength: positiveNumber,
|
|
formatter: callback,
|
|
...fontOptionsDef
|
|
},
|
|
maxWidth: positiveNumber,
|
|
paddingX: positiveNumber,
|
|
paddingY: positiveNumber,
|
|
showSeriesStroke: boolean
|
|
},
|
|
pagination: {
|
|
marker: {
|
|
size: positiveNumber,
|
|
shape: shapeValidator,
|
|
padding: positiveNumber
|
|
},
|
|
activeStyle: {
|
|
...fillOptionsDef,
|
|
...strokeOptionsDef
|
|
},
|
|
inactiveStyle: {
|
|
...fillOptionsDef,
|
|
...strokeOptionsDef
|
|
},
|
|
highlightStyle: {
|
|
...fillOptionsDef,
|
|
...strokeOptionsDef
|
|
},
|
|
label: fontOptionsDef
|
|
},
|
|
listeners: {
|
|
legendItemClick: callback,
|
|
legendItemDoubleClick: callback
|
|
}
|
|
},
|
|
gradientLegend: {
|
|
enabled: boolean,
|
|
position: legendPositionValidator,
|
|
spacing: positiveNumber,
|
|
reverseOrder: boolean,
|
|
border: borderOptionsDef,
|
|
cornerRadius: number,
|
|
padding,
|
|
fill: colorUnion,
|
|
fillOpacity: ratio,
|
|
gradient: {
|
|
preferredLength: positiveNumber,
|
|
thickness: positiveNumber
|
|
},
|
|
scale: {
|
|
label: {
|
|
...fontOptionsDef,
|
|
minSpacing: positiveNumber,
|
|
format: numberFormatValidator,
|
|
formatter: callback
|
|
},
|
|
padding: positiveNumber,
|
|
interval: {
|
|
step: number,
|
|
values: array,
|
|
minSpacing: and(positiveNumber, lessThan("maxSpacing")),
|
|
maxSpacing: and(positiveNumber, greaterThan("minSpacing"))
|
|
}
|
|
}
|
|
},
|
|
listeners: {
|
|
seriesNodeClick: callback,
|
|
seriesNodeDoubleClick: callback,
|
|
seriesVisibilityChange: callback,
|
|
activeChange: callback,
|
|
click: callback,
|
|
doubleClick: callback,
|
|
annotations: callback,
|
|
zoom: callback
|
|
},
|
|
loadGoogleFonts: boolean,
|
|
highlight: {
|
|
drawingMode: union("overlay", "cutout"),
|
|
range: union("tooltip", "node")
|
|
},
|
|
overlays: {
|
|
loading: chartOverlayOptionsDefs,
|
|
noData: chartOverlayOptionsDefs,
|
|
noVisibleSeries: chartOverlayOptionsDefs,
|
|
unsupportedBrowser: chartOverlayOptionsDefs
|
|
},
|
|
tooltip: {
|
|
enabled: boolean,
|
|
showArrow: boolean,
|
|
pagination: boolean,
|
|
delay: positiveNumber,
|
|
range: rangeValidator,
|
|
wrapping: textWrapValidator,
|
|
mode: union("single", "shared", "compact"),
|
|
position: {
|
|
anchorTo: union("pointer", "node", "chart"),
|
|
placement: or(tooltipPlacementValidator, arrayOf(tooltipPlacementValidator)),
|
|
xOffset: number,
|
|
yOffset: number
|
|
}
|
|
},
|
|
animation: defined,
|
|
contextMenu: defined,
|
|
context: () => true,
|
|
dataSource: {
|
|
getData: callback
|
|
},
|
|
keyboard: {
|
|
enabled: boolean,
|
|
tabIndex: number
|
|
},
|
|
touch: {
|
|
dragAction: union("none", "drag", "hover")
|
|
},
|
|
ranges: {
|
|
enabled: boolean,
|
|
buttons: arrayOfDefs(
|
|
{
|
|
...toolbarButtonOptionsDefs,
|
|
value: or(number, and(arrayOf(or(number, date)), arrayLength(2, 2)), callback)
|
|
},
|
|
"range button options array"
|
|
)
|
|
},
|
|
// modules
|
|
locale: {
|
|
localeText: object,
|
|
getLocaleText: callbackOf(string)
|
|
},
|
|
background: {
|
|
visible: boolean,
|
|
fill: color,
|
|
// enterprise
|
|
image: {
|
|
url: required(string),
|
|
top: number,
|
|
right: number,
|
|
bottom: number,
|
|
left: number,
|
|
width: positiveNumber,
|
|
height: positiveNumber,
|
|
opacity: ratio
|
|
}
|
|
},
|
|
styleNonce: string,
|
|
sync: defined,
|
|
zoom: defined,
|
|
scrollbar: defined,
|
|
formatter: or(callbackOf(textOrSegments), formatObjectValidator)
|
|
};
|
|
commonChartOptionsDefs.flashOnUpdate = undocumented(defined);
|
|
commonChartOptionsDefs.dataSource.requestThrottle = undocumented(positiveNumber);
|
|
commonChartOptionsDefs.dataSource.updateThrottle = undocumented(positiveNumber);
|
|
commonChartOptionsDefs.dataSource.updateDuringInteraction = undocumented(boolean);
|
|
commonChartOptionsDefs.statusBar = undocumented(defined);
|
|
commonChartOptionsDefs.foreground = undocumented({
|
|
visible: boolean,
|
|
text: string,
|
|
image: {
|
|
url: string,
|
|
top: number,
|
|
right: number,
|
|
bottom: number,
|
|
left: number,
|
|
width: positiveNumber,
|
|
height: positiveNumber,
|
|
opacity: ratio
|
|
},
|
|
...fillOptionsDef
|
|
});
|
|
commonChartOptionsDefs.overrideDevicePixelRatio = undocumented(number);
|
|
commonChartOptionsDefs.sync.domainMode = undocumented(union("direction", "position", "key"));
|
|
commonChartOptionsDefs.displayNullData = undocumented(boolean);
|
|
var commonSeriesThemeableOptionsDefs = {
|
|
cursor: string,
|
|
context: () => true,
|
|
showInLegend: boolean,
|
|
nodeClickRange: rangeValidator,
|
|
listeners: {
|
|
seriesNodeClick: callback,
|
|
seriesNodeDoubleClick: callback
|
|
},
|
|
highlight: highlightOptionsDef(shapeHighlightOptionsDef)
|
|
};
|
|
commonSeriesThemeableOptionsDefs.allowNullKeys = undocumented(boolean);
|
|
var commonSeriesOptionsDefs = {
|
|
...commonSeriesThemeableOptionsDefs,
|
|
id: string,
|
|
visible: boolean,
|
|
context: () => true,
|
|
data: array
|
|
};
|
|
commonSeriesOptionsDefs.seriesGrouping = undocumented(defined);
|
|
var markerStyleOptionsDefs = {
|
|
shape: shapeValidator,
|
|
size: positiveNumber,
|
|
...fillOptionsDef,
|
|
...strokeOptionsDef,
|
|
...lineDashOptionsDef
|
|
};
|
|
var markerOptionsDefs = {
|
|
enabled: boolean,
|
|
itemStyler: callbackDefs({
|
|
...fillOptionsDef,
|
|
...strokeOptionsDef,
|
|
...lineDashOptionsDef,
|
|
shape: shapeValidator,
|
|
size: positiveNumber
|
|
}),
|
|
...markerStyleOptionsDefs
|
|
};
|
|
var seriesLabelOptionsDefs = {
|
|
enabled: boolean,
|
|
formatter: callbackOf(textOrSegments),
|
|
format: numberFormatValidator,
|
|
itemStyler: callbackDefs({
|
|
enabled: boolean,
|
|
...labelBoxOptionsDef,
|
|
...fontOptionsDef
|
|
}),
|
|
...labelBoxOptionsDef,
|
|
...fontOptionsDef
|
|
};
|
|
var autoSizedLabelOptionsDefs = {
|
|
...seriesLabelOptionsDefs,
|
|
lineHeight: positiveNumber,
|
|
minimumFontSize: positiveNumber,
|
|
wrapping: textWrapValidator,
|
|
overflowStrategy: union("ellipsis", "hide")
|
|
};
|
|
var errorBarThemeableOptionsDefs = {
|
|
visible: boolean,
|
|
cap: {
|
|
visible: boolean,
|
|
length: positiveNumber,
|
|
lengthRatio: ratio,
|
|
...strokeOptionsDef,
|
|
...lineDashOptionsDef
|
|
},
|
|
...strokeOptionsDef,
|
|
...lineDashOptionsDef
|
|
};
|
|
var errorBarOptionsDefs = {
|
|
...errorBarThemeableOptionsDefs,
|
|
xLowerKey: string,
|
|
xUpperKey: string,
|
|
yLowerKey: string,
|
|
yUpperKey: string,
|
|
xLowerName: string,
|
|
xUpperName: string,
|
|
yLowerName: string,
|
|
yUpperName: string,
|
|
itemStyler: callbackDefs({
|
|
visible: boolean,
|
|
...strokeOptionsDef,
|
|
...lineDashOptionsDef,
|
|
cap: {
|
|
visible: boolean,
|
|
length: positiveNumber,
|
|
lengthRatio: ratio,
|
|
...strokeOptionsDef,
|
|
...lineDashOptionsDef
|
|
}
|
|
})
|
|
};
|
|
var tooltipOptionsDefs = {
|
|
enabled: boolean,
|
|
showArrow: boolean,
|
|
range: seriesTooltipRangeValidator,
|
|
renderer: callbackOf(
|
|
or(
|
|
string,
|
|
number,
|
|
date,
|
|
optionsDefs(
|
|
{
|
|
heading: string,
|
|
title: string,
|
|
symbol: {
|
|
marker: {
|
|
enabled: boolean,
|
|
shape: shapeValidator,
|
|
...fillOptionsDef,
|
|
stroke: color,
|
|
strokeOpacity: ratio,
|
|
strokeWidth: positiveNumber,
|
|
...lineDashOptionsDef
|
|
},
|
|
line: {
|
|
enabled: boolean,
|
|
stroke: color,
|
|
strokeWidth: positiveNumber,
|
|
strokeOpacity: ratio,
|
|
...lineDashOptionsDef
|
|
}
|
|
},
|
|
data: arrayOfDefs({
|
|
label: required(string),
|
|
value: required(or(string, number, date))
|
|
})
|
|
},
|
|
"tooltip renderer result object"
|
|
)
|
|
)
|
|
),
|
|
position: {
|
|
anchorTo: union("node", "pointer", "chart"),
|
|
placement: or(tooltipPlacementValidator, arrayOf(tooltipPlacementValidator)),
|
|
xOffset: number,
|
|
yOffset: number
|
|
},
|
|
interaction: {
|
|
enabled: boolean
|
|
}
|
|
};
|
|
var tooltipOptionsDefsWithArea = {
|
|
...tooltipOptionsDefs,
|
|
range: rangeValidator
|
|
};
|
|
var shadowOptionsDefs = {
|
|
enabled: boolean,
|
|
xOffset: number,
|
|
yOffset: number,
|
|
blur: positiveNumber,
|
|
color
|
|
};
|
|
var interpolationOptionsDefs = typeUnion(
|
|
{
|
|
linear: {},
|
|
smooth: {
|
|
tension: ratio
|
|
},
|
|
step: {
|
|
position: union("start", "middle", "end")
|
|
}
|
|
},
|
|
"interpolation line options"
|
|
);
|
|
|
|
// packages/ag-charts-core/src/utils/types/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 target !== void 0 && 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));
|
|
}
|
|
function extractDecoratedProperties(target) {
|
|
return listDecoratedProperties(target).reduce((result, key) => {
|
|
result[String(key)] = target[key] ?? null;
|
|
return result;
|
|
}, {});
|
|
}
|
|
|
|
// packages/ag-charts-core/src/utils/data/iterators.ts
|
|
function* iterate(...items) {
|
|
for (const item of items) {
|
|
if (item == null)
|
|
continue;
|
|
if (item[Symbol.iterator]) {
|
|
yield* item;
|
|
} else {
|
|
yield item;
|
|
}
|
|
}
|
|
}
|
|
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/data/object.ts
|
|
function strictObjectKeys(o) {
|
|
return Object.keys(o);
|
|
}
|
|
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 (isPlainObject(a)) {
|
|
if (!isPlainObject(b))
|
|
return false;
|
|
return objectsEqualWith(a, b, objectsEqual);
|
|
}
|
|
return a === b;
|
|
}
|
|
function objectsEqualWith(a, b, cmp) {
|
|
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 (!cmp(a[key], b[key]))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
function mergeDefaults(...sources) {
|
|
const target = {};
|
|
for (const source of sources) {
|
|
if (!isObject(source))
|
|
continue;
|
|
const keys = isDecoratedObject(source) ? listDecoratedProperties(source) : Object.keys(source);
|
|
for (const key of keys) {
|
|
if (isPlainObject(target[key]) && isPlainObject(source[key])) {
|
|
target[key] = mergeDefaults(target[key], source[key]);
|
|
} else {
|
|
target[key] ?? (target[key] = source[key]);
|
|
}
|
|
}
|
|
}
|
|
return target;
|
|
}
|
|
function merge(...sources) {
|
|
const target = {};
|
|
for (const source of sources) {
|
|
if (!isObject(source))
|
|
continue;
|
|
const keys = isDecoratedObject(source) ? listDecoratedProperties(source) : Object.keys(source);
|
|
for (const key of keys) {
|
|
if (isPlainObject(target[key]) && isPlainObject(source[key])) {
|
|
target[key] = merge(target[key], source[key]);
|
|
} else if (!(key in target)) {
|
|
target[key] ?? (target[key] = source[key]);
|
|
}
|
|
}
|
|
}
|
|
return target;
|
|
}
|
|
function mergeArrayDefaults(dataArray, ...itemDefaults) {
|
|
if (itemDefaults && isArray(dataArray)) {
|
|
return dataArray.map((item) => mergeDefaults(item, ...itemDefaults));
|
|
}
|
|
return dataArray;
|
|
}
|
|
function mapValues(object2, mapper) {
|
|
const result = {};
|
|
for (const [key, value] of entries(object2)) {
|
|
result[key] = mapper(value, key, object2);
|
|
}
|
|
return result;
|
|
}
|
|
function without(object2, keys) {
|
|
const clone2 = { ...object2 };
|
|
for (const key of keys) {
|
|
delete clone2[key];
|
|
}
|
|
return clone2;
|
|
}
|
|
function pick(object2, keys) {
|
|
if (object2 == null)
|
|
return;
|
|
const picked = {};
|
|
for (const key of keys) {
|
|
if (Object.hasOwn(object2, key)) {
|
|
picked[key] = object2[key];
|
|
}
|
|
}
|
|
return picked;
|
|
}
|
|
function every(object2, fn) {
|
|
if (object2 == null)
|
|
return true;
|
|
for (const [key, value] of entries(object2)) {
|
|
if (!fn(key, value))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
function fromPairs(pairs) {
|
|
const object2 = {};
|
|
if (pairs == null)
|
|
return object2;
|
|
for (const [key, value] of pairs) {
|
|
object2[key] = value;
|
|
}
|
|
return object2;
|
|
}
|
|
function getPath(object2, path) {
|
|
const pathArray = isArray(path) ? path : path.split(".");
|
|
return pathArray.reduce((value, pathKey) => value[pathKey], object2);
|
|
}
|
|
var SKIP_JS_BUILTINS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
function setPath(object2, path, newValue) {
|
|
const pathArray = isArray(path) ? path.slice() : path.split(".");
|
|
const lastKey = pathArray.pop();
|
|
if (pathArray.some((p) => SKIP_JS_BUILTINS.has(p)))
|
|
return;
|
|
const lastObject = pathArray.reduce((value, pathKey) => value[pathKey], object2);
|
|
lastObject[lastKey] = newValue;
|
|
return lastObject[lastKey];
|
|
}
|
|
function partialAssign(keysToCopy, target, source) {
|
|
if (source === void 0) {
|
|
return target;
|
|
}
|
|
for (const key of keysToCopy) {
|
|
const value = source[key];
|
|
if (value !== void 0) {
|
|
target[key] = value;
|
|
}
|
|
}
|
|
return target;
|
|
}
|
|
function assignIfNotStrictlyEqual(target, source, keys) {
|
|
const sourceKeys = keys ?? Object.keys(source);
|
|
for (let i = 0, len = sourceKeys.length; i < len; i++) {
|
|
const key = sourceKeys[i];
|
|
const newValue = source[key];
|
|
if (target[key] !== newValue) {
|
|
target[key] = newValue;
|
|
}
|
|
}
|
|
return target;
|
|
}
|
|
function deepFreeze(obj) {
|
|
if (obj == null || typeof obj !== "object" || !isPlainObject(obj)) {
|
|
return obj;
|
|
}
|
|
Object.freeze(obj);
|
|
for (const prop of Object.getOwnPropertyNames(obj)) {
|
|
const value = obj[prop];
|
|
if (value !== null && (typeof value === "object" || typeof value === "function") && !Object.isFrozen(value)) {
|
|
deepFreeze(value);
|
|
}
|
|
}
|
|
return obj;
|
|
}
|
|
function isObjectWithProperty(obj, key) {
|
|
return isPlainObject(obj) && key in obj;
|
|
}
|
|
function isObjectWithStringProperty(obj, key) {
|
|
return isObjectWithProperty(obj, key) && typeof obj[key] === "string";
|
|
}
|
|
|
|
// packages/ag-charts-core/src/config/gaugePreset.ts
|
|
var fillsOptionsDef = {
|
|
fills: and(
|
|
arrayLength(2),
|
|
arrayOf(optionsDefs({ color, stop: number }, "")),
|
|
colorStopsOrderValidator
|
|
),
|
|
fillMode: union("continuous", "discrete")
|
|
};
|
|
var linearGaugeTargetOptionsDef = {
|
|
value: required(number),
|
|
text: string,
|
|
shape: or(
|
|
union("circle", "cross", "diamond", "heart", "plus", "pin", "square", "star", "triangle", "line"),
|
|
callback
|
|
),
|
|
placement: union("before", "after", "middle"),
|
|
spacing: positiveNumber,
|
|
size: positiveNumber,
|
|
rotation: number,
|
|
...fillOptionsDef,
|
|
...strokeOptionsDef,
|
|
...lineDashOptionsDef
|
|
};
|
|
var radialGaugeTargetOptionsDef = {
|
|
value: required(number),
|
|
text: string,
|
|
shape: or(
|
|
union("circle", "cross", "diamond", "heart", "plus", "pin", "square", "star", "triangle", "line"),
|
|
callback
|
|
),
|
|
placement: union("inside", "outside", "middle"),
|
|
spacing: positiveNumber,
|
|
size: positiveNumber,
|
|
rotation: number,
|
|
label: {
|
|
...seriesLabelOptionsDefs,
|
|
spacing: positiveNumber
|
|
},
|
|
...fillOptionsDef,
|
|
...strokeOptionsDef,
|
|
...lineDashOptionsDef
|
|
};
|
|
var linearGaugeSeriesThemeableOptionsDef = {
|
|
...without(commonSeriesThemeableOptionsDefs, ["listeners"]),
|
|
direction: union("horizontal", "vertical"),
|
|
cornerMode: union("container", "item"),
|
|
cornerRadius: positiveNumber,
|
|
thickness: positiveNumber,
|
|
segmentation: {
|
|
enabled: boolean,
|
|
spacing: positiveNumber,
|
|
interval: {
|
|
values: arrayOf(number),
|
|
step: number,
|
|
count: number
|
|
}
|
|
},
|
|
bar: {
|
|
enabled: boolean,
|
|
thickness: positiveNumber,
|
|
thicknessRatio: ratio,
|
|
...fillsOptionsDef,
|
|
...fillOptionsDef,
|
|
...strokeOptionsDef,
|
|
...lineDashOptionsDef
|
|
},
|
|
label: {
|
|
...autoSizedLabelOptionsDefs,
|
|
text: string,
|
|
spacing: positiveNumber,
|
|
avoidCollisions: boolean,
|
|
placement: union(
|
|
"inside-start",
|
|
"outside-start",
|
|
"inside-end",
|
|
"outside-end",
|
|
"inside-center",
|
|
"bar-inside",
|
|
"bar-inside-end",
|
|
"bar-outside-end",
|
|
"bar-end"
|
|
)
|
|
},
|
|
tooltip: tooltipOptionsDefs
|
|
};
|
|
var linearGaugeSeriesOptionsDef = {
|
|
...without(commonSeriesOptionsDefs, ["listeners"]),
|
|
...linearGaugeSeriesThemeableOptionsDef,
|
|
type: required(constant("linear-gauge")),
|
|
value: required(number),
|
|
scale: {
|
|
min: and(number, lessThan("max")),
|
|
max: and(number, greaterThan("min")),
|
|
label: {
|
|
enabled: boolean,
|
|
formatter: callback,
|
|
rotation: number,
|
|
spacing: positiveNumber,
|
|
minSpacing: positiveNumber,
|
|
placement: union("before", "after"),
|
|
avoidCollisions: boolean,
|
|
format: numberFormatValidator,
|
|
...fontOptionsDef
|
|
},
|
|
interval: {
|
|
values: arrayOf(number),
|
|
step: number
|
|
},
|
|
...fillsOptionsDef,
|
|
...fillOptionsDef,
|
|
...strokeOptionsDef,
|
|
...lineDashOptionsDef
|
|
},
|
|
targets: arrayOfDefs(linearGaugeTargetOptionsDef, "target options array")
|
|
};
|
|
linearGaugeSeriesOptionsDef.margin = undocumented(number);
|
|
linearGaugeSeriesOptionsDef.defaultColorRange = undocumented(arrayOf(color));
|
|
linearGaugeSeriesOptionsDef.defaultTarget = undocumented({
|
|
...linearGaugeTargetOptionsDef,
|
|
value: number,
|
|
label: {
|
|
...seriesLabelOptionsDefs,
|
|
spacing: number
|
|
}
|
|
});
|
|
linearGaugeSeriesOptionsDef.defaultScale = undocumented(linearGaugeSeriesOptionsDef.scale);
|
|
linearGaugeSeriesOptionsDef.scale.defaultFill = undocumented(color);
|
|
var radialGaugeSeriesThemeableOptionsDef = {
|
|
...without(commonSeriesThemeableOptionsDefs, ["listeners"]),
|
|
outerRadius: positiveNumber,
|
|
innerRadius: positiveNumber,
|
|
outerRadiusRatio: ratio,
|
|
innerRadiusRatio: ratio,
|
|
startAngle: number,
|
|
endAngle: number,
|
|
spacing: positiveNumber,
|
|
cornerMode: union("container", "item"),
|
|
cornerRadius: positiveNumber,
|
|
scale: {
|
|
min: and(number, lessThan("max")),
|
|
max: and(number, greaterThan("min")),
|
|
label: {
|
|
enabled: boolean,
|
|
formatter: callback,
|
|
rotation: number,
|
|
spacing: positiveNumber,
|
|
minSpacing: positiveNumber,
|
|
avoidCollisions: boolean,
|
|
format: numberFormatValidator,
|
|
...fontOptionsDef
|
|
},
|
|
interval: {
|
|
values: arrayOf(number),
|
|
step: number
|
|
},
|
|
...fillsOptionsDef,
|
|
...fillOptionsDef,
|
|
...strokeOptionsDef,
|
|
...lineDashOptionsDef
|
|
},
|
|
segmentation: {
|
|
enabled: boolean,
|
|
spacing: positiveNumber,
|
|
interval: {
|
|
values: arrayOf(number),
|
|
step: number,
|
|
count: number
|
|
}
|
|
},
|
|
bar: {
|
|
enabled: boolean,
|
|
...fillsOptionsDef,
|
|
...fillOptionsDef,
|
|
...strokeOptionsDef,
|
|
...lineDashOptionsDef
|
|
},
|
|
needle: {
|
|
enabled: boolean,
|
|
spacing: positiveNumber,
|
|
radiusRatio: ratio,
|
|
...fillOptionsDef,
|
|
...strokeOptionsDef,
|
|
...lineDashOptionsDef
|
|
},
|
|
label: {
|
|
text: string,
|
|
spacing: positiveNumber,
|
|
...autoSizedLabelOptionsDefs
|
|
},
|
|
secondaryLabel: {
|
|
text: string,
|
|
...autoSizedLabelOptionsDefs
|
|
},
|
|
tooltip: tooltipOptionsDefs
|
|
};
|
|
var radialGaugeSeriesOptionsDef = {
|
|
...without(commonSeriesOptionsDefs, ["listeners"]),
|
|
...radialGaugeSeriesThemeableOptionsDef,
|
|
type: required(constant("radial-gauge")),
|
|
value: required(number),
|
|
targets: arrayOfDefs(radialGaugeTargetOptionsDef, "target options array")
|
|
};
|
|
radialGaugeSeriesOptionsDef.defaultColorRange = undocumented(arrayOf(color));
|
|
radialGaugeSeriesOptionsDef.defaultTarget = undocumented({
|
|
...radialGaugeTargetOptionsDef,
|
|
value: number,
|
|
label: {
|
|
...seriesLabelOptionsDefs,
|
|
spacing: number
|
|
}
|
|
});
|
|
radialGaugeSeriesOptionsDef.scale.defaultFill = undocumented(color);
|
|
|
|
// packages/ag-charts-core/src/types/themeConstants.ts
|
|
var FONT_SIZE = /* @__PURE__ */ ((FONT_SIZE2) => {
|
|
FONT_SIZE2[FONT_SIZE2["SMALLEST"] = 8] = "SMALLEST";
|
|
FONT_SIZE2[FONT_SIZE2["SMALLER"] = 10] = "SMALLER";
|
|
FONT_SIZE2[FONT_SIZE2["SMALL"] = 12] = "SMALL";
|
|
FONT_SIZE2[FONT_SIZE2["MEDIUM"] = 13] = "MEDIUM";
|
|
FONT_SIZE2[FONT_SIZE2["LARGE"] = 14] = "LARGE";
|
|
FONT_SIZE2[FONT_SIZE2["LARGEST"] = 17] = "LARGEST";
|
|
return FONT_SIZE2;
|
|
})(FONT_SIZE || {});
|
|
var BASE_FONT_SIZE = 12 /* SMALL */;
|
|
var FONT_SIZE_RATIO = {
|
|
SMALLEST: 8 /* SMALLEST */ / BASE_FONT_SIZE,
|
|
SMALLER: 10 /* SMALLER */ / BASE_FONT_SIZE,
|
|
SMALL: 12 /* SMALL */ / BASE_FONT_SIZE,
|
|
MEDIUM: 13 /* MEDIUM */ / BASE_FONT_SIZE,
|
|
LARGE: 14 /* LARGE */ / BASE_FONT_SIZE,
|
|
LARGEST: 17 /* LARGEST */ / BASE_FONT_SIZE
|
|
};
|
|
var CARTESIAN_POSITION = /* @__PURE__ */ ((CARTESIAN_POSITION2) => {
|
|
CARTESIAN_POSITION2["TOP"] = "top";
|
|
CARTESIAN_POSITION2["TOP_RIGHT"] = "top-right";
|
|
CARTESIAN_POSITION2["TOP_LEFT"] = "top-left";
|
|
CARTESIAN_POSITION2["RIGHT"] = "right";
|
|
CARTESIAN_POSITION2["RIGHT_TOP"] = "right-top";
|
|
CARTESIAN_POSITION2["RIGHT_BOTTOM"] = "right-bottom";
|
|
CARTESIAN_POSITION2["BOTTOM"] = "bottom";
|
|
CARTESIAN_POSITION2["BOTTOM_RIGHT"] = "bottom-right";
|
|
CARTESIAN_POSITION2["BOTTOM_LEFT"] = "bottom-left";
|
|
CARTESIAN_POSITION2["LEFT"] = "left";
|
|
CARTESIAN_POSITION2["LEFT_TOP"] = "left-top";
|
|
CARTESIAN_POSITION2["LEFT_BOTTOM"] = "left-bottom";
|
|
return CARTESIAN_POSITION2;
|
|
})(CARTESIAN_POSITION || {});
|
|
var CARTESIAN_AXIS_TYPE = /* @__PURE__ */ ((CARTESIAN_AXIS_TYPE2) => {
|
|
CARTESIAN_AXIS_TYPE2["CATEGORY"] = "category";
|
|
CARTESIAN_AXIS_TYPE2["GROUPED_CATEGORY"] = "grouped-category";
|
|
CARTESIAN_AXIS_TYPE2["ORDINAL_TIME"] = "ordinal-time";
|
|
CARTESIAN_AXIS_TYPE2["UNIT_TIME"] = "unit-time";
|
|
CARTESIAN_AXIS_TYPE2["TIME"] = "time";
|
|
CARTESIAN_AXIS_TYPE2["NUMBER"] = "number";
|
|
CARTESIAN_AXIS_TYPE2["LOG"] = "log";
|
|
return CARTESIAN_AXIS_TYPE2;
|
|
})(CARTESIAN_AXIS_TYPE || {});
|
|
var POLAR_AXIS_TYPE = /* @__PURE__ */ ((POLAR_AXIS_TYPE2) => {
|
|
POLAR_AXIS_TYPE2["ANGLE_CATEGORY"] = "angle-category";
|
|
POLAR_AXIS_TYPE2["ANGLE_NUMBER"] = "angle-number";
|
|
POLAR_AXIS_TYPE2["RADIUS_CATEGORY"] = "radius-category";
|
|
POLAR_AXIS_TYPE2["RADIUS_NUMBER"] = "radius-number";
|
|
return POLAR_AXIS_TYPE2;
|
|
})(POLAR_AXIS_TYPE || {});
|
|
var POLAR_AXIS_SHAPE = /* @__PURE__ */ ((POLAR_AXIS_SHAPE2) => {
|
|
POLAR_AXIS_SHAPE2["CIRCLE"] = "circle";
|
|
POLAR_AXIS_SHAPE2["POLYGON"] = "polygon";
|
|
return POLAR_AXIS_SHAPE2;
|
|
})(POLAR_AXIS_SHAPE || {});
|
|
|
|
// packages/ag-charts-core/src/utils/format/color.ts
|
|
var lerp = (x, y, t) => x * (1 - t) + y * t;
|
|
var srgbToLinear = (value) => {
|
|
const sign = value < 0 ? -1 : 1;
|
|
const abs = Math.abs(value);
|
|
if (abs <= 0.04045)
|
|
return value / 12.92;
|
|
return sign * ((abs + 0.055) / 1.055) ** 2.4;
|
|
};
|
|
var srgbFromLinear = (value) => {
|
|
const sign = value < 0 ? -1 : 1;
|
|
const abs = Math.abs(value);
|
|
if (abs > 31308e-7) {
|
|
return sign * (1.055 * abs ** (1 / 2.4) - 0.055);
|
|
}
|
|
return 12.92 * value;
|
|
};
|
|
var _Color = class _Color {
|
|
/**
|
|
* Every color component should be in the [0, 1] range.
|
|
* Some easing functions (such as elastic easing) can overshoot the target value by some amount.
|
|
* So, when animating colors, if the source or target color components are already near
|
|
* or at the edge of the allowed [0, 1] range, it is possible for the intermediate color
|
|
* component value to end up outside of that range mid-animation. For this reason the constructor
|
|
* performs range checking/constraining.
|
|
* @param r Red component.
|
|
* @param g Green component.
|
|
* @param b Blue component.
|
|
* @param a Alpha (opacity) component.
|
|
*/
|
|
constructor(r, g, b, a = 1) {
|
|
this.r = clamp(0, r || 0, 1);
|
|
this.g = clamp(0, g || 0, 1);
|
|
this.b = clamp(0, b || 0, 1);
|
|
this.a = clamp(0, a || 0, 1);
|
|
}
|
|
/**
|
|
* A color string can be in one of the following formats to be valid:
|
|
* - #rgb
|
|
* - #rrggbb
|
|
* - rgb(r, g, b)
|
|
* - rgba(r, g, b, a)
|
|
* - CSS color name such as 'white', 'orange', 'cyan', etc.
|
|
*/
|
|
static validColorString(str) {
|
|
if (str.includes("#")) {
|
|
return !!_Color.parseHex(str);
|
|
}
|
|
if (str.includes("rgb")) {
|
|
return !!_Color.stringToRgba(str);
|
|
}
|
|
return _Color.nameToHex.has(str.toLowerCase());
|
|
}
|
|
/**
|
|
* The given string can be in one of the following formats:
|
|
* - #rgb
|
|
* - #rrggbb
|
|
* - rgb(r, g, b)
|
|
* - rgba(r, g, b, a)
|
|
* - CSS color name such as 'white', 'orange', 'cyan', etc.
|
|
* @param str
|
|
*/
|
|
static fromString(str) {
|
|
if (str.includes("#")) {
|
|
return _Color.fromHexString(str);
|
|
}
|
|
const hex = _Color.nameToHex.get(str.toLowerCase());
|
|
if (hex) {
|
|
return _Color.fromHexString(hex);
|
|
}
|
|
if (str.includes("rgb")) {
|
|
return _Color.fromRgbaString(str);
|
|
}
|
|
throw new Error(`Invalid color string: '${str}'`);
|
|
}
|
|
// See https://drafts.csswg.org/css-color/#hex-notation
|
|
static parseHex(input) {
|
|
input = input.replaceAll(" ", "").slice(1);
|
|
let parts;
|
|
switch (input.length) {
|
|
case 6:
|
|
case 8:
|
|
parts = [];
|
|
for (let i = 0; i < input.length; i += 2) {
|
|
parts.push(Number.parseInt(`${input[i]}${input[i + 1]}`, 16));
|
|
}
|
|
break;
|
|
case 3:
|
|
case 4:
|
|
parts = input.split("").map((p) => Number.parseInt(p, 16)).map((p) => p + p * 16);
|
|
break;
|
|
}
|
|
if (parts?.length >= 3 && parts.every((p) => p >= 0)) {
|
|
if (parts.length === 3) {
|
|
parts.push(255);
|
|
}
|
|
return parts;
|
|
}
|
|
}
|
|
static fromHexString(str) {
|
|
const values = _Color.parseHex(str);
|
|
if (values) {
|
|
const [r, g, b, a] = values;
|
|
return new _Color(r / 255, g / 255, b / 255, a / 255);
|
|
}
|
|
throw new Error(`Malformed hexadecimal color string: '${str}'`);
|
|
}
|
|
static stringToRgba(str) {
|
|
let po = -1;
|
|
let pc = -1;
|
|
for (let i = 0; i < str.length; i++) {
|
|
const c = str[i];
|
|
if (po === -1 && c === "(") {
|
|
po = i;
|
|
} else if (c === ")") {
|
|
pc = i;
|
|
break;
|
|
}
|
|
}
|
|
if (po === -1 || pc === -1)
|
|
return;
|
|
const contents = str.substring(po + 1, pc);
|
|
const parts = contents.split(",");
|
|
const rgba = [];
|
|
for (let i = 0; i < parts.length; i++) {
|
|
const part = parts[i];
|
|
let value = Number.parseFloat(part);
|
|
if (!Number.isFinite(value)) {
|
|
return;
|
|
}
|
|
if (part.includes("%")) {
|
|
value = clamp(0, value, 100);
|
|
value /= 100;
|
|
} else if (i === 3) {
|
|
value = clamp(0, value, 1);
|
|
} else {
|
|
value = clamp(0, value, 255);
|
|
value /= 255;
|
|
}
|
|
rgba.push(value);
|
|
}
|
|
return rgba;
|
|
}
|
|
static fromRgbaString(str) {
|
|
const rgba = _Color.stringToRgba(str);
|
|
if (rgba) {
|
|
if (rgba.length === 3) {
|
|
return new _Color(rgba[0], rgba[1], rgba[2]);
|
|
} else if (rgba.length === 4) {
|
|
return new _Color(rgba[0], rgba[1], rgba[2], rgba[3]);
|
|
}
|
|
}
|
|
throw new Error(`Malformed rgb/rgba color string: '${str}'`);
|
|
}
|
|
static fromArray(arr) {
|
|
if (arr.length === 4) {
|
|
return new _Color(arr[0], arr[1], arr[2], arr[3]);
|
|
}
|
|
if (arr.length === 3) {
|
|
return new _Color(arr[0], arr[1], arr[2]);
|
|
}
|
|
throw new Error("The given array should contain 3 or 4 color components (numbers).");
|
|
}
|
|
static fromHSB(h, s, b, alpha = 1) {
|
|
const rgb = _Color.HSBtoRGB(h, s, b);
|
|
return new _Color(rgb[0], rgb[1], rgb[2], alpha);
|
|
}
|
|
static fromHSL(h, s, l, alpha = 1) {
|
|
const rgb = _Color.HSLtoRGB(h, s, l);
|
|
return new _Color(rgb[0], rgb[1], rgb[2], alpha);
|
|
}
|
|
static fromOKLCH(l, c, h, alpha = 1) {
|
|
const rgb = _Color.OKLCHtoRGB(l, c, h);
|
|
return new _Color(rgb[0], rgb[1], rgb[2], alpha);
|
|
}
|
|
static padHex(str) {
|
|
return str.length === 1 ? "0" + str : str;
|
|
}
|
|
toHexString() {
|
|
let hex = "#" + _Color.padHex(Math.round(this.r * 255).toString(16)) + _Color.padHex(Math.round(this.g * 255).toString(16)) + _Color.padHex(Math.round(this.b * 255).toString(16));
|
|
if (this.a < 1) {
|
|
hex += _Color.padHex(Math.round(this.a * 255).toString(16));
|
|
}
|
|
return hex;
|
|
}
|
|
toRgbaString(fractionDigits = 3) {
|
|
const components = [Math.round(this.r * 255), Math.round(this.g * 255), Math.round(this.b * 255)];
|
|
const k = Math.pow(10, fractionDigits);
|
|
if (this.a !== 1) {
|
|
components.push(Math.round(this.a * k) / k);
|
|
return `rgba(${components.join(", ")})`;
|
|
}
|
|
return `rgb(${components.join(", ")})`;
|
|
}
|
|
toString() {
|
|
if (this.a === 1) {
|
|
return this.toHexString();
|
|
}
|
|
return this.toRgbaString();
|
|
}
|
|
toHSB() {
|
|
return _Color.RGBtoHSB(this.r, this.g, this.b);
|
|
}
|
|
static RGBtoOKLCH(r, g, b) {
|
|
const LSRGB0 = srgbToLinear(r);
|
|
const LSRGB1 = srgbToLinear(g);
|
|
const LSRGB2 = srgbToLinear(b);
|
|
const LMS0 = Math.cbrt(0.4122214708 * LSRGB0 + 0.5363325363 * LSRGB1 + 0.0514459929 * LSRGB2);
|
|
const LMS1 = Math.cbrt(0.2119034982 * LSRGB0 + 0.6806995451 * LSRGB1 + 0.1073969566 * LSRGB2);
|
|
const LMS2 = Math.cbrt(0.0883024619 * LSRGB0 + 0.2817188376 * LSRGB1 + 0.6299787005 * LSRGB2);
|
|
const OKLAB0 = 0.2104542553 * LMS0 + 0.793617785 * LMS1 - 0.0040720468 * LMS2;
|
|
const OKLAB1 = 1.9779984951 * LMS0 - 2.428592205 * LMS1 + 0.4505937099 * LMS2;
|
|
const OKLAB2 = 0.0259040371 * LMS0 + 0.7827717662 * LMS1 - 0.808675766 * LMS2;
|
|
const hue = Math.atan2(OKLAB2, OKLAB1) * 180 / Math.PI;
|
|
const OKLCH0 = OKLAB0;
|
|
const OKLCH1 = Math.hypot(OKLAB1, OKLAB2);
|
|
const OKLCH2 = hue >= 0 ? hue : hue + 360;
|
|
return [OKLCH0, OKLCH1, OKLCH2];
|
|
}
|
|
static OKLCHtoRGB(l, c, h) {
|
|
const OKLAB0 = l;
|
|
const OKLAB1 = c * Math.cos(h * Math.PI / 180);
|
|
const OKLAB2 = c * Math.sin(h * Math.PI / 180);
|
|
const LMS0 = (OKLAB0 + 0.3963377774 * OKLAB1 + 0.2158037573 * OKLAB2) ** 3;
|
|
const LMS1 = (OKLAB0 - 0.1055613458 * OKLAB1 - 0.0638541728 * OKLAB2) ** 3;
|
|
const LMS2 = (OKLAB0 - 0.0894841775 * OKLAB1 - 1.291485548 * OKLAB2) ** 3;
|
|
const LSRGB0 = 4.0767416621 * LMS0 - 3.3077115913 * LMS1 + 0.2309699292 * LMS2;
|
|
const LSRGB1 = -1.2684380046 * LMS0 + 2.6097574011 * LMS1 - 0.3413193965 * LMS2;
|
|
const LSRGB2 = -0.0041960863 * LMS0 - 0.7034186147 * LMS1 + 1.707614701 * LMS2;
|
|
const SRGB0 = srgbFromLinear(LSRGB0);
|
|
const SRGB1 = srgbFromLinear(LSRGB1);
|
|
const SRGB2 = srgbFromLinear(LSRGB2);
|
|
return [SRGB0, SRGB1, SRGB2];
|
|
}
|
|
static RGBtoHSL(r, g, b) {
|
|
const min = Math.min(r, g, b);
|
|
const max = Math.max(r, g, b);
|
|
const l = (max + min) / 2;
|
|
let h;
|
|
let s;
|
|
if (max === min) {
|
|
h = 0;
|
|
s = 0;
|
|
} else {
|
|
const delta = max - min;
|
|
s = l > 0.5 ? delta / (2 - max - min) : delta / (max + min);
|
|
if (max === r) {
|
|
h = (g - b) / delta + (g < b ? 6 : 0);
|
|
} else if (max === g) {
|
|
h = (b - r) / delta + 2;
|
|
} else {
|
|
h = (r - g) / delta + 4;
|
|
}
|
|
h *= 360 / 6;
|
|
}
|
|
return [h, s, l];
|
|
}
|
|
static HSLtoRGB(h, s, l) {
|
|
h = (h % 360 + 360) % 360;
|
|
if (s === 0) {
|
|
return [l, l, l];
|
|
}
|
|
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
|
const p = 2 * l - q;
|
|
function hueToRgb(t) {
|
|
if (t < 0)
|
|
t += 1;
|
|
if (t > 1)
|
|
t -= 1;
|
|
if (t < 1 / 6)
|
|
return p + (q - p) * 6 * t;
|
|
if (t < 1 / 2)
|
|
return q;
|
|
if (t < 2 / 3)
|
|
return p + (q - p) * (2 / 3 - t) * 6;
|
|
return p;
|
|
}
|
|
const r = hueToRgb(h / 360 + 1 / 3);
|
|
const g = hueToRgb(h / 360);
|
|
const b = hueToRgb(h / 360 - 1 / 3);
|
|
return [r, g, b];
|
|
}
|
|
/**
|
|
* Converts the given RGB triple to an array of HSB (HSV) components.
|
|
*/
|
|
static RGBtoHSB(r, g, b) {
|
|
const min = Math.min(r, g, b);
|
|
const max = Math.max(r, g, b);
|
|
const S = max === 0 ? 0 : (max - min) / max;
|
|
let H = 0;
|
|
if (min !== max) {
|
|
const delta = max - min;
|
|
const rc = (max - r) / delta;
|
|
const gc = (max - g) / delta;
|
|
const bc = (max - b) / delta;
|
|
if (r === max) {
|
|
H = bc - gc;
|
|
} else if (g === max) {
|
|
H = 2 + rc - bc;
|
|
} else {
|
|
H = 4 + gc - rc;
|
|
}
|
|
H /= 6;
|
|
if (H < 0) {
|
|
H = H + 1;
|
|
}
|
|
}
|
|
return [H * 360, S, max];
|
|
}
|
|
/**
|
|
* Converts the given HSB (HSV) triple to an array of RGB components.
|
|
*/
|
|
static HSBtoRGB(H, S, B) {
|
|
H = (H % 360 + 360) % 360 / 360;
|
|
let r = 0;
|
|
let g = 0;
|
|
let b = 0;
|
|
if (S === 0) {
|
|
r = g = b = B;
|
|
} else {
|
|
const h = (H - Math.floor(H)) * 6;
|
|
const f = h - Math.floor(h);
|
|
const p = B * (1 - S);
|
|
const q = B * (1 - S * f);
|
|
const t = B * (1 - S * (1 - f));
|
|
switch (Math.trunc(h)) {
|
|
case 0:
|
|
r = B;
|
|
g = t;
|
|
b = p;
|
|
break;
|
|
case 1:
|
|
r = q;
|
|
g = B;
|
|
b = p;
|
|
break;
|
|
case 2:
|
|
r = p;
|
|
g = B;
|
|
b = t;
|
|
break;
|
|
case 3:
|
|
r = p;
|
|
g = q;
|
|
b = B;
|
|
break;
|
|
case 4:
|
|
r = t;
|
|
g = p;
|
|
b = B;
|
|
break;
|
|
case 5:
|
|
r = B;
|
|
g = p;
|
|
b = q;
|
|
break;
|
|
}
|
|
}
|
|
return [r, g, b];
|
|
}
|
|
static mix(c0, c1, t) {
|
|
return new _Color(lerp(c0.r, c1.r, t), lerp(c0.g, c1.g, t), lerp(c0.b, c1.b, t), lerp(c0.a, c1.a, t));
|
|
}
|
|
static lighten(c, t) {
|
|
const oklch = _Color.RGBtoOKLCH(c.r, c.g, c.b);
|
|
return _Color.fromOKLCH(clamp(0, oklch[0] + t, 1), oklch[1], oklch[2]);
|
|
}
|
|
static darken(c, t) {
|
|
const oklch = _Color.RGBtoOKLCH(c.r, c.g, c.b);
|
|
return _Color.fromOKLCH(clamp(0, oklch[0] - t, 1), oklch[1], oklch[2]);
|
|
}
|
|
static interpolate(colors, count) {
|
|
const step = 1 / (colors.length - 1);
|
|
const oklchColors = colors.map((c) => _Color.RGBtoOKLCH(c.r, c.g, c.b));
|
|
return Array.from({ length: count }, (_, i) => {
|
|
const t = i / (count - 1);
|
|
const index = colors.length <= 2 ? 0 : Math.min(Math.floor(t * (colors.length - 1)), colors.length - 2);
|
|
const q = (t - index * step) / step;
|
|
const c0 = oklchColors[index];
|
|
const c1 = oklchColors[index + 1];
|
|
return _Color.fromOKLCH(lerp(c0[0], c1[0], q), lerp(c0[1], c1[1], q), lerp(c0[2], c1[2], q));
|
|
});
|
|
}
|
|
};
|
|
/**
|
|
* CSS Color Module Level 4:
|
|
* https://drafts.csswg.org/css-color/#named-colors
|
|
*/
|
|
_Color.nameToHex = /* @__PURE__ */ new Map([
|
|
["aliceblue", "#F0F8FF"],
|
|
["antiquewhite", "#FAEBD7"],
|
|
["aqua", "#00FFFF"],
|
|
["aquamarine", "#7FFFD4"],
|
|
["azure", "#F0FFFF"],
|
|
["beige", "#F5F5DC"],
|
|
["bisque", "#FFE4C4"],
|
|
["black", "#000000"],
|
|
["blanchedalmond", "#FFEBCD"],
|
|
["blue", "#0000FF"],
|
|
["blueviolet", "#8A2BE2"],
|
|
["brown", "#A52A2A"],
|
|
["burlywood", "#DEB887"],
|
|
["cadetblue", "#5F9EA0"],
|
|
["chartreuse", "#7FFF00"],
|
|
["chocolate", "#D2691E"],
|
|
["coral", "#FF7F50"],
|
|
["cornflowerblue", "#6495ED"],
|
|
["cornsilk", "#FFF8DC"],
|
|
["crimson", "#DC143C"],
|
|
["cyan", "#00FFFF"],
|
|
["darkblue", "#00008B"],
|
|
["darkcyan", "#008B8B"],
|
|
["darkgoldenrod", "#B8860B"],
|
|
["darkgray", "#A9A9A9"],
|
|
["darkgreen", "#006400"],
|
|
["darkgrey", "#A9A9A9"],
|
|
["darkkhaki", "#BDB76B"],
|
|
["darkmagenta", "#8B008B"],
|
|
["darkolivegreen", "#556B2F"],
|
|
["darkorange", "#FF8C00"],
|
|
["darkorchid", "#9932CC"],
|
|
["darkred", "#8B0000"],
|
|
["darksalmon", "#E9967A"],
|
|
["darkseagreen", "#8FBC8F"],
|
|
["darkslateblue", "#483D8B"],
|
|
["darkslategray", "#2F4F4F"],
|
|
["darkslategrey", "#2F4F4F"],
|
|
["darkturquoise", "#00CED1"],
|
|
["darkviolet", "#9400D3"],
|
|
["deeppink", "#FF1493"],
|
|
["deepskyblue", "#00BFFF"],
|
|
["dimgray", "#696969"],
|
|
["dimgrey", "#696969"],
|
|
["dodgerblue", "#1E90FF"],
|
|
["firebrick", "#B22222"],
|
|
["floralwhite", "#FFFAF0"],
|
|
["forestgreen", "#228B22"],
|
|
["fuchsia", "#FF00FF"],
|
|
["gainsboro", "#DCDCDC"],
|
|
["ghostwhite", "#F8F8FF"],
|
|
["gold", "#FFD700"],
|
|
["goldenrod", "#DAA520"],
|
|
["gray", "#808080"],
|
|
["green", "#008000"],
|
|
["greenyellow", "#ADFF2F"],
|
|
["grey", "#808080"],
|
|
["honeydew", "#F0FFF0"],
|
|
["hotpink", "#FF69B4"],
|
|
["indianred", "#CD5C5C"],
|
|
["indigo", "#4B0082"],
|
|
["ivory", "#FFFFF0"],
|
|
["khaki", "#F0E68C"],
|
|
["lavender", "#E6E6FA"],
|
|
["lavenderblush", "#FFF0F5"],
|
|
["lawngreen", "#7CFC00"],
|
|
["lemonchiffon", "#FFFACD"],
|
|
["lightblue", "#ADD8E6"],
|
|
["lightcoral", "#F08080"],
|
|
["lightcyan", "#E0FFFF"],
|
|
["lightgoldenrodyellow", "#FAFAD2"],
|
|
["lightgray", "#D3D3D3"],
|
|
["lightgreen", "#90EE90"],
|
|
["lightgrey", "#D3D3D3"],
|
|
["lightpink", "#FFB6C1"],
|
|
["lightsalmon", "#FFA07A"],
|
|
["lightseagreen", "#20B2AA"],
|
|
["lightskyblue", "#87CEFA"],
|
|
["lightslategray", "#778899"],
|
|
["lightslategrey", "#778899"],
|
|
["lightsteelblue", "#B0C4DE"],
|
|
["lightyellow", "#FFFFE0"],
|
|
["lime", "#00FF00"],
|
|
["limegreen", "#32CD32"],
|
|
["linen", "#FAF0E6"],
|
|
["magenta", "#FF00FF"],
|
|
["maroon", "#800000"],
|
|
["mediumaquamarine", "#66CDAA"],
|
|
["mediumblue", "#0000CD"],
|
|
["mediumorchid", "#BA55D3"],
|
|
["mediumpurple", "#9370DB"],
|
|
["mediumseagreen", "#3CB371"],
|
|
["mediumslateblue", "#7B68EE"],
|
|
["mediumspringgreen", "#00FA9A"],
|
|
["mediumturquoise", "#48D1CC"],
|
|
["mediumvioletred", "#C71585"],
|
|
["midnightblue", "#191970"],
|
|
["mintcream", "#F5FFFA"],
|
|
["mistyrose", "#FFE4E1"],
|
|
["moccasin", "#FFE4B5"],
|
|
["navajowhite", "#FFDEAD"],
|
|
["navy", "#000080"],
|
|
["oldlace", "#FDF5E6"],
|
|
["olive", "#808000"],
|
|
["olivedrab", "#6B8E23"],
|
|
["orange", "#FFA500"],
|
|
["orangered", "#FF4500"],
|
|
["orchid", "#DA70D6"],
|
|
["palegoldenrod", "#EEE8AA"],
|
|
["palegreen", "#98FB98"],
|
|
["paleturquoise", "#AFEEEE"],
|
|
["palevioletred", "#DB7093"],
|
|
["papayawhip", "#FFEFD5"],
|
|
["peachpuff", "#FFDAB9"],
|
|
["peru", "#CD853F"],
|
|
["pink", "#FFC0CB"],
|
|
["plum", "#DDA0DD"],
|
|
["powderblue", "#B0E0E6"],
|
|
["purple", "#800080"],
|
|
["rebeccapurple", "#663399"],
|
|
["red", "#FF0000"],
|
|
["rosybrown", "#BC8F8F"],
|
|
["royalblue", "#4169E1"],
|
|
["saddlebrown", "#8B4513"],
|
|
["salmon", "#FA8072"],
|
|
["sandybrown", "#F4A460"],
|
|
["seagreen", "#2E8B57"],
|
|
["seashell", "#FFF5EE"],
|
|
["sienna", "#A0522D"],
|
|
["silver", "#C0C0C0"],
|
|
["skyblue", "#87CEEB"],
|
|
["slateblue", "#6A5ACD"],
|
|
["slategray", "#708090"],
|
|
["slategrey", "#708090"],
|
|
["snow", "#FFFAFA"],
|
|
["springgreen", "#00FF7F"],
|
|
["steelblue", "#4682B4"],
|
|
["tan", "#D2B48C"],
|
|
["teal", "#008080"],
|
|
["thistle", "#D8BFD8"],
|
|
["tomato", "#FF6347"],
|
|
["transparent", "#00000000"],
|
|
["turquoise", "#40E0D0"],
|
|
["violet", "#EE82EE"],
|
|
["wheat", "#F5DEB3"],
|
|
["white", "#FFFFFF"],
|
|
["whitesmoke", "#F5F5F5"],
|
|
["yellow", "#FFFF00"],
|
|
["yellowgreen", "#9ACD32"]
|
|
]);
|
|
var Color = _Color;
|
|
|
|
// packages/ag-charts-core/src/config/themeUtil.ts
|
|
var DIRECTION_SWAP_AXES = {
|
|
x: {
|
|
position: "bottom" /* BOTTOM */,
|
|
type: {
|
|
$if: [
|
|
{ $eq: [{ $path: ["/series/0/direction", void 0] }, "horizontal"] },
|
|
"number" /* NUMBER */,
|
|
"category" /* CATEGORY */
|
|
]
|
|
}
|
|
},
|
|
y: {
|
|
position: "left" /* LEFT */,
|
|
type: {
|
|
$if: [
|
|
{ $eq: [{ $path: ["/series/0/direction", void 0] }, "horizontal"] },
|
|
"category" /* CATEGORY */,
|
|
"number" /* NUMBER */
|
|
]
|
|
}
|
|
}
|
|
};
|
|
var SAFE_FILL_OPERATION = {
|
|
$if: [
|
|
{
|
|
$or: [
|
|
{ $isGradient: { $palette: "fill" } },
|
|
{ $isPattern: { $palette: "fill" } },
|
|
{ $isImage: { $value: "$1" } }
|
|
]
|
|
},
|
|
{ $palette: "fillFallback" },
|
|
{ $palette: "fill" }
|
|
]
|
|
};
|
|
var SAFE_FILLS_OPERATION = {
|
|
$if: [
|
|
{
|
|
$or: [
|
|
{ $isGradient: { $palette: "fill" } },
|
|
{ $isPattern: { $palette: "fill" } },
|
|
{ $isImage: { $value: "$1" } }
|
|
]
|
|
},
|
|
{ $palette: "fillsFallback" },
|
|
{ $palette: "fills" }
|
|
]
|
|
};
|
|
var SAFE_STROKE_FILL_OPERATION = {
|
|
$if: [
|
|
{ $isGradient: { $palette: "fill" } },
|
|
{ $palette: "fillFallback" },
|
|
{
|
|
$if: [
|
|
{ $isPattern: { $palette: "fill" } },
|
|
{ $path: ["/stroke", { $palette: "fillFallback" }, { $palette: "fill" }] },
|
|
{ $palette: "fill" }
|
|
]
|
|
}
|
|
]
|
|
};
|
|
var SAFE_RANGE2_OPERATION = {
|
|
$if: [
|
|
{
|
|
$or: [
|
|
{ $isGradient: { $palette: "fill" } },
|
|
{ $isPattern: { $palette: "fill" } },
|
|
{ $isImage: { $value: "$1" } }
|
|
]
|
|
},
|
|
[{ $palette: "fillFallback" }, { $palette: "fillFallback" }],
|
|
{ $palette: "range2" }
|
|
]
|
|
};
|
|
var FILL_GRADIENT_BLANK_DEFAULTS = {
|
|
type: "gradient",
|
|
gradient: "linear",
|
|
bounds: "item",
|
|
colorStops: [{ color: "black" }],
|
|
rotation: 0,
|
|
reverse: false,
|
|
colorSpace: "rgb"
|
|
};
|
|
var FILL_GRADIENT_LINEAR_DEFAULTS = {
|
|
type: "gradient",
|
|
gradient: "linear",
|
|
bounds: "item",
|
|
colorStops: { $shallow: { $map: [{ color: { $value: "$1" } }, { $palette: "gradient" }] } },
|
|
rotation: 0,
|
|
reverse: false,
|
|
colorSpace: "rgb"
|
|
};
|
|
var FILL_GRADIENT_LINEAR_HIERARCHY_DEFAULTS = {
|
|
...FILL_GRADIENT_LINEAR_DEFAULTS,
|
|
colorStops: {
|
|
$shallow: [
|
|
{
|
|
color: {
|
|
$mix: [{ $path: ["/1", { $palette: "fill" }, { $palette: "hierarchyColors" }] }, "black", 0.15]
|
|
}
|
|
},
|
|
{
|
|
color: {
|
|
$mix: [{ $path: ["/1", { $palette: "fill" }, { $palette: "hierarchyColors" }] }, "white", 0.15]
|
|
}
|
|
}
|
|
]
|
|
}
|
|
};
|
|
var FILL_GRADIENT_LINEAR_SINGLE_DEFAULTS = {
|
|
...FILL_GRADIENT_LINEAR_DEFAULTS,
|
|
colorStops: {
|
|
$map: [{ color: { $value: "$1" } }, { $path: ["/0", void 0, { $palette: "gradients" }] }]
|
|
}
|
|
};
|
|
var FILL_GRADIENT_LINEAR_KEYED_DEFAULTS = (key) => ({
|
|
...FILL_GRADIENT_LINEAR_DEFAULTS,
|
|
colorStops: {
|
|
$shallow: {
|
|
$if: [
|
|
{
|
|
$or: [
|
|
{ $isGradient: { $palette: `${key}.fill` } },
|
|
{ $isPattern: { $palette: `${key}.fill` } },
|
|
{ $isImage: { $palette: `${key}.fill` } }
|
|
]
|
|
},
|
|
{ $path: ["/colorStops", void 0, { $palette: `${key}.fill` }] },
|
|
[
|
|
{ color: { $mix: [{ $palette: `${key}.fill` }, "black", 0.15] } },
|
|
{ color: { $mix: [{ $palette: `${key}.fill` }, "white", 0.15] } }
|
|
]
|
|
]
|
|
}
|
|
}
|
|
});
|
|
var FILL_GRADIENT_RADIAL_DEFAULTS = {
|
|
type: "gradient",
|
|
gradient: "radial",
|
|
bounds: "item",
|
|
colorStops: { $shallow: { $map: [{ color: { $value: "$1" } }, { $palette: "gradient" }] } },
|
|
rotation: 0,
|
|
reverse: false,
|
|
colorSpace: "rgb"
|
|
};
|
|
var FILL_GRADIENT_RADIAL_REVERSED_DEFAULTS = {
|
|
...FILL_GRADIENT_RADIAL_DEFAULTS,
|
|
reverse: true
|
|
};
|
|
var FILL_GRADIENT_RADIAL_SERIES_DEFAULTS = {
|
|
...FILL_GRADIENT_RADIAL_DEFAULTS,
|
|
bounds: "series"
|
|
};
|
|
var FILL_GRADIENT_RADIAL_REVERSED_SERIES_DEFAULTS = {
|
|
...FILL_GRADIENT_RADIAL_DEFAULTS,
|
|
bounds: "series",
|
|
reverse: true
|
|
};
|
|
var FILL_GRADIENT_CONIC_SERIES_DEFAULTS = {
|
|
type: "gradient",
|
|
gradient: "conic",
|
|
bounds: "series",
|
|
colorStops: { $map: [{ color: { $value: "$1" } }, { $palette: "gradient" }] },
|
|
rotation: 0,
|
|
reverse: false,
|
|
colorSpace: "rgb"
|
|
};
|
|
var FILL_PATTERN_DEFAULTS = {
|
|
type: "pattern",
|
|
pattern: "forward-slanted-lines",
|
|
width: { $isUserOption: ["./height", { $path: "./height" }, 10] },
|
|
height: { $isUserOption: ["./width", { $path: "./width" }, 10] },
|
|
padding: 2,
|
|
fill: {
|
|
$if: [
|
|
{
|
|
$or: [{ $isGradient: { $palette: "fill" } }, { $isImage: { $palette: "fill" } }]
|
|
},
|
|
{ $palette: "fillFallback" },
|
|
{
|
|
$if: [
|
|
{ $isPattern: { $palette: "fill" } },
|
|
{ $path: ["/fill", { $palette: "fillFallback" }, { $palette: "fill" }] },
|
|
{ $palette: "fill" }
|
|
]
|
|
}
|
|
]
|
|
},
|
|
fillOpacity: 1,
|
|
stroke: SAFE_STROKE_FILL_OPERATION,
|
|
strokeOpacity: 1,
|
|
strokeWidth: {
|
|
$switch: [
|
|
{ $path: "./pattern" },
|
|
0,
|
|
[["backward-slanted-lines", "forward-slanted-lines", "horizontal-lines", "vertical-lines"], 4]
|
|
]
|
|
},
|
|
backgroundFill: "none",
|
|
backgroundFillOpacity: 1,
|
|
rotation: 0,
|
|
scale: 1
|
|
};
|
|
var FILL_PATTERN_SINGLE_DEFAULTS = {
|
|
...FILL_PATTERN_DEFAULTS,
|
|
stroke: {
|
|
$if: [
|
|
{ $isGradient: { $palette: "fill" } },
|
|
{ $path: ["/0", void 0, { $palette: "fillsFallback" }] },
|
|
{
|
|
$if: [
|
|
{ $isPattern: { $palette: "fill" } },
|
|
{
|
|
$path: [
|
|
"/stroke",
|
|
{ $path: ["/0", void 0, { $palette: "fillsFallback" }] },
|
|
{ $path: ["/0", void 0, { $palette: "fills" }] }
|
|
]
|
|
},
|
|
{ $path: ["/0", void 0, { $palette: "fills" }] }
|
|
]
|
|
}
|
|
]
|
|
},
|
|
fill: {
|
|
$if: [
|
|
{
|
|
$or: [{ $isGradient: { $palette: "fill" } }, { $isImage: { $palette: "fill" } }]
|
|
},
|
|
{ $path: ["/0", void 0, { $palette: "fillsFallback" }] },
|
|
{
|
|
$if: [
|
|
{ $isPattern: { $palette: "fill" } },
|
|
{
|
|
$path: [
|
|
"/fill",
|
|
{ $path: ["/0", void 0, { $palette: "fillsFallback" }] },
|
|
{ $path: ["/0", void 0, { $palette: "fills" }] }
|
|
]
|
|
},
|
|
{ $path: ["/0", void 0, { $palette: "fills" }] }
|
|
]
|
|
}
|
|
]
|
|
}
|
|
};
|
|
var FILL_PATTERN_BLANK_DEFAULTS = {
|
|
type: "pattern",
|
|
pattern: "forward-slanted-lines",
|
|
width: 8,
|
|
height: 8,
|
|
padding: 1,
|
|
fill: "black",
|
|
fillOpacity: 1,
|
|
backgroundFill: "white",
|
|
backgroundFillOpacity: 1,
|
|
stroke: "black",
|
|
strokeOpacity: 1,
|
|
strokeWidth: 1,
|
|
rotation: 0,
|
|
scale: 1
|
|
};
|
|
var FILL_PATTERN_HIERARCHY_DEFAULTS = {
|
|
...FILL_PATTERN_DEFAULTS,
|
|
fill: { $path: ["/1", { $palette: "fill" }, { $palette: "hierarchyColors" }] },
|
|
stroke: { $path: ["/1", { $palette: "fill" }, { $palette: "hierarchyColors" }] }
|
|
};
|
|
var FILL_PATTERN_KEYED_DEFAULTS = (key) => ({
|
|
...FILL_PATTERN_DEFAULTS,
|
|
stroke: {
|
|
$if: [
|
|
{ $isGradient: { $palette: `${key}.fill` } },
|
|
{ $palette: "fillFallback" },
|
|
{
|
|
$if: [
|
|
{ $isPattern: { $palette: `${key}.fill` } },
|
|
{ $path: ["/stroke", { $palette: "fillFallback" }, { $palette: `${key}.fill` }] },
|
|
{ $palette: `${key}.fill` }
|
|
]
|
|
}
|
|
]
|
|
}
|
|
});
|
|
var FILL_IMAGE_DEFAULTS = {
|
|
type: "image",
|
|
backgroundFill: { $palette: "fillFallback" },
|
|
backgroundFillOpacity: 1,
|
|
repeat: "no-repeat",
|
|
fit: "contain",
|
|
rotation: 0
|
|
};
|
|
var FILL_IMAGE_BLANK_DEFAULTS = {
|
|
type: "image",
|
|
backgroundFill: "black",
|
|
backgroundFillOpacity: 1,
|
|
rotation: 0,
|
|
repeat: "no-repeat",
|
|
fit: "contain",
|
|
width: 8,
|
|
height: 8
|
|
};
|
|
function getSequentialColors(colors) {
|
|
return mapValues(colors, (value) => {
|
|
const color2 = Color.fromString(value);
|
|
return [Color.darken(color2, 0.15).toString(), value, Color.lighten(color2, 0.15).toString()];
|
|
});
|
|
}
|
|
var LABEL_BOXING_DEFAULTS = {
|
|
padding: 8,
|
|
cornerRadius: 4,
|
|
fill: {
|
|
$if: [
|
|
{
|
|
$and: [
|
|
{ $eq: [{ $path: "./fill/type" }, "image"] },
|
|
{ $isUserOption: ["./fill/backgroundFill", false, true] }
|
|
]
|
|
},
|
|
{ backgroundFill: "transparent" },
|
|
void 0
|
|
]
|
|
},
|
|
border: {
|
|
enabled: { $isUserOption: ["../border", true, false] },
|
|
strokeWidth: 1,
|
|
stroke: { $foregroundOpacity: 0.08 }
|
|
}
|
|
};
|
|
var MULTI_SERIES_HIGHLIGHT_STYLE = {
|
|
enabled: true,
|
|
unhighlightedItem: {
|
|
opacity: 0.6
|
|
},
|
|
unhighlightedSeries: {
|
|
opacity: 0.2
|
|
}
|
|
};
|
|
var MARKER_SERIES_HIGHLIGHT_STYLE = {
|
|
enabled: true,
|
|
unhighlightedSeries: {
|
|
opacity: 0.2
|
|
}
|
|
};
|
|
var PART_WHOLE_HIGHLIGHT_STYLE = {
|
|
enabled: true,
|
|
unhighlightedItem: {
|
|
opacity: 0.2
|
|
},
|
|
unhighlightedSeries: {
|
|
opacity: 0.2
|
|
}
|
|
};
|
|
var SINGLE_SERIES_HIGHLIGHT_STYLE = {
|
|
enabled: true,
|
|
unhighlightedItem: {
|
|
opacity: 0.2
|
|
}
|
|
};
|
|
var LEGEND_CONTAINER_THEME = {
|
|
border: {
|
|
enabled: false,
|
|
stroke: { $foregroundBackgroundMix: 0.25 },
|
|
strokeOpacity: 1,
|
|
strokeWidth: 1
|
|
},
|
|
cornerRadius: 4,
|
|
fillOpacity: 1,
|
|
padding: {
|
|
$if: [{ $eq: [{ $path: "./border/enabled" }, true] }, 5, { $isUserOption: ["./fill", 5, 0] }]
|
|
}
|
|
};
|
|
var SEGMENTATION_DEFAULTS = {
|
|
enabled: false,
|
|
key: "x",
|
|
segments: {
|
|
$apply: {
|
|
fill: {
|
|
$applySwitch: [
|
|
{ $path: "type" },
|
|
{ $path: "../../../fill" },
|
|
["gradient", FILL_GRADIENT_LINEAR_DEFAULTS],
|
|
["image", FILL_IMAGE_DEFAULTS],
|
|
["pattern", FILL_PATTERN_DEFAULTS]
|
|
]
|
|
},
|
|
stroke: { $path: "../../../stroke" },
|
|
fillOpacity: { $path: "../../../fillOpacity" },
|
|
strokeWidth: {
|
|
$isUserOption: [
|
|
"./stroke",
|
|
{
|
|
$isUserOption: [
|
|
"../../../strokeWidth",
|
|
{ $path: "../../../strokeWidth" },
|
|
{
|
|
$if: [
|
|
{ $greaterThan: [{ $path: "../../../strokeWidth" }, 0] },
|
|
{ $path: "../../../strokeWidth" },
|
|
2
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{ $path: "../../../strokeWidth" }
|
|
]
|
|
},
|
|
strokeOpacity: { $path: "../../../strokeOpacity" },
|
|
lineDash: { $path: "../../../lineDash" },
|
|
lineDashOffset: { $path: "../../../lineDashOffset" }
|
|
}
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-core/src/state/memento.ts
|
|
var MementoCaretaker = class _MementoCaretaker {
|
|
constructor(version) {
|
|
this.version = version.split("-")[0];
|
|
}
|
|
save(...originators) {
|
|
const packet = { version: this.version };
|
|
for (const originator of Object.values(originators)) {
|
|
packet[originator.mementoOriginatorKey] = this.encode(originator, originator.createMemento());
|
|
}
|
|
return packet;
|
|
}
|
|
restore(blob, ...originators) {
|
|
if (typeof blob !== "object") {
|
|
warnOnce(`Could not restore data of type [${typeof blob}], expecting an object, ignoring.`);
|
|
return;
|
|
}
|
|
if (blob == null) {
|
|
warnOnce(`Could not restore data of type [null], expecting an object, ignoring.`);
|
|
return;
|
|
}
|
|
if (!("version" in blob) || typeof blob.version !== "string") {
|
|
warnOnce(`Could not restore data, missing [version] string in object, ignoring.`);
|
|
return;
|
|
}
|
|
for (const originator of originators) {
|
|
const memento = this.decode(originator, blob[originator.mementoOriginatorKey]);
|
|
const messages = [];
|
|
if (!originator.guardMemento(memento, messages)) {
|
|
const messagesString = messages.length > 0 ? `
|
|
|
|
${messages.join("\n\n")}
|
|
|
|
` : "";
|
|
warnOnce(
|
|
`Could not restore [${originator.mementoOriginatorKey}] data, value was invalid, ignoring.${messagesString}`,
|
|
memento
|
|
);
|
|
return;
|
|
}
|
|
originator.restoreMemento(this.version, blob.version, memento);
|
|
}
|
|
}
|
|
/**
|
|
* Encode a memento as a serializable object, encoding any non-serializble types.
|
|
*/
|
|
encode(originator, memento) {
|
|
try {
|
|
return JSON.parse(JSON.stringify(memento, _MementoCaretaker.encodeTypes));
|
|
} catch (error2) {
|
|
throw new Error(`Failed to encode [${originator.mementoOriginatorKey}] value [${error2}].`, {
|
|
cause: error2
|
|
});
|
|
}
|
|
}
|
|
/**
|
|
* Decode an encoded memento, decoding any non-serializable types.
|
|
*/
|
|
decode(originator, encoded) {
|
|
if (encoded == null)
|
|
return encoded;
|
|
try {
|
|
return JSON.parse(JSON.stringify(encoded), _MementoCaretaker.decodeTypes);
|
|
} catch (error2) {
|
|
throw new Error(`Failed to decode [${originator.mementoOriginatorKey}] value [${error2}].`, {
|
|
cause: error2
|
|
});
|
|
}
|
|
}
|
|
static encodeTypes(key, value) {
|
|
if (isDate(this[key])) {
|
|
return { __type: "date", value: this[key].toISOString() };
|
|
}
|
|
return value;
|
|
}
|
|
static decodeTypes(key, value) {
|
|
if (isObject(this[key]) && "__type" in this[key] && this[key].__type === "date") {
|
|
return new Date(this[key].value);
|
|
}
|
|
return value;
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-core/src/types/axisDirection.ts
|
|
var ChartAxisDirection = /* @__PURE__ */ ((ChartAxisDirection2) => {
|
|
ChartAxisDirection2["X"] = "x";
|
|
ChartAxisDirection2["Y"] = "y";
|
|
ChartAxisDirection2["Angle"] = "angle";
|
|
ChartAxisDirection2["Radius"] = "radius";
|
|
return ChartAxisDirection2;
|
|
})(ChartAxisDirection || {});
|
|
|
|
// packages/ag-charts-core/src/types/updateType.ts
|
|
var ChartUpdateType = /* @__PURE__ */ ((ChartUpdateType2) => {
|
|
ChartUpdateType2[ChartUpdateType2["FULL"] = 0] = "FULL";
|
|
ChartUpdateType2[ChartUpdateType2["UPDATE_DATA"] = 1] = "UPDATE_DATA";
|
|
ChartUpdateType2[ChartUpdateType2["PROCESS_DATA"] = 2] = "PROCESS_DATA";
|
|
ChartUpdateType2[ChartUpdateType2["PROCESS_DOMAIN"] = 3] = "PROCESS_DOMAIN";
|
|
ChartUpdateType2[ChartUpdateType2["PROCESS_RANGE"] = 4] = "PROCESS_RANGE";
|
|
ChartUpdateType2[ChartUpdateType2["PERFORM_LAYOUT"] = 5] = "PERFORM_LAYOUT";
|
|
ChartUpdateType2[ChartUpdateType2["PRE_SERIES_UPDATE"] = 6] = "PRE_SERIES_UPDATE";
|
|
ChartUpdateType2[ChartUpdateType2["SERIES_UPDATE"] = 7] = "SERIES_UPDATE";
|
|
ChartUpdateType2[ChartUpdateType2["PRE_SCENE_RENDER"] = 8] = "PRE_SCENE_RENDER";
|
|
ChartUpdateType2[ChartUpdateType2["SCENE_RENDER"] = 9] = "SCENE_RENDER";
|
|
ChartUpdateType2[ChartUpdateType2["NONE"] = 10] = "NONE";
|
|
return ChartUpdateType2;
|
|
})(ChartUpdateType || {});
|
|
|
|
// packages/ag-charts-core/src/types/zIndexMap.ts
|
|
var ZIndexMap = /* @__PURE__ */ ((ZIndexMap2) => {
|
|
ZIndexMap2[ZIndexMap2["CHART_BACKGROUND"] = 0] = "CHART_BACKGROUND";
|
|
ZIndexMap2[ZIndexMap2["AXIS_BAND_HIGHLIGHT"] = 1] = "AXIS_BAND_HIGHLIGHT";
|
|
ZIndexMap2[ZIndexMap2["AXIS_GRID"] = 2] = "AXIS_GRID";
|
|
ZIndexMap2[ZIndexMap2["AXIS"] = 3] = "AXIS";
|
|
ZIndexMap2[ZIndexMap2["SERIES_AREA_CONTAINER"] = 4] = "SERIES_AREA_CONTAINER";
|
|
ZIndexMap2[ZIndexMap2["ZOOM_SELECTION"] = 5] = "ZOOM_SELECTION";
|
|
ZIndexMap2[ZIndexMap2["SERIES_CROSSLINE_RANGE"] = 6] = "SERIES_CROSSLINE_RANGE";
|
|
ZIndexMap2[ZIndexMap2["SERIES_LAYER"] = 7] = "SERIES_LAYER";
|
|
ZIndexMap2[ZIndexMap2["AXIS_FOREGROUND"] = 8] = "AXIS_FOREGROUND";
|
|
ZIndexMap2[ZIndexMap2["SERIES_CROSSHAIR"] = 9] = "SERIES_CROSSHAIR";
|
|
ZIndexMap2[ZIndexMap2["SERIES_CROSSLINE_LINE"] = 10] = "SERIES_CROSSLINE_LINE";
|
|
ZIndexMap2[ZIndexMap2["SERIES_ANNOTATION"] = 11] = "SERIES_ANNOTATION";
|
|
ZIndexMap2[ZIndexMap2["CHART_ANNOTATION"] = 12] = "CHART_ANNOTATION";
|
|
ZIndexMap2[ZIndexMap2["CHART_ANNOTATION_FOCUSED"] = 13] = "CHART_ANNOTATION_FOCUSED";
|
|
ZIndexMap2[ZIndexMap2["STATUS_BAR"] = 14] = "STATUS_BAR";
|
|
ZIndexMap2[ZIndexMap2["SERIES_LABEL"] = 15] = "SERIES_LABEL";
|
|
ZIndexMap2[ZIndexMap2["LEGEND"] = 16] = "LEGEND";
|
|
ZIndexMap2[ZIndexMap2["NAVIGATOR"] = 17] = "NAVIGATOR";
|
|
ZIndexMap2[ZIndexMap2["FOREGROUND"] = 18] = "FOREGROUND";
|
|
return ZIndexMap2;
|
|
})(ZIndexMap || {});
|
|
var SeriesZIndexMap = /* @__PURE__ */ ((SeriesZIndexMap2) => {
|
|
SeriesZIndexMap2[SeriesZIndexMap2["BACKGROUND"] = 0] = "BACKGROUND";
|
|
SeriesZIndexMap2[SeriesZIndexMap2["ANY_CONTENT"] = 1] = "ANY_CONTENT";
|
|
return SeriesZIndexMap2;
|
|
})(SeriesZIndexMap || {});
|
|
var SeriesContentZIndexMap = /* @__PURE__ */ ((SeriesContentZIndexMap2) => {
|
|
SeriesContentZIndexMap2[SeriesContentZIndexMap2["FOREGROUND"] = 0] = "FOREGROUND";
|
|
SeriesContentZIndexMap2[SeriesContentZIndexMap2["HIGHLIGHT"] = 1] = "HIGHLIGHT";
|
|
SeriesContentZIndexMap2[SeriesContentZIndexMap2["LABEL"] = 2] = "LABEL";
|
|
return SeriesContentZIndexMap2;
|
|
})(SeriesContentZIndexMap || {});
|
|
var PolarZIndexMap = /* @__PURE__ */ ((PolarZIndexMap2) => {
|
|
PolarZIndexMap2[PolarZIndexMap2["BACKGROUND"] = 0] = "BACKGROUND";
|
|
PolarZIndexMap2[PolarZIndexMap2["FOREGROUND"] = 1] = "FOREGROUND";
|
|
PolarZIndexMap2[PolarZIndexMap2["HIGHLIGHT"] = 2] = "HIGHLIGHT";
|
|
PolarZIndexMap2[PolarZIndexMap2["LABEL"] = 3] = "LABEL";
|
|
return PolarZIndexMap2;
|
|
})(PolarZIndexMap || {});
|
|
|
|
// packages/ag-charts-core/src/chart/legendUtil.ts
|
|
function expandLegendPosition(position) {
|
|
const {
|
|
placement = "bottom",
|
|
floating = false,
|
|
xOffset = 0,
|
|
yOffset = 0
|
|
} = typeof position === "string" ? { placement: position, floating: false } : position;
|
|
return { placement, floating, xOffset, yOffset };
|
|
}
|
|
|
|
// packages/ag-charts-core/src/state/properties.ts
|
|
var BaseProperties = class {
|
|
handleUnknownProperties(_unknownKeys, _properties) {
|
|
}
|
|
set(properties) {
|
|
const { className = this.constructor.name } = this.constructor;
|
|
if (properties == null) {
|
|
this.clear();
|
|
return this;
|
|
}
|
|
if (typeof properties !== "object") {
|
|
warn(`unable to set ${className} - expecting a properties object`);
|
|
return this;
|
|
}
|
|
const keys = new Set(Object.keys(properties));
|
|
for (const propertyKey of listDecoratedProperties(this)) {
|
|
if (keys.has(propertyKey)) {
|
|
const value = properties[propertyKey];
|
|
const self = this;
|
|
if (isProperties(self[propertyKey])) {
|
|
if (self[propertyKey] instanceof PropertiesArray) {
|
|
const array2 = self[propertyKey].reset(value);
|
|
if (array2 == null) {
|
|
warn(`unable to set [${String(propertyKey)}] - expecting a properties array`);
|
|
} else {
|
|
self[propertyKey] = array2;
|
|
}
|
|
} else {
|
|
self[propertyKey].set(value);
|
|
}
|
|
} else if (isPlainObject(value)) {
|
|
self[propertyKey] = merge(value, self[propertyKey] ?? {});
|
|
} else {
|
|
self[propertyKey] = value;
|
|
}
|
|
keys.delete(propertyKey);
|
|
}
|
|
}
|
|
this.handleUnknownProperties(keys, properties);
|
|
for (const unknownKey of keys) {
|
|
warn(`unable to set [${String(unknownKey)}] in ${className} - property is unknown`);
|
|
}
|
|
return this;
|
|
}
|
|
clear() {
|
|
for (const propertyKey of listDecoratedProperties(this)) {
|
|
const currentValue = this[propertyKey];
|
|
if (isProperties(currentValue)) {
|
|
currentValue.clear();
|
|
} else {
|
|
this[propertyKey] = void 0;
|
|
}
|
|
}
|
|
return this;
|
|
}
|
|
toJson() {
|
|
return listDecoratedProperties(this).reduce((object2, propertyKey) => {
|
|
const propertyValue = this[propertyKey];
|
|
object2[String(propertyKey)] = isProperties(propertyValue) ? propertyValue.toJson() : propertyValue;
|
|
return object2;
|
|
}, {});
|
|
}
|
|
};
|
|
var PropertiesArray = class _PropertiesArray extends Array {
|
|
constructor(itemFactory, ...properties) {
|
|
super(properties.length);
|
|
const isConstructor = (value2) => Boolean(value2?.prototype?.constructor?.name);
|
|
const value = isConstructor(itemFactory) ? (params) => new itemFactory().set(params) : itemFactory;
|
|
Object.defineProperty(this, "itemFactory", { value, enumerable: false, configurable: false });
|
|
this.set(properties);
|
|
}
|
|
set(properties) {
|
|
if (isArray(properties)) {
|
|
this.length = properties.length;
|
|
for (let i = 0; i < properties.length; i++) {
|
|
this[i] = this.itemFactory(properties[i]);
|
|
}
|
|
}
|
|
return this;
|
|
}
|
|
reset(properties) {
|
|
if (Array.isArray(properties)) {
|
|
return new _PropertiesArray(this.itemFactory, ...properties);
|
|
}
|
|
}
|
|
toJson() {
|
|
return this.map((value) => value?.toJson?.() ?? value);
|
|
}
|
|
};
|
|
function isProperties(value) {
|
|
return value instanceof BaseProperties || value instanceof PropertiesArray;
|
|
}
|
|
|
|
// packages/ag-charts-core/src/chart/interpolationProperties.ts
|
|
var InterpolationProperties = class extends BaseProperties {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.type = "linear";
|
|
this.tension = 1;
|
|
this.position = "end";
|
|
}
|
|
};
|
|
__decorateClass([
|
|
addFakeTransformToInstanceProperty
|
|
], InterpolationProperties.prototype, "type", 2);
|
|
__decorateClass([
|
|
addFakeTransformToInstanceProperty
|
|
], InterpolationProperties.prototype, "tension", 2);
|
|
__decorateClass([
|
|
addFakeTransformToInstanceProperty
|
|
], InterpolationProperties.prototype, "position", 2);
|
|
|
|
// packages/ag-charts-core/src/utils/data/numberArray.ts
|
|
function clampArray(value, array2) {
|
|
const [min, max] = findMinMax(array2);
|
|
return clamp(min, value, max);
|
|
}
|
|
function findMinMax(array2) {
|
|
if (array2.length === 0)
|
|
return [];
|
|
const result = [Infinity, -Infinity];
|
|
for (const val of array2) {
|
|
if (val < result[0])
|
|
result[0] = val;
|
|
if (val > result[1])
|
|
result[1] = val;
|
|
}
|
|
return result;
|
|
}
|
|
function findRangeExtent(array2) {
|
|
const [min, max] = findMinMax(array2);
|
|
return max - min;
|
|
}
|
|
function nextPowerOf2(value) {
|
|
value = Math.trunc(value);
|
|
if (value <= 0)
|
|
return 1;
|
|
if (value === 1)
|
|
return 2;
|
|
return 1 << 32 - Math.clz32(value - 1);
|
|
}
|
|
function previousPowerOf2(value) {
|
|
value = Math.trunc(value);
|
|
if (value <= 0)
|
|
return 0;
|
|
if (value === 1)
|
|
return 1;
|
|
return 1 << 31 - Math.clz32(value);
|
|
}
|
|
|
|
// packages/ag-charts-core/src/utils/aggregation.ts
|
|
var AGGREGATION_INDEX_X_MIN = 0;
|
|
var AGGREGATION_INDEX_X_MAX = 1;
|
|
var AGGREGATION_INDEX_Y_MIN = 2;
|
|
var AGGREGATION_INDEX_Y_MAX = 3;
|
|
var AGGREGATION_SPAN = 4;
|
|
var AGGREGATION_THRESHOLD = 1e3;
|
|
var AGGREGATION_MAX_POINTS = 10;
|
|
var AGGREGATION_MIN_RANGE = 64;
|
|
var AGGREGATION_INDEX_UNSET = 4294967295;
|
|
var SMALLEST_INTERVAL_MIN_RECURSE = 3;
|
|
var SMALLEST_INTERVAL_RECURSE_LIMIT = 20;
|
|
var SMALLEST_INTERVAL_MAX_INDEX_ADJUSTMENTS = 100;
|
|
function estimateSmallestPixelIntervalIter(xValues, d0, d1, startDatumIndex, endDatumIndex, currentSmallestInterval, depth, xNeedsValueOf) {
|
|
let indexAdjustments = 0;
|
|
while (indexAdjustments < SMALLEST_INTERVAL_MAX_INDEX_ADJUSTMENTS && xValues[startDatumIndex] == null && startDatumIndex < endDatumIndex) {
|
|
startDatumIndex += 1;
|
|
indexAdjustments += 1;
|
|
}
|
|
while (indexAdjustments < SMALLEST_INTERVAL_MAX_INDEX_ADJUSTMENTS && xValues[endDatumIndex] == null && endDatumIndex > startDatumIndex) {
|
|
endDatumIndex -= 1;
|
|
indexAdjustments += 1;
|
|
}
|
|
if (indexAdjustments >= SMALLEST_INTERVAL_MAX_INDEX_ADJUSTMENTS || startDatumIndex >= endDatumIndex) {
|
|
return currentSmallestInterval;
|
|
}
|
|
const ratio2 = Number.isFinite(d0) ? aggregationXRatioForXValue(xValues[endDatumIndex], d0, d1, xNeedsValueOf) - aggregationXRatioForXValue(xValues[startDatumIndex], d0, d1, xNeedsValueOf) : aggregationXRatioForDatumIndex(endDatumIndex, xValues.length) - aggregationXRatioForDatumIndex(startDatumIndex, xValues.length);
|
|
if (ratio2 === 0 || !Number.isFinite(ratio2))
|
|
return currentSmallestInterval;
|
|
const currentInterval = Math.abs(ratio2) / (endDatumIndex - startDatumIndex);
|
|
let recurse;
|
|
if (depth < SMALLEST_INTERVAL_MIN_RECURSE) {
|
|
recurse = true;
|
|
} else if (depth > SMALLEST_INTERVAL_RECURSE_LIMIT) {
|
|
recurse = false;
|
|
} else {
|
|
recurse = currentInterval <= currentSmallestInterval;
|
|
}
|
|
currentSmallestInterval = Math.min(currentSmallestInterval, currentInterval);
|
|
if (!recurse)
|
|
return currentSmallestInterval;
|
|
const midIndex = Math.floor((startDatumIndex + endDatumIndex) / 2);
|
|
const leadingInterval = estimateSmallestPixelIntervalIter(
|
|
xValues,
|
|
d0,
|
|
d1,
|
|
startDatumIndex,
|
|
midIndex,
|
|
currentSmallestInterval,
|
|
depth + 1,
|
|
xNeedsValueOf
|
|
);
|
|
const trailingInterval = estimateSmallestPixelIntervalIter(
|
|
xValues,
|
|
d0,
|
|
d1,
|
|
midIndex + 1,
|
|
endDatumIndex,
|
|
currentSmallestInterval,
|
|
depth + 1,
|
|
xNeedsValueOf
|
|
);
|
|
return Math.min(leadingInterval, trailingInterval, currentSmallestInterval);
|
|
}
|
|
function estimateSmallestPixelInterval(xValues, d0, d1, xNeedsValueOf) {
|
|
return estimateSmallestPixelIntervalIter(
|
|
xValues,
|
|
d0,
|
|
d1,
|
|
0,
|
|
xValues.length - 1,
|
|
1 / (xValues.length - 1),
|
|
0,
|
|
xNeedsValueOf
|
|
);
|
|
}
|
|
function aggregationRangeFittingPoints(xValues, d0, d1, opts) {
|
|
if (Number.isFinite(d0)) {
|
|
const smallestKeyInterval = opts?.smallestKeyInterval;
|
|
const xNeedsValueOf = opts?.xNeedsValueOf ?? true;
|
|
const smallestPixelInterval = smallestKeyInterval == null ? estimateSmallestPixelInterval(xValues, d0, d1, xNeedsValueOf) : smallestKeyInterval / (d1 - d0);
|
|
return nextPowerOf2(Math.trunc(1 / smallestPixelInterval)) >> 3;
|
|
} else {
|
|
let power = Math.ceil(Math.log2(xValues.length)) - 1;
|
|
power = Math.min(Math.max(power, 0), 24);
|
|
return Math.trunc(2 ** power);
|
|
}
|
|
}
|
|
function aggregationDomain(scale, domainInput) {
|
|
const { domain, sortMetadata } = domainInput;
|
|
switch (scale) {
|
|
case "category":
|
|
return [Number.NaN, Number.NaN];
|
|
case "number":
|
|
case "time":
|
|
case "ordinal-time":
|
|
case "unit-time": {
|
|
if (domain.length === 0)
|
|
return [Infinity, -Infinity];
|
|
if (sortMetadata?.sortOrder === 1) {
|
|
return [Number(domain[0]), Number(domain.at(-1))];
|
|
}
|
|
if (sortMetadata?.sortOrder === -1) {
|
|
return [Number(domain.at(-1)), Number(domain[0])];
|
|
}
|
|
let min = Infinity;
|
|
let max = -Infinity;
|
|
for (const d of domain) {
|
|
const value = Number(d);
|
|
min = Math.min(min, value);
|
|
max = Math.max(max, value);
|
|
}
|
|
return [min, max];
|
|
}
|
|
case "color":
|
|
case "log":
|
|
case "mercator":
|
|
return [0, 0];
|
|
}
|
|
}
|
|
function aggregationXRatioForDatumIndex(datumIndex, domainCount) {
|
|
return datumIndex / domainCount;
|
|
}
|
|
function aggregationXRatioForXValue(xValue, d0, d1, xNeedsValueOf) {
|
|
if (xNeedsValueOf) {
|
|
return (xValue.valueOf() - d0) / (d1 - d0);
|
|
}
|
|
return (xValue - d0) / (d1 - d0);
|
|
}
|
|
function aggregationIndexForXRatio(xRatio, maxRange) {
|
|
return Math.trunc(Math.min(Math.floor(xRatio * maxRange), maxRange - 1) * AGGREGATION_SPAN);
|
|
}
|
|
function aggregationBucketForDatum(xValues, d0, d1, maxRange, datumIndex, { xNeedsValueOf = true, xValuesLength } = {}) {
|
|
const xValue = xValues[datumIndex];
|
|
if (xValue == null)
|
|
return -1;
|
|
const length2 = xValuesLength ?? xValues.length;
|
|
const xRatio = Number.isFinite(d0) ? aggregationXRatioForXValue(xValue, d0, d1, xNeedsValueOf) : aggregationXRatioForDatumIndex(datumIndex, length2);
|
|
return aggregationIndexForXRatio(xRatio, maxRange);
|
|
}
|
|
function aggregationDatumMatchesIndex(indexData, aggIndex, datumIndex, offsets) {
|
|
for (const offset of offsets) {
|
|
if (datumIndex === indexData[aggIndex + offset]) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
function createAggregationIndices(xValues, yMaxValues, yMinValues, d0, d1, maxRange, {
|
|
positive,
|
|
split = false,
|
|
xNeedsValueOf = true,
|
|
yNeedsValueOf = true,
|
|
// Optional pre-allocated arrays to reuse (must be correct size: maxRange * AGGREGATION_SPAN)
|
|
reuseIndexData,
|
|
reuseValueData,
|
|
reuseNegativeIndexData,
|
|
reuseNegativeValueData
|
|
} = {}) {
|
|
const nan = Number.NaN;
|
|
const requiredSize = maxRange * AGGREGATION_SPAN;
|
|
const indexData = reuseIndexData?.length === requiredSize ? reuseIndexData : new Uint32Array(requiredSize);
|
|
const valueData = reuseValueData?.length === requiredSize ? reuseValueData : new Float64Array(requiredSize);
|
|
let negativeIndexData;
|
|
let negativeValueData;
|
|
if (split) {
|
|
if (reuseNegativeIndexData?.length === requiredSize) {
|
|
negativeIndexData = reuseNegativeIndexData;
|
|
} else {
|
|
negativeIndexData = new Uint32Array(requiredSize);
|
|
}
|
|
if (reuseNegativeValueData?.length === requiredSize) {
|
|
negativeValueData = reuseNegativeValueData;
|
|
} else {
|
|
negativeValueData = new Float64Array(requiredSize);
|
|
}
|
|
}
|
|
const continuous = Number.isFinite(d0) && Number.isFinite(d1);
|
|
const domainCount = xValues.length;
|
|
if (continuous) {
|
|
valueData.fill(nan);
|
|
indexData.fill(AGGREGATION_INDEX_UNSET);
|
|
if (split) {
|
|
negativeValueData.fill(nan);
|
|
negativeIndexData.fill(AGGREGATION_INDEX_UNSET);
|
|
}
|
|
}
|
|
const scaleFactor = continuous ? maxRange / (d1 - d0) : maxRange * (1 / domainCount);
|
|
let lastAggIndex = -1;
|
|
let cachedXMinIndex = -1;
|
|
let cachedXMinValue = nan;
|
|
let cachedXMaxIndex = -1;
|
|
let cachedXMaxValue = nan;
|
|
let cachedYMinIndex = -1;
|
|
let cachedYMinValue = nan;
|
|
let cachedYMaxIndex = -1;
|
|
let cachedYMaxValue = nan;
|
|
let negLastAggIndex = -1;
|
|
let negCachedXMinIndex = -1;
|
|
let negCachedXMinValue = nan;
|
|
let negCachedXMaxIndex = -1;
|
|
let negCachedXMaxValue = nan;
|
|
let negCachedYMinIndex = -1;
|
|
let negCachedYMinValue = nan;
|
|
let negCachedYMaxIndex = -1;
|
|
let negCachedYMaxValue = nan;
|
|
const xValuesLength = xValues.length;
|
|
const yArraysSame = yMaxValues === yMinValues;
|
|
for (let datumIndex = 0; datumIndex < xValuesLength; datumIndex++) {
|
|
const xValue = xValues[datumIndex];
|
|
if (xValue == null)
|
|
continue;
|
|
const yMaxValue = yMaxValues[datumIndex];
|
|
const yMinValue = yArraysSame ? yMaxValue : yMinValues[datumIndex];
|
|
let yMax;
|
|
let yMin;
|
|
if (yNeedsValueOf) {
|
|
yMax = yMaxValue == null ? nan : yMaxValue.valueOf();
|
|
yMin = yMinValue == null ? nan : yMinValue.valueOf();
|
|
} else {
|
|
yMax = yMaxValue ?? nan;
|
|
yMin = yMinValue ?? nan;
|
|
}
|
|
let isPositiveDatum = true;
|
|
if (split) {
|
|
isPositiveDatum = yMax >= 0;
|
|
} else if (positive != null && yMax >= 0 !== positive) {
|
|
continue;
|
|
}
|
|
let scaledX;
|
|
if (continuous) {
|
|
if (xNeedsValueOf) {
|
|
scaledX = (xValue.valueOf() - d0) * scaleFactor;
|
|
} else {
|
|
scaledX = (xValue - d0) * scaleFactor;
|
|
}
|
|
} else {
|
|
scaledX = datumIndex * scaleFactor;
|
|
}
|
|
const bucketIndex = Math.floor(scaledX);
|
|
const aggIndex = (bucketIndex < maxRange ? bucketIndex : maxRange - 1) << 2;
|
|
if (isPositiveDatum) {
|
|
if (aggIndex !== lastAggIndex) {
|
|
if (lastAggIndex !== -1) {
|
|
indexData[lastAggIndex] = cachedXMinIndex;
|
|
indexData[lastAggIndex + 1] = cachedXMaxIndex;
|
|
indexData[lastAggIndex + 2] = cachedYMinIndex;
|
|
indexData[lastAggIndex + 3] = cachedYMaxIndex;
|
|
valueData[lastAggIndex] = cachedXMinValue;
|
|
valueData[lastAggIndex + 1] = cachedXMaxValue;
|
|
valueData[lastAggIndex + 2] = cachedYMinValue;
|
|
valueData[lastAggIndex + 3] = cachedYMaxValue;
|
|
}
|
|
lastAggIndex = aggIndex;
|
|
cachedXMinIndex = -1;
|
|
cachedXMinValue = nan;
|
|
cachedXMaxIndex = -1;
|
|
cachedXMaxValue = nan;
|
|
cachedYMinIndex = -1;
|
|
cachedYMinValue = nan;
|
|
cachedYMaxIndex = -1;
|
|
cachedYMaxValue = nan;
|
|
}
|
|
const yMinValid = yMin === yMin;
|
|
const yMaxValid = yMax === yMax;
|
|
if (cachedXMinIndex === -1) {
|
|
cachedXMinIndex = datumIndex;
|
|
cachedXMinValue = scaledX;
|
|
cachedXMaxIndex = datumIndex;
|
|
cachedXMaxValue = scaledX;
|
|
if (yMinValid) {
|
|
cachedYMinIndex = datumIndex;
|
|
cachedYMinValue = yMin;
|
|
}
|
|
if (yMaxValid) {
|
|
cachedYMaxIndex = datumIndex;
|
|
cachedYMaxValue = yMax;
|
|
}
|
|
} else {
|
|
if (scaledX < cachedXMinValue) {
|
|
cachedXMinIndex = datumIndex;
|
|
cachedXMinValue = scaledX;
|
|
}
|
|
if (scaledX > cachedXMaxValue) {
|
|
cachedXMaxIndex = datumIndex;
|
|
cachedXMaxValue = scaledX;
|
|
}
|
|
if (yMinValid && yMin < cachedYMinValue) {
|
|
cachedYMinIndex = datumIndex;
|
|
cachedYMinValue = yMin;
|
|
}
|
|
if (yMaxValid && yMax > cachedYMaxValue) {
|
|
cachedYMaxIndex = datumIndex;
|
|
cachedYMaxValue = yMax;
|
|
}
|
|
}
|
|
} else {
|
|
if (aggIndex !== negLastAggIndex) {
|
|
if (negLastAggIndex !== -1) {
|
|
negativeIndexData[negLastAggIndex] = negCachedXMinIndex;
|
|
negativeIndexData[negLastAggIndex + 1] = negCachedXMaxIndex;
|
|
negativeIndexData[negLastAggIndex + 2] = negCachedYMinIndex;
|
|
negativeIndexData[negLastAggIndex + 3] = negCachedYMaxIndex;
|
|
negativeValueData[negLastAggIndex] = negCachedXMinValue;
|
|
negativeValueData[negLastAggIndex + 1] = negCachedXMaxValue;
|
|
negativeValueData[negLastAggIndex + 2] = negCachedYMinValue;
|
|
negativeValueData[negLastAggIndex + 3] = negCachedYMaxValue;
|
|
}
|
|
negLastAggIndex = aggIndex;
|
|
negCachedXMinIndex = -1;
|
|
negCachedXMinValue = nan;
|
|
negCachedXMaxIndex = -1;
|
|
negCachedXMaxValue = nan;
|
|
negCachedYMinIndex = -1;
|
|
negCachedYMinValue = nan;
|
|
negCachedYMaxIndex = -1;
|
|
negCachedYMaxValue = nan;
|
|
}
|
|
const yMinValid = yMin === yMin;
|
|
const yMaxValid = yMax === yMax;
|
|
if (negCachedXMinIndex === -1) {
|
|
negCachedXMinIndex = datumIndex;
|
|
negCachedXMinValue = scaledX;
|
|
negCachedXMaxIndex = datumIndex;
|
|
negCachedXMaxValue = scaledX;
|
|
if (yMinValid) {
|
|
negCachedYMinIndex = datumIndex;
|
|
negCachedYMinValue = yMin;
|
|
}
|
|
if (yMaxValid) {
|
|
negCachedYMaxIndex = datumIndex;
|
|
negCachedYMaxValue = yMax;
|
|
}
|
|
} else {
|
|
if (scaledX < negCachedXMinValue) {
|
|
negCachedXMinIndex = datumIndex;
|
|
negCachedXMinValue = scaledX;
|
|
}
|
|
if (scaledX > negCachedXMaxValue) {
|
|
negCachedXMaxIndex = datumIndex;
|
|
negCachedXMaxValue = scaledX;
|
|
}
|
|
if (yMinValid && yMin < negCachedYMinValue) {
|
|
negCachedYMinIndex = datumIndex;
|
|
negCachedYMinValue = yMin;
|
|
}
|
|
if (yMaxValid && yMax > negCachedYMaxValue) {
|
|
negCachedYMaxIndex = datumIndex;
|
|
negCachedYMaxValue = yMax;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (lastAggIndex !== -1) {
|
|
indexData[lastAggIndex] = cachedXMinIndex;
|
|
indexData[lastAggIndex + 1] = cachedXMaxIndex;
|
|
indexData[lastAggIndex + 2] = cachedYMinIndex;
|
|
indexData[lastAggIndex + 3] = cachedYMaxIndex;
|
|
valueData[lastAggIndex] = cachedXMinValue;
|
|
valueData[lastAggIndex + 1] = cachedXMaxValue;
|
|
valueData[lastAggIndex + 2] = cachedYMinValue;
|
|
valueData[lastAggIndex + 3] = cachedYMaxValue;
|
|
}
|
|
if (split && negLastAggIndex !== -1) {
|
|
negativeIndexData[negLastAggIndex] = negCachedXMinIndex;
|
|
negativeIndexData[negLastAggIndex + 1] = negCachedXMaxIndex;
|
|
negativeIndexData[negLastAggIndex + 2] = negCachedYMinIndex;
|
|
negativeIndexData[negLastAggIndex + 3] = negCachedYMaxIndex;
|
|
negativeValueData[negLastAggIndex] = negCachedXMinValue;
|
|
negativeValueData[negLastAggIndex + 1] = negCachedXMaxValue;
|
|
negativeValueData[negLastAggIndex + 2] = negCachedYMinValue;
|
|
negativeValueData[negLastAggIndex + 3] = negCachedYMaxValue;
|
|
}
|
|
return { indexData, valueData, negativeIndexData, negativeValueData };
|
|
}
|
|
function compactAggregationIndices(indexData, valueData, maxRange, {
|
|
inPlace = false,
|
|
midpointData,
|
|
reuseIndexData,
|
|
reuseValueData
|
|
} = {}) {
|
|
const nextMaxRange = Math.trunc(maxRange / 2);
|
|
const requiredSize = nextMaxRange * AGGREGATION_SPAN;
|
|
let nextIndexData;
|
|
if (inPlace) {
|
|
nextIndexData = indexData;
|
|
} else if (reuseIndexData?.length === requiredSize) {
|
|
nextIndexData = reuseIndexData;
|
|
} else {
|
|
nextIndexData = new Uint32Array(requiredSize);
|
|
}
|
|
let nextValueData;
|
|
if (inPlace) {
|
|
nextValueData = valueData;
|
|
} else if (reuseValueData?.length === requiredSize) {
|
|
nextValueData = reuseValueData;
|
|
} else {
|
|
nextValueData = new Float64Array(requiredSize);
|
|
}
|
|
const nextMidpointData = midpointData ?? new Uint32Array(nextMaxRange);
|
|
for (let i = 0; i < nextMaxRange; i += 1) {
|
|
const aggIndex = Math.trunc(i * AGGREGATION_SPAN);
|
|
const index0 = Math.trunc(aggIndex * 2);
|
|
const index1 = Math.trunc(index0 + AGGREGATION_SPAN);
|
|
const index1Unset = indexData[index1 + AGGREGATION_INDEX_X_MIN] === AGGREGATION_INDEX_UNSET;
|
|
const xMinAggIndex = index1Unset || valueData[index0 + AGGREGATION_INDEX_X_MIN] < valueData[index1 + AGGREGATION_INDEX_X_MIN] ? index0 : index1;
|
|
const xMinIndex = indexData[xMinAggIndex + AGGREGATION_INDEX_X_MIN];
|
|
nextIndexData[aggIndex + AGGREGATION_INDEX_X_MIN] = xMinIndex;
|
|
nextValueData[aggIndex + AGGREGATION_INDEX_X_MIN] = valueData[xMinAggIndex + AGGREGATION_INDEX_X_MIN];
|
|
const xMaxAggIndex = index1Unset || valueData[index0 + AGGREGATION_INDEX_X_MAX] > valueData[index1 + AGGREGATION_INDEX_X_MAX] ? index0 : index1;
|
|
const xMaxIndex = indexData[xMaxAggIndex + AGGREGATION_INDEX_X_MAX];
|
|
nextIndexData[aggIndex + AGGREGATION_INDEX_X_MAX] = xMaxIndex;
|
|
nextValueData[aggIndex + AGGREGATION_INDEX_X_MAX] = valueData[xMaxAggIndex + AGGREGATION_INDEX_X_MAX];
|
|
nextMidpointData[i] = xMinIndex + xMaxIndex >> 1;
|
|
const yMinAggIndex = index1Unset || valueData[index0 + AGGREGATION_INDEX_Y_MIN] < valueData[index1 + AGGREGATION_INDEX_Y_MIN] ? index0 : index1;
|
|
nextIndexData[aggIndex + AGGREGATION_INDEX_Y_MIN] = indexData[yMinAggIndex + AGGREGATION_INDEX_Y_MIN];
|
|
nextValueData[aggIndex + AGGREGATION_INDEX_Y_MIN] = valueData[yMinAggIndex + AGGREGATION_INDEX_Y_MIN];
|
|
const yMaxAggIndex = index1Unset || valueData[index0 + AGGREGATION_INDEX_Y_MAX] > valueData[index1 + AGGREGATION_INDEX_Y_MAX] ? index0 : index1;
|
|
nextIndexData[aggIndex + AGGREGATION_INDEX_Y_MAX] = indexData[yMaxAggIndex + AGGREGATION_INDEX_Y_MAX];
|
|
nextValueData[aggIndex + AGGREGATION_INDEX_Y_MAX] = valueData[yMaxAggIndex + AGGREGATION_INDEX_Y_MAX];
|
|
}
|
|
return {
|
|
maxRange: nextMaxRange,
|
|
indexData: nextIndexData,
|
|
valueData: nextValueData,
|
|
midpointData: nextMidpointData
|
|
};
|
|
}
|
|
function getMidpointsForIndices(maxRange, indexData, reuseMidpointData, xMinOffset = AGGREGATION_INDEX_X_MIN, xMaxOffset = AGGREGATION_INDEX_X_MAX, invalidSentinel = -1) {
|
|
const midpoints = reuseMidpointData?.length === maxRange ? reuseMidpointData : new Uint32Array(maxRange);
|
|
for (let i = 0, offset = 0; i < maxRange; i += 1, offset += AGGREGATION_SPAN) {
|
|
const xMin = indexData[offset + xMinOffset];
|
|
const xMax = indexData[offset + xMaxOffset];
|
|
midpoints[i] = xMin === invalidSentinel ? invalidSentinel : xMin + xMax >> 1;
|
|
}
|
|
return midpoints;
|
|
}
|
|
function collectAggregationLevels(state, {
|
|
collectLevel,
|
|
shouldContinue,
|
|
minRange = AGGREGATION_MIN_RANGE,
|
|
compactInPlace = false
|
|
}) {
|
|
let aggregationState = state;
|
|
let level = collectLevel(aggregationState);
|
|
const levels = [level];
|
|
while (aggregationState.maxRange > minRange && shouldContinue(level, aggregationState)) {
|
|
const compacted = compactAggregationIndices(
|
|
aggregationState.indexData,
|
|
aggregationState.valueData,
|
|
aggregationState.maxRange,
|
|
{ inPlace: compactInPlace }
|
|
);
|
|
aggregationState = {
|
|
maxRange: compacted.maxRange,
|
|
indexData: compacted.indexData,
|
|
valueData: compacted.valueData,
|
|
midpointData: compacted.midpointData
|
|
};
|
|
level = collectLevel(aggregationState);
|
|
levels.push(level);
|
|
}
|
|
levels.reverse();
|
|
return levels;
|
|
}
|
|
function computeExtremesAggregation(domain, xValues, highValues, lowValues, options) {
|
|
if (xValues.length < AGGREGATION_THRESHOLD)
|
|
return;
|
|
const [d0, d1] = domain;
|
|
const { smallestKeyInterval, xNeedsValueOf, yNeedsValueOf, existingFilters } = options;
|
|
let maxRange = aggregationRangeFittingPoints(xValues, d0, d1, { smallestKeyInterval, xNeedsValueOf });
|
|
const existingFilter = existingFilters?.find((f) => f.maxRange === maxRange);
|
|
let { indexData, valueData } = createAggregationIndices(xValues, highValues, lowValues, d0, d1, maxRange, {
|
|
xNeedsValueOf,
|
|
yNeedsValueOf,
|
|
reuseIndexData: existingFilter?.indexData,
|
|
reuseValueData: existingFilter?.valueData
|
|
});
|
|
let midpointIndices = getMidpointsForIndices(maxRange, indexData, existingFilter?.midpointIndices);
|
|
const filters = [
|
|
{
|
|
maxRange,
|
|
indexData,
|
|
valueData,
|
|
midpointIndices
|
|
}
|
|
];
|
|
while (maxRange > AGGREGATION_MIN_RANGE) {
|
|
const currentMaxRange = maxRange;
|
|
const nextMaxRange = Math.trunc(currentMaxRange / 2);
|
|
const nextExistingFilter = existingFilters?.find((f) => f.maxRange === nextMaxRange);
|
|
const compacted = compactAggregationIndices(indexData, valueData, currentMaxRange, {
|
|
reuseIndexData: nextExistingFilter?.indexData,
|
|
reuseValueData: nextExistingFilter?.valueData
|
|
});
|
|
maxRange = compacted.maxRange;
|
|
indexData = compacted.indexData;
|
|
valueData = compacted.valueData;
|
|
midpointIndices = compacted.midpointData ?? getMidpointsForIndices(maxRange, indexData, nextExistingFilter?.midpointIndices);
|
|
filters.push({
|
|
maxRange,
|
|
indexData,
|
|
valueData,
|
|
midpointIndices
|
|
});
|
|
}
|
|
filters.reverse();
|
|
return filters;
|
|
}
|
|
function computeExtremesAggregationPartial(domain, xValues, highValues, lowValues, options) {
|
|
if (xValues.length < AGGREGATION_THRESHOLD)
|
|
return;
|
|
const [d0, d1] = domain;
|
|
const { smallestKeyInterval, targetRange, xNeedsValueOf, yNeedsValueOf, existingFilters } = options;
|
|
const finestMaxRange = aggregationRangeFittingPoints(xValues, d0, d1, { smallestKeyInterval, xNeedsValueOf });
|
|
const targetMaxRange = Math.min(finestMaxRange, nextPowerOf2(Math.max(targetRange, AGGREGATION_MIN_RANGE)));
|
|
const existingFilter = existingFilters?.find((f) => f.maxRange === targetMaxRange);
|
|
const { indexData, valueData } = createAggregationIndices(xValues, highValues, lowValues, d0, d1, targetMaxRange, {
|
|
xNeedsValueOf,
|
|
yNeedsValueOf,
|
|
reuseIndexData: existingFilter?.indexData,
|
|
reuseValueData: existingFilter?.valueData
|
|
});
|
|
const midpointIndices = getMidpointsForIndices(targetMaxRange, indexData, existingFilter?.midpointIndices);
|
|
const immediateLevel = {
|
|
maxRange: targetMaxRange,
|
|
indexData,
|
|
valueData,
|
|
midpointIndices
|
|
};
|
|
function computeRemaining() {
|
|
const allLevels = computeExtremesAggregation([d0, d1], xValues, highValues, lowValues, {
|
|
smallestKeyInterval,
|
|
xNeedsValueOf,
|
|
yNeedsValueOf,
|
|
existingFilters
|
|
});
|
|
return allLevels?.filter((level) => level.maxRange !== targetMaxRange) ?? [];
|
|
}
|
|
return { immediate: [immediateLevel], computeRemaining };
|
|
}
|
|
|
|
// packages/ag-charts-core/src/types/themeSymbols.ts
|
|
var IS_DARK_THEME = Symbol("is-dark-theme");
|
|
var DEFAULT_SHADOW_COLOUR = Symbol("default-shadow-colour");
|
|
var DEFAULT_CAPTION_LAYOUT_STYLE = Symbol("default-caption-layout-style");
|
|
var DEFAULT_CAPTION_ALIGNMENT = Symbol("default-caption-alignment");
|
|
var PALETTE_UP_STROKE = Symbol("palette-up-stroke");
|
|
var PALETTE_DOWN_STROKE = Symbol("palette-down-stroke");
|
|
var PALETTE_UP_FILL = Symbol("palette-up-fill");
|
|
var PALETTE_DOWN_FILL = Symbol("palette-down-fill");
|
|
var PALETTE_NEUTRAL_STROKE = Symbol("palette-neutral-stroke");
|
|
var PALETTE_NEUTRAL_FILL = Symbol("palette-neutral-fill");
|
|
var PALETTE_ALT_UP_STROKE = Symbol("palette-alt-up-stroke");
|
|
var PALETTE_ALT_DOWN_STROKE = Symbol("palette-alt-down-stroke");
|
|
var PALETTE_ALT_UP_FILL = Symbol("palette-alt-up-fill");
|
|
var PALETTE_ALT_DOWN_FILL = Symbol("palette-alt-down-fill");
|
|
var PALETTE_ALT_NEUTRAL_FILL = Symbol("palette-gray-fill");
|
|
var PALETTE_ALT_NEUTRAL_STROKE = Symbol("palette-gray-stroke");
|
|
var DEFAULT_POLAR_SERIES_STROKE = Symbol("default-polar-series-stroke");
|
|
var DEFAULT_SPARKLINE_CROSSHAIR_STROKE = Symbol("default-sparkline-crosshair-stroke");
|
|
var DEFAULT_FINANCIAL_CHARTS_ANNOTATION_COLOR = Symbol(
|
|
"default-financial-charts-annotation-stroke"
|
|
);
|
|
var DEFAULT_FIBONACCI_STROKES = Symbol("default-hierarchy-strokes");
|
|
var DEFAULT_TEXT_ANNOTATION_COLOR = Symbol("default-text-annotation-color");
|
|
var DEFAULT_FINANCIAL_CHARTS_ANNOTATION_BACKGROUND_FILL = Symbol(
|
|
"default-financial-charts-annotation-background-fill"
|
|
);
|
|
var DEFAULT_ANNOTATION_HANDLE_FILL = Symbol("default-annotation-handle-fill");
|
|
var DEFAULT_ANNOTATION_STATISTICS_FILL = Symbol("default-annotation-statistics-fill");
|
|
var DEFAULT_ANNOTATION_STATISTICS_STROKE = Symbol("default-annotation-statistics-stroke");
|
|
var DEFAULT_ANNOTATION_STATISTICS_COLOR = Symbol("default-annotation-statistics-color");
|
|
var DEFAULT_ANNOTATION_STATISTICS_DIVIDER_STROKE = Symbol(
|
|
"default-annotation-statistics-divider-stroke"
|
|
);
|
|
var DEFAULT_ANNOTATION_STATISTICS_DOWN_FILL = Symbol(
|
|
"default-annotation-statistics-fill"
|
|
);
|
|
var DEFAULT_ANNOTATION_STATISTICS_DOWN_STROKE = Symbol(
|
|
"default-annotation-statistics-stroke"
|
|
);
|
|
var DEFAULT_TEXTBOX_FILL = Symbol("default-textbox-fill");
|
|
var DEFAULT_TEXTBOX_STROKE = Symbol("default-textbox-stroke");
|
|
var DEFAULT_TEXTBOX_COLOR = Symbol("default-textbox-color");
|
|
var DEFAULT_TOOLBAR_POSITION = Symbol("default-toolbar-position");
|
|
|
|
// packages/ag-charts-core/src/state/callbackCache.ts
|
|
function needsContext(caller, _params) {
|
|
return "context" in caller;
|
|
}
|
|
function maybeSetContext(caller, params) {
|
|
if (caller != null && needsContext(caller, params)) {
|
|
if (params != null && typeof params === "object" && params.context === void 0) {
|
|
params.context = caller.context;
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
function callWithContext(callers, fn, params) {
|
|
if (Array.isArray(callers)) {
|
|
for (const caller of callers) {
|
|
if (maybeSetContext(caller, params)) {
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
maybeSetContext(callers, params);
|
|
}
|
|
return fn(params);
|
|
}
|
|
var CallbackCache = class {
|
|
constructor() {
|
|
this.cache = /* @__PURE__ */ new WeakMap();
|
|
}
|
|
call(callers, fn, params) {
|
|
let serialisedParams;
|
|
let paramCache = this.cache.get(fn);
|
|
try {
|
|
serialisedParams = JSON.stringify(params);
|
|
} catch {
|
|
return this.invoke(callers, fn, paramCache, void 0, params);
|
|
}
|
|
if (paramCache == null) {
|
|
paramCache = /* @__PURE__ */ new Map();
|
|
this.cache.set(fn, paramCache);
|
|
}
|
|
if (!paramCache.has(serialisedParams)) {
|
|
return this.invoke(callers, fn, paramCache, serialisedParams, params);
|
|
}
|
|
return paramCache.get(serialisedParams);
|
|
}
|
|
invoke(callers, fn, paramCache, serialisedParams, params) {
|
|
try {
|
|
const result = callWithContext(callers, fn, params);
|
|
if (paramCache && serialisedParams != null) {
|
|
paramCache.set(serialisedParams, result);
|
|
}
|
|
return result;
|
|
} catch (e) {
|
|
warnOnce(`User callback errored, ignoring`, e);
|
|
return;
|
|
}
|
|
}
|
|
invalidateCache() {
|
|
this.cache = /* @__PURE__ */ new WeakMap();
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-core/src/utils/dom/domUtil.ts
|
|
function setElementBBox(element, bbox) {
|
|
if (!element)
|
|
return;
|
|
const { x, y, width: width2, height: height2 } = normalizeBounds(bbox);
|
|
setPixelValue(element.style, "width", width2);
|
|
setPixelValue(element.style, "height", height2);
|
|
setPixelValue(element.style, "left", x);
|
|
setPixelValue(element.style, "top", y);
|
|
}
|
|
function getElementBBox(element) {
|
|
const styleWidth = Number.parseFloat(element.style.width);
|
|
const styleHeight = Number.parseFloat(element.style.height);
|
|
const styleX = Number.parseFloat(element.style.left);
|
|
const styleY = Number.parseFloat(element.style.top);
|
|
const width2 = Number.isFinite(styleWidth) ? styleWidth : element.offsetWidth;
|
|
const height2 = Number.isFinite(styleHeight) ? styleHeight : element.offsetHeight;
|
|
const x = Number.isFinite(styleX) ? styleX : element.offsetLeft;
|
|
const y = Number.isFinite(styleY) ? styleY : element.offsetTop;
|
|
return { x, y, width: width2, height: height2 };
|
|
}
|
|
function focusCursorAtEnd(element) {
|
|
element.focus({ preventScroll: true });
|
|
if (element.lastChild?.textContent == null)
|
|
return;
|
|
const range2 = getDocument().createRange();
|
|
range2.setStart(element.lastChild, element.lastChild.textContent.length);
|
|
range2.setEnd(element.lastChild, element.lastChild.textContent.length);
|
|
const selection = getWindow().getSelection();
|
|
selection?.removeAllRanges();
|
|
selection?.addRange(range2);
|
|
}
|
|
function isInputPending() {
|
|
const navigator = getWindow("navigator");
|
|
if ("scheduling" in navigator) {
|
|
const scheduling = navigator.scheduling;
|
|
if ("isInputPending" in scheduling) {
|
|
return scheduling.isInputPending({ includeContinuous: true });
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
function getIconClassNames(icon) {
|
|
return `ag-charts-icon ag-charts-icon-${icon}`;
|
|
}
|
|
function normalizeBounds(bbox) {
|
|
let { x, y, width: width2, height: height2 } = bbox;
|
|
if ((width2 == null || width2 > 0) && (height2 == null || height2 > 0)) {
|
|
return bbox;
|
|
}
|
|
if (x != null && width2 != null && width2 < 0) {
|
|
width2 = -width2;
|
|
x = x - width2;
|
|
}
|
|
if (y != null && height2 != null && height2 < 0) {
|
|
height2 = -height2;
|
|
y = y - height2;
|
|
}
|
|
return { x, y, width: width2, height: height2 };
|
|
}
|
|
function setPixelValue(style2, key, value) {
|
|
if (value == null) {
|
|
style2.removeProperty(key);
|
|
} else {
|
|
style2.setProperty(key, `${value}px`);
|
|
}
|
|
}
|
|
|
|
// packages/ag-charts-core/src/utils/geometry/math/shapeUtils.ts
|
|
function getMaxInnerRectSize(rotationDeg, containerWidth, containerHeight = Infinity) {
|
|
const W = containerWidth;
|
|
const H = containerHeight;
|
|
const angle2 = rotationDeg % 180 * (Math.PI / 180);
|
|
const sin = Math.abs(Math.sin(angle2));
|
|
const cos = Math.abs(Math.cos(angle2));
|
|
if (sin === 0)
|
|
return { width: W, height: H };
|
|
if (cos === 0)
|
|
return { width: H, height: W };
|
|
if (!Number.isFinite(H)) {
|
|
const r = cos / sin;
|
|
const width2 = W / (cos + r * sin);
|
|
return { width: width2, height: r * width2 };
|
|
}
|
|
const denominator = cos * cos - sin * sin;
|
|
if (denominator === 0) {
|
|
const side = Math.min(W, H) / Math.SQRT2;
|
|
return { width: side, height: side };
|
|
}
|
|
return {
|
|
width: Math.abs((W * cos - H * sin) / denominator),
|
|
height: Math.abs((H * cos - W * sin) / denominator)
|
|
};
|
|
}
|
|
function getMinOuterRectSize(rotationDeg, innerWidth, innerHeight = Infinity) {
|
|
const w = innerWidth;
|
|
const h = innerHeight;
|
|
const angle2 = rotationDeg % 180 * (Math.PI / 180);
|
|
const sin = Math.abs(Math.sin(angle2));
|
|
const cos = Math.abs(Math.cos(angle2));
|
|
if (sin === 0)
|
|
return { width: w, height: h };
|
|
if (cos === 0)
|
|
return { width: h, height: w };
|
|
return {
|
|
width: w * cos + h * sin,
|
|
height: w * sin + h * cos
|
|
};
|
|
}
|
|
function rotatePoint(x, y, angle2, originX = 0, originY = 0) {
|
|
const cos = Math.cos(angle2);
|
|
const sin = Math.sin(angle2);
|
|
const dx = x - originX;
|
|
const dy = y - originY;
|
|
return {
|
|
x: originX + dx * cos - dy * sin,
|
|
y: originY + dx * sin + dy * cos
|
|
};
|
|
}
|
|
|
|
// packages/ag-charts-core/src/utils/geometry/angle.ts
|
|
var twoPi = Math.PI * 2;
|
|
var halfPi = Math.PI / 2;
|
|
function normalizeAngle360(radians) {
|
|
radians %= twoPi;
|
|
radians += twoPi;
|
|
radians %= twoPi;
|
|
return radians;
|
|
}
|
|
function normalizeAngle360Inclusive(radians) {
|
|
radians %= twoPi;
|
|
radians += twoPi;
|
|
if (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 startAngle !== endAngle;
|
|
}
|
|
}
|
|
function toRadians(degrees) {
|
|
return degrees / 180 * Math.PI;
|
|
}
|
|
function toDegrees(radians) {
|
|
return radians / Math.PI * 180;
|
|
}
|
|
function angleBetween(angle0, angle1) {
|
|
angle0 = normalizeAngle360(angle0);
|
|
angle1 = normalizeAngle360(angle1);
|
|
return angle1 - angle0 + (angle0 > angle1 ? twoPi : 0);
|
|
}
|
|
function getAngleRatioRadians(angle2) {
|
|
const normalizedAngle = normalizeAngle360(angle2);
|
|
if (normalizedAngle <= halfPi) {
|
|
return normalizedAngle / halfPi;
|
|
} else if (normalizedAngle <= Math.PI) {
|
|
return (Math.PI - normalizedAngle) / halfPi;
|
|
} else if (normalizedAngle <= 1.5 * Math.PI) {
|
|
return (normalizedAngle - Math.PI) / halfPi;
|
|
} else {
|
|
return (twoPi - normalizedAngle) / halfPi;
|
|
}
|
|
}
|
|
function angularPadding(hPadding, vPadding, angle2) {
|
|
const angleRatio = getAngleRatioRadians(angle2);
|
|
return hPadding * angleRatio + vPadding * Math.abs(1 - angleRatio);
|
|
}
|
|
function normalizeAngle360FromDegrees(degrees) {
|
|
return degrees ? normalizeAngle360(toRadians(degrees)) : 0;
|
|
}
|
|
|
|
// packages/ag-charts-core/src/utils/async.ts
|
|
var AsyncAwaitQueue = class {
|
|
constructor() {
|
|
this.queue = [];
|
|
}
|
|
/** Await another async process to call notify(). */
|
|
waitForCompletion(timeout = 50) {
|
|
const queue = this.queue;
|
|
function createCompletionPromise(resolve) {
|
|
function successFn() {
|
|
clearTimeout(timeoutHandle);
|
|
resolve(true);
|
|
}
|
|
function timeoutFn() {
|
|
const queueIndex = queue.indexOf(successFn);
|
|
if (queueIndex < 0)
|
|
return;
|
|
queue.splice(queueIndex, 1);
|
|
resolve(false);
|
|
}
|
|
const timeoutHandle = setTimeout(timeoutFn, timeout);
|
|
queue.push(successFn);
|
|
}
|
|
return new Promise(createCompletionPromise);
|
|
}
|
|
/** Trigger any await()ing async processes to continue. */
|
|
notify() {
|
|
for (const cb of this.queue.splice(0)) {
|
|
cb();
|
|
}
|
|
}
|
|
};
|
|
function pause(delayMilliseconds = 0) {
|
|
function resolveAfterDelay(resolve) {
|
|
setTimeout(resolve, delayMilliseconds);
|
|
}
|
|
return new Promise(resolveAfterDelay);
|
|
}
|
|
async function withTimeout(promise, timeoutMs, errorMessage = `Timeout after ${timeoutMs}ms`) {
|
|
let timer;
|
|
const timeoutPromise = new Promise((_, reject) => {
|
|
timer = setTimeout(() => reject(new Error(errorMessage)), timeoutMs);
|
|
});
|
|
try {
|
|
return await Promise.race([promise, timeoutPromise]);
|
|
} finally {
|
|
clearTimeout(timer);
|
|
}
|
|
}
|
|
|
|
// packages/ag-charts-core/src/utils/dom/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 (!isHTMLElement(e))
|
|
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/state/proxy.ts
|
|
function ProxyProperty(proxyPath, configMetadata) {
|
|
const pathArray = Array.isArray(proxyPath) ? proxyPath : proxyPath.split(".");
|
|
if (pathArray.length === 1) {
|
|
const [property] = pathArray;
|
|
return addTransformToInstanceProperty(
|
|
(target, _, value) => target[property] = value,
|
|
(target) => target[property],
|
|
configMetadata
|
|
);
|
|
}
|
|
return addTransformToInstanceProperty(
|
|
(target, _, value) => setPath(target, pathArray, value),
|
|
(target) => getPath(target, pathArray),
|
|
configMetadata
|
|
);
|
|
}
|
|
function ProxyOnWrite(proxyProperty) {
|
|
return addTransformToInstanceProperty((target, _, value) => target[proxyProperty] = value);
|
|
}
|
|
function ProxyPropertyOnWrite(childName, childProperty) {
|
|
return addTransformToInstanceProperty((target, key, value) => target[childName][childProperty ?? key] = value);
|
|
}
|
|
function ActionOnSet(opts) {
|
|
const { newValue: newValueFn, oldValue: oldValueFn, changeValue: changeValueFn } = opts;
|
|
return addTransformToInstanceProperty((target, _, newValue, oldValue) => {
|
|
if (newValue !== oldValue) {
|
|
if (oldValue !== void 0) {
|
|
oldValueFn?.call(target, oldValue);
|
|
}
|
|
if (newValue !== void 0) {
|
|
newValueFn?.call(target, newValue);
|
|
}
|
|
changeValueFn?.call(target, newValue, oldValue);
|
|
}
|
|
return newValue;
|
|
});
|
|
}
|
|
function ObserveChanges(observerFn) {
|
|
return addObserverToInstanceProperty(observerFn);
|
|
}
|
|
|
|
// packages/ag-charts-core/src/utils/geometry/border.ts
|
|
var Border = class extends BaseProperties {
|
|
constructor(node) {
|
|
super();
|
|
this.node = node;
|
|
this.enabled = false;
|
|
this.stroke = "black";
|
|
this.strokeOpacity = 1;
|
|
this.strokeWidth = 1;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
ActionOnSet({
|
|
changeValue(newValue) {
|
|
if (newValue) {
|
|
this.node.strokeWidth = this.strokeWidth;
|
|
} else {
|
|
this.node.strokeWidth = 0;
|
|
}
|
|
}
|
|
}),
|
|
addFakeTransformToInstanceProperty
|
|
], Border.prototype, "enabled", 2);
|
|
__decorateClass([
|
|
ProxyPropertyOnWrite("node", "stroke"),
|
|
addFakeTransformToInstanceProperty
|
|
], Border.prototype, "stroke", 2);
|
|
__decorateClass([
|
|
ProxyPropertyOnWrite("node", "strokeOpacity"),
|
|
addFakeTransformToInstanceProperty
|
|
], Border.prototype, "strokeOpacity", 2);
|
|
__decorateClass([
|
|
ActionOnSet({
|
|
changeValue(newValue) {
|
|
if (this.enabled) {
|
|
this.node.strokeWidth = newValue;
|
|
} else {
|
|
this.node.strokeWidth = 0;
|
|
}
|
|
}
|
|
}),
|
|
addFakeTransformToInstanceProperty
|
|
], Border.prototype, "strokeWidth", 2);
|
|
|
|
// packages/ag-charts-core/src/utils/geometry/boxBounds.ts
|
|
function boxCollides(b, x, y, w, h) {
|
|
return x < b.x + b.width && x + w > b.x && y < b.y + b.height && y + h > b.y;
|
|
}
|
|
function boxContains(b, x, y, w = 0, h = 0) {
|
|
return x >= b.x && x + w <= b.x + b.width && y >= b.y && y + h <= b.y + b.height;
|
|
}
|
|
function boxEmpty(b) {
|
|
return b == null || b.height === 0 || b.width === 0 || Number.isNaN(b.height) || Number.isNaN(b.width);
|
|
}
|
|
function boxesEqual(a, b) {
|
|
if (a === b)
|
|
return true;
|
|
if (a == null || b == null)
|
|
return false;
|
|
return a.x === b.x && a.y === b.y && a.width === b.width && a.height === b.height;
|
|
}
|
|
|
|
// packages/ag-charts-core/src/utils/data/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/canvas.ts
|
|
function createCanvasContext(width2 = 0, height2 = 0) {
|
|
const OffscreenCanvasCtor = getOffscreenCanvas();
|
|
return new OffscreenCanvasCtor(width2, height2).getContext("2d");
|
|
}
|
|
|
|
// packages/ag-charts-core/src/utils/configuredCanvasMixin.ts
|
|
var CANVAS_WIDTH = 800;
|
|
var CANVAS_HEIGHT = 600;
|
|
var CANVAS_TO_BUFFER_DEFAULTS = { quality: 1 };
|
|
function ConfiguredCanvasMixin(Base) {
|
|
const ConfiguredCanvasClass = class ConfiguredCanvas extends Base {
|
|
constructor(...args) {
|
|
super(...args);
|
|
this.gpu = false;
|
|
}
|
|
toBuffer(format, options) {
|
|
return super.toBuffer(format, { ...options, msaa: false });
|
|
}
|
|
transferToImageBitmap() {
|
|
const { width: width2, height: height2 } = this;
|
|
const bitmap = new ConfiguredCanvasClass(Math.max(1, width2), Math.max(1, height2));
|
|
if (width2 > 0 && height2 > 0) {
|
|
bitmap.getContext("2d").drawCanvas(this, 0, 0, width2, height2);
|
|
}
|
|
Object.defineProperty(bitmap, "close", {
|
|
value: () => {
|
|
}
|
|
});
|
|
return bitmap;
|
|
}
|
|
};
|
|
return ConfiguredCanvasClass;
|
|
}
|
|
var patchesApplied = false;
|
|
function applySkiaPatches(CanvasRenderingContext2D, DOMMatrix) {
|
|
if (patchesApplied)
|
|
return;
|
|
patchesApplied = true;
|
|
const superCreateConicGradient = CanvasRenderingContext2D.prototype.createConicGradient;
|
|
Object.defineProperty(CanvasRenderingContext2D.prototype, "createConicGradient", {
|
|
value: function(angle2, x, y) {
|
|
return superCreateConicGradient.call(this, angle2 + Math.PI / 2, x, y);
|
|
},
|
|
writable: true,
|
|
configurable: true
|
|
});
|
|
Object.defineProperty(CanvasRenderingContext2D.prototype, "fillText", {
|
|
value: function(text, x, y) {
|
|
let path2d = this.outlineText(text);
|
|
path2d = path2d.transform(new DOMMatrix([1, 0, 0, 1, x, y]));
|
|
this.fill(path2d);
|
|
},
|
|
writable: true,
|
|
configurable: true
|
|
});
|
|
}
|
|
|
|
// packages/ag-charts-core/src/state/caching.ts
|
|
var SimpleCache = class {
|
|
constructor(getter) {
|
|
this.getter = getter;
|
|
}
|
|
get() {
|
|
this.result ?? (this.result = this.getter());
|
|
return this.result;
|
|
}
|
|
clear() {
|
|
this.result = void 0;
|
|
}
|
|
};
|
|
var WeakCache = class {
|
|
constructor(getter) {
|
|
this.getter = getter;
|
|
}
|
|
get() {
|
|
let result = this.result?.deref();
|
|
if (result)
|
|
return result;
|
|
result = this.getter();
|
|
this.result = new WeakRef(result);
|
|
return result;
|
|
}
|
|
clear() {
|
|
this.result = void 0;
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-core/src/utils/time/date.ts
|
|
function compareDates(a, b) {
|
|
return a.valueOf() - b.valueOf();
|
|
}
|
|
function deduplicateSortedArray(values) {
|
|
let v0 = Number.NaN;
|
|
const out = [];
|
|
for (const v of values) {
|
|
const v1 = v.valueOf();
|
|
if (v0 !== v1)
|
|
out.push(v);
|
|
v0 = v1;
|
|
}
|
|
return out;
|
|
}
|
|
function sortAndUniqueDates(values) {
|
|
const sortedValues = values.slice().sort(compareDates);
|
|
return datesSortOrder(sortedValues) == null ? deduplicateSortedArray(sortedValues) : sortedValues;
|
|
}
|
|
function datesSortOrder(d) {
|
|
if (d.length === 0)
|
|
return 1;
|
|
const sign = Number(d.at(-1)) > Number(d[0]) ? 1 : -1;
|
|
let v0 = -Infinity * sign;
|
|
for (const v of d) {
|
|
const v1 = v.valueOf();
|
|
if (Math.sign(v1 - v0) !== sign)
|
|
return;
|
|
v0 = v1;
|
|
}
|
|
return sign;
|
|
}
|
|
|
|
// packages/ag-charts-core/src/utils/deprecation.ts
|
|
function createDeprecationWarning() {
|
|
return (key, message) => {
|
|
const msg = [`Property [${key}] is deprecated.`, message].filter(Boolean).join(" ");
|
|
warnOnce(msg);
|
|
};
|
|
}
|
|
function Deprecated(message, opts) {
|
|
const warnDeprecated = createDeprecationWarning();
|
|
const def = opts?.default;
|
|
return addTransformToInstanceProperty((_, key, value) => {
|
|
if (value !== def) {
|
|
warnDeprecated(key.toString(), message);
|
|
}
|
|
return value;
|
|
});
|
|
}
|
|
function DeprecatedAndRenamedTo(newPropName, mapValue) {
|
|
const warnDeprecated = createDeprecationWarning();
|
|
return addTransformToInstanceProperty(
|
|
(target, key, value) => {
|
|
if (value !== target[newPropName]) {
|
|
warnDeprecated(key.toString(), `Use [${newPropName}] instead.`);
|
|
setPath(target, newPropName, mapValue ? mapValue(value) : value);
|
|
}
|
|
return BREAK_TRANSFORM_CHAIN;
|
|
},
|
|
(target, key) => {
|
|
warnDeprecated(key.toString(), `Use [${newPropName}] instead.`);
|
|
return getPath(target, newPropName);
|
|
}
|
|
);
|
|
}
|
|
|
|
// packages/ag-charts-core/src/utils/data/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/geometry/distance.ts
|
|
function pointsDistanceSquared(x1, y1, x2, y2) {
|
|
const dx = x1 - x2;
|
|
const dy = y1 - y2;
|
|
return dx * dx + dy * dy;
|
|
}
|
|
function lineDistanceSquared(x, y, x1, y1, x2, y2, best) {
|
|
if (x1 === x2 && y1 === y2) {
|
|
return Math.min(best, pointsDistanceSquared(x, y, x1, y1));
|
|
}
|
|
const dx = x2 - x1;
|
|
const dy = y2 - y1;
|
|
const t = Math.max(0, Math.min(1, ((x - x1) * dx + (y - y1) * dy) / (dx * dx + dy * dy)));
|
|
const ix = x1 + t * dx;
|
|
const iy = y1 + t * dy;
|
|
return Math.min(best, pointsDistanceSquared(x, y, ix, iy));
|
|
}
|
|
function arcDistanceSquared(x, y, cx, cy, radius, startAngle, endAngle, counterClockwise, best) {
|
|
if (counterClockwise) {
|
|
[endAngle, startAngle] = [startAngle, endAngle];
|
|
}
|
|
const angle2 = Math.atan2(y - cy, x - cx);
|
|
if (!isBetweenAngles(angle2, startAngle, endAngle)) {
|
|
const startX = cx + Math.cos(startAngle) * radius;
|
|
const startY = cy + Math.sin(startAngle) * radius;
|
|
const endX = cx + Math.cos(startAngle) * radius;
|
|
const endY = cy + Math.sin(startAngle) * radius;
|
|
return Math.min(best, pointsDistanceSquared(x, y, startX, startY), pointsDistanceSquared(x, y, endX, endY));
|
|
}
|
|
const distToArc = radius - Math.sqrt(pointsDistanceSquared(x, y, cx, cy));
|
|
return Math.min(best, distToArc * distToArc);
|
|
}
|
|
|
|
// packages/ag-charts-core/src/utils/data/extent.ts
|
|
function extent(values, sortOrder) {
|
|
if (values.length === 0) {
|
|
return null;
|
|
}
|
|
if (sortOrder !== void 0) {
|
|
const first2 = values.at(0);
|
|
const last = values.at(-1);
|
|
const v0 = first2 instanceof Date ? first2.getTime() : first2;
|
|
const v1 = last instanceof Date ? last.getTime() : last;
|
|
if (typeof v0 === "number" && typeof v1 === "number") {
|
|
return sortOrder === 1 ? [v0, v1] : [v1, v0];
|
|
}
|
|
}
|
|
let min = Infinity;
|
|
let max = -Infinity;
|
|
for (const n of values) {
|
|
const v = n instanceof Date ? n.getTime() : n;
|
|
if (typeof v !== "number")
|
|
continue;
|
|
if (v < min) {
|
|
min = v;
|
|
}
|
|
if (v > max) {
|
|
max = v;
|
|
}
|
|
}
|
|
const result = [min, max];
|
|
return result.every(Number.isFinite) ? result : null;
|
|
}
|
|
function normalisedExtentWithMetadata(d, min, max, preferredMin, preferredMax, toValue, sortOrder) {
|
|
let clipped = false;
|
|
const domainExtentNumbers = extent(d, sortOrder);
|
|
const domainExtent = domainExtentNumbers && toValue ? [toValue(domainExtentNumbers[0]), toValue(domainExtentNumbers[1])] : domainExtentNumbers;
|
|
if (domainExtent == null) {
|
|
let nullExtent;
|
|
if (min != null && max != null && min <= max) {
|
|
nullExtent = [min, max];
|
|
} else if (preferredMin != null && preferredMax != null && preferredMin <= preferredMax) {
|
|
nullExtent = [preferredMin, preferredMax];
|
|
}
|
|
return { extent: nullExtent ?? [], clipped: false };
|
|
}
|
|
let [d0, d1] = domainExtent;
|
|
if (min != null) {
|
|
clipped || (clipped = min > d0);
|
|
d0 = min;
|
|
} else if (preferredMin != null && preferredMin < d0) {
|
|
d0 = preferredMin;
|
|
}
|
|
if (max != null) {
|
|
clipped || (clipped = max < d1);
|
|
d1 = max;
|
|
} else if (preferredMax != null && preferredMax > d1) {
|
|
d1 = preferredMax;
|
|
}
|
|
if (d0 > d1) {
|
|
return { extent: [], clipped: false };
|
|
}
|
|
return { extent: [d0, d1], clipped };
|
|
}
|
|
function normalisedTimeExtentWithMetadata(input, min, max, preferredMin, preferredMax) {
|
|
const { extent: e, clipped } = normalisedExtentWithMetadata(
|
|
input.domain,
|
|
isNumber(min) ? new Date(min) : min,
|
|
isNumber(max) ? new Date(max) : max,
|
|
isNumber(preferredMin) ? new Date(preferredMin) : preferredMin,
|
|
isNumber(preferredMax) ? new Date(preferredMax) : preferredMax,
|
|
(x) => new Date(x),
|
|
input.sortMetadata?.sortOrder
|
|
);
|
|
return { extent: e.map((x) => new Date(x)), clipped };
|
|
}
|
|
|
|
// packages/ag-charts-core/src/utils/format/format.util.ts
|
|
var percentFormatter = new Intl.NumberFormat("en-US", { style: "percent" });
|
|
function formatValue(value, maximumFractionDigits = 2) {
|
|
if (typeof value === "number") {
|
|
return formatNumber(value, maximumFractionDigits);
|
|
}
|
|
return typeof value === "string" ? value : String(value ?? "");
|
|
}
|
|
function formatPercent(value) {
|
|
return percentFormatter.format(value);
|
|
}
|
|
var numberFormatters = (/* @__PURE__ */ new Map()).set(
|
|
2,
|
|
new Intl.NumberFormat("en-US", { maximumFractionDigits: 2, useGrouping: false })
|
|
);
|
|
function formatNumber(value, maximumFractionDigits) {
|
|
let formatter2 = numberFormatters.get(maximumFractionDigits);
|
|
if (!formatter2) {
|
|
formatter2 = new Intl.NumberFormat("en-US", { maximumFractionDigits, useGrouping: false });
|
|
numberFormatters.set(maximumFractionDigits, formatter2);
|
|
}
|
|
return formatter2.format(value);
|
|
}
|
|
|
|
// 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 start2 = c[0];
|
|
const end2 = c.at(-1);
|
|
if (end2 === void 0)
|
|
return false;
|
|
return isNumberEqual(start2[0], end2[0], 1e-3) && isNumberEqual(start2[1], end2[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.features) && value.features.every(isValidFeature);
|
|
}
|
|
var geoJson = attachDescription(isValidFeatureCollection, "a GeoJSON object");
|
|
|
|
// packages/ag-charts-core/src/structures/graph.ts
|
|
var AdjacencyListGraph = class {
|
|
constructor(cachedNeighboursEdge, processedEdge, singleValueEdges) {
|
|
this._vertexCount = 0;
|
|
this._edgeCount = 0;
|
|
this.pendingProcessingEdgesFrom = [];
|
|
this.pendingProcessingEdgesTo = [];
|
|
this.cachedNeighboursEdge = cachedNeighboursEdge;
|
|
this.processedEdge = processedEdge;
|
|
this.singleValueEdges = singleValueEdges;
|
|
}
|
|
clear() {
|
|
this._vertexCount = 0;
|
|
this._edgeCount = 0;
|
|
this.pendingProcessingEdgesFrom = [];
|
|
this.pendingProcessingEdgesTo = [];
|
|
this.singleValueEdges?.clear();
|
|
}
|
|
getVertexCount() {
|
|
return this._vertexCount;
|
|
}
|
|
getEdgeCount() {
|
|
return this._edgeCount;
|
|
}
|
|
addVertex(value) {
|
|
const vertex = new Vertex(value);
|
|
this._vertexCount++;
|
|
return vertex;
|
|
}
|
|
addEdge(from3, to, edge) {
|
|
if (edge === this.cachedNeighboursEdge) {
|
|
from3.updateCachedNeighbours().set(to.value, to);
|
|
} else if (edge === this.processedEdge) {
|
|
this.pendingProcessingEdgesFrom.push(from3);
|
|
this.pendingProcessingEdgesTo.push(to);
|
|
}
|
|
const { edges } = from3;
|
|
const vertices = edges.get(edge);
|
|
if (!vertices) {
|
|
edges.set(edge, [to]);
|
|
this._edgeCount++;
|
|
} else if (!vertices.includes(to)) {
|
|
if (this.singleValueEdges?.has(edge)) {
|
|
edges.set(edge, [to]);
|
|
} else {
|
|
vertices.push(to);
|
|
this._edgeCount++;
|
|
}
|
|
}
|
|
}
|
|
removeVertex(vertex) {
|
|
this._vertexCount--;
|
|
const edges = vertex.edges;
|
|
if (!edges)
|
|
return;
|
|
for (const [, adjacentVertices] of edges) {
|
|
this._vertexCount -= adjacentVertices.length;
|
|
}
|
|
vertex.clear();
|
|
}
|
|
removeEdge(from3, to, edge) {
|
|
const neighbours = from3.edges.get(edge);
|
|
if (!neighbours)
|
|
return;
|
|
const index = neighbours.indexOf(to);
|
|
if (index === -1)
|
|
return;
|
|
neighbours.splice(index, 1);
|
|
if (neighbours.length === 0) {
|
|
from3.edges.delete(edge);
|
|
}
|
|
this._edgeCount--;
|
|
if (edge === this.cachedNeighboursEdge) {
|
|
from3.readCachedNeighbours()?.delete(to.value);
|
|
}
|
|
}
|
|
removeEdges(from3, edgeValue) {
|
|
from3.edges.delete(edgeValue);
|
|
}
|
|
getVertexValue(vertex) {
|
|
return vertex.value;
|
|
}
|
|
// Iterate all the neighbours of a given vertex.
|
|
*neighbours(from3) {
|
|
for (const [, adjacentVertices] of from3.edges) {
|
|
for (const adjacentVertex of adjacentVertices) {
|
|
yield adjacentVertex;
|
|
}
|
|
}
|
|
}
|
|
// Iterate all the neighbours and their edges of a given vertex
|
|
*neighboursAndEdges(from3) {
|
|
for (const [edge, adjacentVertices] of from3.edges) {
|
|
for (const adjacentVertex of adjacentVertices) {
|
|
yield [adjacentVertex, edge];
|
|
}
|
|
}
|
|
}
|
|
// Get the set of neighbours along a given edge.
|
|
neighboursWithEdgeValue(from3, edgeValue) {
|
|
return from3.edges.get(edgeValue);
|
|
}
|
|
// Find the first neighbour along the given edge.
|
|
findNeighbour(from3, edgeValue) {
|
|
return from3.edges.get(edgeValue)?.[0];
|
|
}
|
|
// Find the value of the first neighbour along the given edge.
|
|
findNeighbourValue(from3, edgeValue) {
|
|
const neighbour = this.findNeighbour(from3, edgeValue);
|
|
if (!neighbour)
|
|
return;
|
|
return this.getVertexValue(neighbour);
|
|
}
|
|
// Find the first neighbour with a given value, optionally along a given edge.
|
|
findNeighbourWithValue(from3, value, edgeValue) {
|
|
const neighbours = edgeValue == null ? this.neighbours(from3) : this.neighboursWithEdgeValue(from3, edgeValue);
|
|
if (!neighbours)
|
|
return;
|
|
for (const neighbour of neighbours) {
|
|
if (this.getVertexValue(neighbour) === value) {
|
|
return neighbour;
|
|
}
|
|
}
|
|
}
|
|
// Find a vertex by iterating an array of vertex values along a given edge.
|
|
findVertexAlongEdge(from3, findValues, edgeValue) {
|
|
if (edgeValue === this.cachedNeighboursEdge) {
|
|
let found2;
|
|
for (const value of findValues) {
|
|
found2 = (found2 ?? from3).readCachedNeighbours()?.get(value);
|
|
if (!found2)
|
|
return;
|
|
}
|
|
return found2;
|
|
}
|
|
if (findValues.length === 0)
|
|
return;
|
|
let found = from3;
|
|
for (const value of findValues) {
|
|
const neighbours = found ? this.neighboursWithEdgeValue(found, edgeValue) : void 0;
|
|
if (!neighbours)
|
|
return;
|
|
found = neighbours.find((n) => n.value === value);
|
|
}
|
|
return found;
|
|
}
|
|
adjacent(from3, to) {
|
|
for (const [, adjacentVertices] of from3.edges) {
|
|
if (adjacentVertices.includes(to))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
};
|
|
var Vertex = class {
|
|
constructor(value) {
|
|
this.value = value;
|
|
this.edges = /* @__PURE__ */ new Map();
|
|
}
|
|
readCachedNeighbours() {
|
|
return this._cachedNeighbours;
|
|
}
|
|
updateCachedNeighbours() {
|
|
this._cachedNeighbours ?? (this._cachedNeighbours = /* @__PURE__ */ new Map());
|
|
return this._cachedNeighbours;
|
|
}
|
|
clear() {
|
|
this.edges.clear();
|
|
this._cachedNeighbours?.clear();
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-core/src/utils/data/json.ts
|
|
var CLASS_INSTANCE_TYPE = "class-instance";
|
|
function jsonDiff(source, target, shallow) {
|
|
if (isArray(target)) {
|
|
if (!isArray(source) || source.length !== target.length || target.some((v, i) => jsonDiff(source[i], v, shallow) != null)) {
|
|
return target;
|
|
}
|
|
} else if (isPlainObject(target)) {
|
|
if (!isPlainObject(source)) {
|
|
return target;
|
|
}
|
|
const result = {};
|
|
const allKeys = /* @__PURE__ */ new Set([
|
|
...Object.keys(source),
|
|
...Object.keys(target)
|
|
]);
|
|
for (const key of allKeys) {
|
|
if (source[key] === target[key]) {
|
|
continue;
|
|
} else if (shallow?.has(key)) {
|
|
result[key] = target[key];
|
|
} else if (typeof source[key] === typeof target[key]) {
|
|
const diff = jsonDiff(source[key], target[key], shallow);
|
|
if (diff !== null) {
|
|
result[key] = diff;
|
|
}
|
|
} else {
|
|
result[key] = target[key];
|
|
}
|
|
}
|
|
return Object.keys(result).length ? result : null;
|
|
} else if (source !== target) {
|
|
return target;
|
|
}
|
|
return null;
|
|
}
|
|
function jsonPropertyCompare(source, target) {
|
|
for (const key of Object.keys(source)) {
|
|
if (source[key] === target?.[key])
|
|
continue;
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
function deepClone(source, opts) {
|
|
if (isArray(source)) {
|
|
return cloneArray(source, opts);
|
|
}
|
|
if (isPlainObject(source)) {
|
|
return clonePlainObject(source, opts);
|
|
}
|
|
if (source instanceof Map) {
|
|
return new Map(deepClone(Array.from(source)));
|
|
}
|
|
return shallowClone(source);
|
|
}
|
|
function cloneArray(source, opts) {
|
|
const result = [];
|
|
const seen = opts?.seen;
|
|
for (const item of source) {
|
|
if (typeof item === "object" && seen?.includes(item)) {
|
|
warn("cycle detected in array", item);
|
|
continue;
|
|
}
|
|
seen?.push(item);
|
|
result.push(deepClone(item, opts));
|
|
seen?.pop();
|
|
}
|
|
return result;
|
|
}
|
|
function clonePlainObject(source, opts) {
|
|
const target = {};
|
|
for (const key of Object.keys(source)) {
|
|
if (opts?.assign?.has(key)) {
|
|
target[key] = source[key];
|
|
} else if (opts?.shallow?.has(key)) {
|
|
target[key] = shallowClone(source[key]);
|
|
} else {
|
|
target[key] = deepClone(source[key], opts);
|
|
}
|
|
}
|
|
return target;
|
|
}
|
|
function shallowClone(source) {
|
|
if (isArray(source)) {
|
|
return source.slice(0);
|
|
}
|
|
if (isPlainObject(source)) {
|
|
return { ...source };
|
|
}
|
|
if (isDate(source)) {
|
|
return new Date(source);
|
|
}
|
|
if (isRegExp(source)) {
|
|
return new RegExp(source.source, source.flags);
|
|
}
|
|
return source;
|
|
}
|
|
function jsonWalk(json, visit, skip, parallelJson, ctx, acc) {
|
|
if (isArray(json)) {
|
|
acc = visit(json, parallelJson, ctx, acc);
|
|
let index = 0;
|
|
for (const node of json) {
|
|
acc = jsonWalk(node, visit, skip, parallelJson?.[index], ctx, acc);
|
|
index++;
|
|
}
|
|
} else if (isPlainObject(json)) {
|
|
acc = visit(json, parallelJson, ctx, acc);
|
|
for (const key of Object.keys(json)) {
|
|
if (skip?.has(key)) {
|
|
continue;
|
|
}
|
|
const value = json[key];
|
|
acc = jsonWalk(value, visit, skip, parallelJson?.[key], ctx, acc);
|
|
}
|
|
}
|
|
return acc;
|
|
}
|
|
function jsonApply(target, source, params = {}) {
|
|
const { path, matcherPath = path?.replace(/(\[[0-9+]+])/i, "[]"), skip = [] } = params;
|
|
if (target == null) {
|
|
throw new Error(`AG Charts - target is uninitialised: ${path ?? "<root>"}`);
|
|
}
|
|
if (source == null) {
|
|
return target;
|
|
}
|
|
if (isProperties(target)) {
|
|
return target.set(source);
|
|
}
|
|
const targetAny = target;
|
|
const targetType = classify(target);
|
|
for (const property of Object.keys(source)) {
|
|
if (SKIP_JS_BUILTINS.has(property))
|
|
continue;
|
|
const propertyMatcherPath = `${matcherPath ? matcherPath + "." : ""}${property}`;
|
|
if (skip.includes(propertyMatcherPath))
|
|
continue;
|
|
const newValue = source[property];
|
|
const propertyPath = `${path ? path + "." : ""}${property}`;
|
|
const targetClass = targetAny.constructor;
|
|
const currentValue = targetAny[property];
|
|
try {
|
|
const currentValueType = classify(currentValue);
|
|
const newValueType = classify(newValue);
|
|
if (targetType === CLASS_INSTANCE_TYPE && !(property in target || property === "context")) {
|
|
if (newValue === void 0)
|
|
continue;
|
|
warn(`unable to set [${propertyPath}] in ${targetClass?.name} - property is unknown`);
|
|
continue;
|
|
}
|
|
if (currentValueType != null && newValueType != null && newValueType !== currentValueType && (currentValueType !== CLASS_INSTANCE_TYPE || newValueType !== "object")) {
|
|
warn(
|
|
`unable to set [${propertyPath}] in ${targetClass?.name} - can't apply type of [${newValueType}], allowed types are: [${currentValueType}]`
|
|
);
|
|
continue;
|
|
}
|
|
if (isProperties(currentValue)) {
|
|
if (newValue === void 0) {
|
|
currentValue.clear();
|
|
} else {
|
|
currentValue.set(newValue);
|
|
}
|
|
} else if (newValueType === "object" && property !== "context") {
|
|
if (!(property in targetAny)) {
|
|
warn(`unable to set [${propertyPath}] in ${targetClass?.name} - property is unknown`);
|
|
continue;
|
|
}
|
|
if (currentValue == null) {
|
|
targetAny[property] = newValue;
|
|
} else {
|
|
jsonApply(currentValue, newValue, {
|
|
...params,
|
|
path: propertyPath,
|
|
matcherPath: propertyMatcherPath
|
|
});
|
|
}
|
|
} else {
|
|
targetAny[property] = newValue;
|
|
}
|
|
} catch (error2) {
|
|
warn(`unable to set [${propertyPath}] in [${targetClass?.name}]; nested error is: ${error2.message}`);
|
|
}
|
|
}
|
|
return target;
|
|
}
|
|
function classify(value) {
|
|
if (value == null) {
|
|
return null;
|
|
}
|
|
if (isHtmlElement(value) || isDate(value)) {
|
|
return "primitive";
|
|
}
|
|
if (isArray(value)) {
|
|
return "array";
|
|
}
|
|
if (isObject(value)) {
|
|
return isPlainObject(value) ? "object" : CLASS_INSTANCE_TYPE;
|
|
}
|
|
if (isFunction(value)) {
|
|
return "function";
|
|
}
|
|
return "primitive";
|
|
}
|
|
|
|
// packages/ag-charts-core/src/utils/dom/domEvents.ts
|
|
function attachListener(element, eventName, handler, options) {
|
|
element.addEventListener(eventName, handler, options);
|
|
return () => element.removeEventListener(eventName, handler, options);
|
|
}
|
|
|
|
// packages/ag-charts-core/src/utils/dom/keynavUtil.ts
|
|
function addEscapeEventListener(elem, onEscape, keyCodes = ["Escape"]) {
|
|
return attachListener(elem, "keydown", (event) => {
|
|
if (matchesKey(event, ...keyCodes)) {
|
|
onEscape(event);
|
|
}
|
|
});
|
|
}
|
|
function addMouseCloseListener(menu, hideCallback) {
|
|
const removeEvent = attachListener(getWindow(), "mousedown", (event) => {
|
|
if ([0, 2].includes(event.button) && !containsEvent(menu, event)) {
|
|
hideCallback();
|
|
removeEvent();
|
|
}
|
|
});
|
|
return removeEvent;
|
|
}
|
|
function addTouchCloseListener(menu, hideCallback) {
|
|
const removeEvent = attachListener(getWindow(), "touchstart", (event) => {
|
|
const touches = Array.from(event.targetTouches);
|
|
if (touches.some((touch) => !containsEvent(menu, touch))) {
|
|
hideCallback();
|
|
removeEvent();
|
|
}
|
|
});
|
|
return removeEvent;
|
|
}
|
|
function containsEvent(container, event) {
|
|
if (isElement(event.target) && event.target.shadowRoot != null) {
|
|
return true;
|
|
}
|
|
return isNode(event.target) && container.contains(event.target);
|
|
}
|
|
function addOverrideFocusVisibleEventListener(menu, buttons, overrideFocusVisible) {
|
|
const setFocusVisible = (value) => {
|
|
for (const btn of buttons) {
|
|
setAttribute(btn, "data-focus-visible-override", value);
|
|
}
|
|
};
|
|
setFocusVisible(overrideFocusVisible);
|
|
return attachListener(menu, "keydown", () => setFocusVisible(true), { once: true });
|
|
}
|
|
function hasNoModifiers(event) {
|
|
return !(event.shiftKey || event.altKey || event.ctrlKey || event.metaKey);
|
|
}
|
|
function matchesKey(event, ...keys) {
|
|
return hasNoModifiers(event) && keys.includes(event.key);
|
|
}
|
|
function linkTwoButtons(src, dst, key) {
|
|
return attachListener(src, "keydown", (event) => {
|
|
if (matchesKey(event, key)) {
|
|
dst.focus();
|
|
}
|
|
});
|
|
}
|
|
var PREV_NEXT_KEYS = {
|
|
horizontal: { nextKey: "ArrowRight", prevKey: "ArrowLeft" },
|
|
vertical: { nextKey: "ArrowDown", prevKey: "ArrowUp" }
|
|
};
|
|
function initRovingTabIndex(opts) {
|
|
const { orientation, buttons, wrapAround = false, onEscape, onFocus, onBlur } = opts;
|
|
const { nextKey, prevKey } = PREV_NEXT_KEYS[orientation];
|
|
const setTabIndices = (event) => {
|
|
if (event.target && "tabIndex" in event.target) {
|
|
for (const b of buttons) {
|
|
b.tabIndex = -1;
|
|
}
|
|
event.target.tabIndex = 0;
|
|
}
|
|
};
|
|
const [c, m] = wrapAround ? [buttons.length, buttons.length] : [0, Infinity];
|
|
const cleanup = new CleanupRegistry();
|
|
for (let i = 0; i < buttons.length; i++) {
|
|
const prev = buttons[(c + i - 1) % m];
|
|
const curr = buttons[i];
|
|
const next = buttons[(c + i + 1) % m];
|
|
cleanup.register(
|
|
attachListener(curr, "focus", setTabIndices),
|
|
onFocus && attachListener(curr, "focus", onFocus),
|
|
onBlur && attachListener(curr, "blur", onBlur),
|
|
onEscape && addEscapeEventListener(curr, onEscape),
|
|
prev && linkTwoButtons(curr, prev, prevKey),
|
|
next && linkTwoButtons(curr, next, nextKey),
|
|
attachListener(curr, "keydown", (event) => {
|
|
if (matchesKey(event, nextKey, prevKey)) {
|
|
event.preventDefault();
|
|
}
|
|
})
|
|
);
|
|
curr.tabIndex = i === 0 ? 0 : -1;
|
|
}
|
|
return cleanup;
|
|
}
|
|
function makeAccessibleClickListener(element, onclick) {
|
|
return (event) => {
|
|
if (element.ariaDisabled === "true") {
|
|
return event.preventDefault();
|
|
}
|
|
onclick(event);
|
|
};
|
|
}
|
|
function isButtonClickEvent(event) {
|
|
if ("button" in event) {
|
|
return event.button === 0;
|
|
}
|
|
return hasNoModifiers(event) && (event.code === "Space" || event.key === "Enter");
|
|
}
|
|
function getLastFocus(sourceEvent) {
|
|
const target = sourceEvent?.target;
|
|
if (isElement(target) && "tabindex" in target.attributes) {
|
|
return target;
|
|
}
|
|
return void 0;
|
|
}
|
|
function stopPageScrolling(element) {
|
|
return attachListener(element, "keydown", (event) => {
|
|
if (event.defaultPrevented)
|
|
return;
|
|
const shouldPrevent = getAttribute(event.target, "data-preventdefault", true);
|
|
if (shouldPrevent && matchesKey(event, "ArrowRight", "ArrowLeft", "ArrowDown", "ArrowUp")) {
|
|
event.preventDefault();
|
|
}
|
|
});
|
|
}
|
|
|
|
// packages/ag-charts-core/src/identity/id.ts
|
|
var ID_MAP = /* @__PURE__ */ new Map();
|
|
var nextElementID = 1;
|
|
function resetIds() {
|
|
ID_MAP.clear();
|
|
nextElementID = 1;
|
|
}
|
|
function createId(instance) {
|
|
const constructor = instance.constructor;
|
|
let className = Object.hasOwn(constructor, "className") ? constructor.className : constructor.name;
|
|
inDevelopmentMode(() => {
|
|
if (!className) {
|
|
throw new Error(`The ${String(constructor)} is missing the 'className' property.`);
|
|
}
|
|
});
|
|
className ?? (className = "Unknown");
|
|
const nextId = (ID_MAP.get(className) ?? 0) + 1;
|
|
ID_MAP.set(className, nextId);
|
|
return `${className}-${nextId}`;
|
|
}
|
|
function createElementId() {
|
|
return `ag-charts-${nextElementID++}`;
|
|
}
|
|
function generateUUID() {
|
|
return crypto.randomUUID?.() ?? generateUUIDv4();
|
|
}
|
|
function generateUUIDv4() {
|
|
const uuidArray = new Uint8Array(16);
|
|
crypto.getRandomValues(uuidArray);
|
|
uuidArray[6] = uuidArray[6] & 15 | 64;
|
|
uuidArray[8] = uuidArray[8] & 63 | 128;
|
|
let uuid = "";
|
|
for (let i = 0; i < uuidArray.length; i++) {
|
|
if (i === 4 || i === 6 || i === 8 || i === 10) {
|
|
uuid += "-";
|
|
}
|
|
uuid += uuidArray[i].toString(16).padStart(2, "0");
|
|
}
|
|
return uuid;
|
|
}
|
|
|
|
// packages/ag-charts-core/src/utils/data/linkedList.ts
|
|
function insertListItemsSorted(list, items, cmp) {
|
|
let head = list;
|
|
let current = head;
|
|
for (const value of items) {
|
|
if (head == null || cmp(head.value, value) > 0) {
|
|
head = { value, next: head };
|
|
current = head;
|
|
} else {
|
|
current = current;
|
|
while (current.next != null && cmp(current.next.value, value) <= 0) {
|
|
current = current.next;
|
|
}
|
|
current.next = { value, next: current.next };
|
|
}
|
|
}
|
|
return head;
|
|
}
|
|
|
|
// packages/ag-charts-core/src/state/memo.ts
|
|
var memorizedFns = /* @__PURE__ */ new WeakMap();
|
|
function memo(params, fnGenerator) {
|
|
const serialisedParams = JSON.stringify(params, null, 0);
|
|
if (!memorizedFns.has(fnGenerator)) {
|
|
memorizedFns.set(fnGenerator, /* @__PURE__ */ new Map());
|
|
}
|
|
if (!memorizedFns.get(fnGenerator)?.has(serialisedParams)) {
|
|
memorizedFns.get(fnGenerator)?.set(serialisedParams, fnGenerator(params));
|
|
}
|
|
return memorizedFns.get(fnGenerator)?.get(serialisedParams);
|
|
}
|
|
var MemoizeNode = class {
|
|
constructor() {
|
|
this.weak = /* @__PURE__ */ new WeakMap();
|
|
this.strong = /* @__PURE__ */ new Map();
|
|
this.set = false;
|
|
this.value = void 0;
|
|
}
|
|
};
|
|
function simpleMemorize2(fn, cacheCallback) {
|
|
let root = new MemoizeNode();
|
|
const memoised = (...p) => {
|
|
let current = root;
|
|
for (const param of p) {
|
|
const target = typeof param === "object" || typeof param === "symbol" ? current.weak : current.strong;
|
|
let next = target.get(param);
|
|
if (next == null) {
|
|
next = new MemoizeNode();
|
|
target.set(param, next);
|
|
}
|
|
current = next;
|
|
}
|
|
if (current.set) {
|
|
cacheCallback?.("hit", fn, p);
|
|
return current.value;
|
|
} else {
|
|
const out = fn(...p);
|
|
current.set = true;
|
|
current.value = out;
|
|
cacheCallback?.("miss", fn, p);
|
|
return out;
|
|
}
|
|
};
|
|
memoised.reset = () => {
|
|
root = new MemoizeNode();
|
|
};
|
|
return memoised;
|
|
}
|
|
function simpleMemorize(fn, cacheCallback) {
|
|
const primitiveCache = /* @__PURE__ */ new Map();
|
|
const paramsToKeys = (...params) => {
|
|
return params.map((v) => {
|
|
if (typeof v === "object")
|
|
return v;
|
|
if (typeof v === "symbol")
|
|
return v;
|
|
if (!primitiveCache.has(v)) {
|
|
primitiveCache.set(v, { v });
|
|
}
|
|
return primitiveCache.get(v);
|
|
});
|
|
};
|
|
const empty = {};
|
|
const cache = /* @__PURE__ */ new WeakMap();
|
|
return (...p) => {
|
|
const keys = p.length === 0 ? [empty] : paramsToKeys(...p);
|
|
let currentCache = cache;
|
|
for (const key of keys.slice(0, -1)) {
|
|
if (!currentCache.has(key)) {
|
|
currentCache.set(key, /* @__PURE__ */ new WeakMap());
|
|
}
|
|
currentCache = currentCache.get(key);
|
|
}
|
|
const finalKey = keys.at(-1);
|
|
let cachedValue = currentCache.get(finalKey);
|
|
if (cachedValue) {
|
|
cacheCallback?.("hit", fn, p);
|
|
} else {
|
|
cachedValue = fn(...p);
|
|
currentCache.set(finalKey, cachedValue);
|
|
cacheCallback?.("miss", fn, p);
|
|
}
|
|
return cachedValue;
|
|
};
|
|
}
|
|
|
|
// packages/ag-charts-core/src/utils/data/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;
|
|
}
|
|
function nearestSquaredInContainer(x, y, container, maxDistanceSquared = Infinity) {
|
|
const { x: tx = x, y: ty = y } = container.transformPoint?.(x, y) ?? {};
|
|
const result = { nearest: void 0, distanceSquared: maxDistanceSquared };
|
|
for (const child of container.children) {
|
|
const { nearest, distanceSquared: distanceSquared2 } = child.nearestSquared(tx, ty, result.distanceSquared);
|
|
if (distanceSquared2 === 0) {
|
|
return { nearest, distanceSquared: distanceSquared2 };
|
|
} else if (distanceSquared2 < result.distanceSquared) {
|
|
result.nearest = nearest;
|
|
result.distanceSquared = distanceSquared2;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// packages/ag-charts-core/src/utils/geometry/padding.ts
|
|
var Padding = class extends BaseProperties {
|
|
constructor(top = 0, right = top, bottom = top, left = right) {
|
|
super();
|
|
this.top = top;
|
|
this.right = right;
|
|
this.bottom = bottom;
|
|
this.left = left;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
addFakeTransformToInstanceProperty
|
|
], Padding.prototype, "top", 2);
|
|
__decorateClass([
|
|
addFakeTransformToInstanceProperty
|
|
], Padding.prototype, "right", 2);
|
|
__decorateClass([
|
|
addFakeTransformToInstanceProperty
|
|
], Padding.prototype, "bottom", 2);
|
|
__decorateClass([
|
|
addFakeTransformToInstanceProperty
|
|
], Padding.prototype, "left", 2);
|
|
|
|
// packages/ag-charts-core/src/utils/geometry/placement.ts
|
|
function calculatePlacement(naturalWidth, naturalHeight, container, bounds) {
|
|
let { top, right, bottom, left, width: width2, height: height2 } = bounds;
|
|
if (left != null) {
|
|
if (width2 != null) {
|
|
right = container.width - left + width2;
|
|
} else if (right != null) {
|
|
width2 = container.width - left - right;
|
|
}
|
|
} else if (right != null && width2 != null) {
|
|
left = container.width - right - width2;
|
|
}
|
|
if (top != null) {
|
|
if (height2 != null) {
|
|
bottom = container.height - top - height2;
|
|
} else if (bottom != null) {
|
|
height2 = container.height - bottom - top;
|
|
}
|
|
} else if (bottom != null && height2 != null) {
|
|
top = container.height - bottom - height2;
|
|
}
|
|
if (width2 == null) {
|
|
if (height2 == null) {
|
|
height2 = naturalHeight;
|
|
width2 = naturalWidth;
|
|
} else {
|
|
width2 = Math.ceil(naturalWidth * height2 / naturalHeight);
|
|
}
|
|
} else {
|
|
height2 ?? (height2 = Math.ceil(naturalHeight * width2 / naturalWidth));
|
|
}
|
|
if (left == null) {
|
|
if (right == null) {
|
|
left = Math.floor((container.width - width2) / 2);
|
|
} else {
|
|
left = container.width - right - width2;
|
|
}
|
|
}
|
|
if (top == null) {
|
|
if (bottom == null) {
|
|
top = Math.floor((container.height - height2) / 2);
|
|
} else {
|
|
top = container.height - height2 - bottom;
|
|
}
|
|
}
|
|
return { x: left, y: top, width: width2, height: height2 };
|
|
}
|
|
|
|
// packages/ag-charts-core/src/state/stateMachine.ts
|
|
var debugColor = "color: green";
|
|
var debugQuietColor = "color: grey";
|
|
function StateMachineProperty() {
|
|
return addObserverToInstanceProperty(() => {
|
|
});
|
|
}
|
|
function applyProperties(parentState, childState) {
|
|
const childProperties = listDecoratedProperties(childState);
|
|
if (childProperties.length === 0)
|
|
return;
|
|
const properties = extractDecoratedProperties(parentState);
|
|
for (const property of childProperties) {
|
|
if (property in properties) {
|
|
childState[property] = properties[property];
|
|
}
|
|
}
|
|
}
|
|
var AbstractStateMachine = class {
|
|
transitionRoot(event, data) {
|
|
if (this.parent) {
|
|
this.parent.transitionRoot(event, data);
|
|
} else {
|
|
this.transition(event, data);
|
|
}
|
|
}
|
|
};
|
|
var _StateMachine = class _StateMachine extends AbstractStateMachine {
|
|
constructor(defaultState, states, enterEach) {
|
|
super();
|
|
this.defaultState = defaultState;
|
|
this.states = states;
|
|
this.enterEach = enterEach;
|
|
this.debug = create(true, "animation");
|
|
this.state = defaultState;
|
|
this.debug(`%c${this.constructor.name} | init -> ${defaultState}`, debugColor);
|
|
}
|
|
// TODO: handle events which do not require data without requiring `undefined` to be passed as as parameter, while
|
|
// also still requiring data to be passed to those events which do require it.
|
|
transition(event, data) {
|
|
const shouldTransitionSelf = this.transitionChild(event, data);
|
|
if (!shouldTransitionSelf || this.state === _StateMachine.child || this.state === _StateMachine.parent) {
|
|
return;
|
|
}
|
|
const currentState = this.state;
|
|
const currentStateConfig = this.states[this.state];
|
|
let destination = currentStateConfig[event];
|
|
const debugPrefix = `%c${this.constructor.name} | ${this.state} -> ${event} ->`;
|
|
if (Array.isArray(destination)) {
|
|
destination = destination.find((transition) => {
|
|
if (!transition.guard)
|
|
return true;
|
|
const valid = transition.guard(data);
|
|
if (!valid) {
|
|
this.debug(`${debugPrefix} (guarded)`, transition.target, debugQuietColor);
|
|
}
|
|
return valid;
|
|
});
|
|
} else if (typeof destination === "object" && !(destination instanceof _StateMachine) && destination.guard && !destination.guard(data)) {
|
|
this.debug(`${debugPrefix} (guarded)`, destination.target, debugQuietColor);
|
|
return;
|
|
}
|
|
if (!destination) {
|
|
this.debug(`${debugPrefix} ${this.state}`, debugQuietColor);
|
|
return;
|
|
}
|
|
const destinationState = this.getDestinationState(destination);
|
|
const exitFn = destinationState === this.state ? void 0 : currentStateConfig.onExit;
|
|
this.debug(`${debugPrefix} ${destinationState}`, debugColor);
|
|
this.state = destinationState;
|
|
if (typeof destination === "function") {
|
|
destination(data);
|
|
} else if (typeof destination === "object" && !(destination instanceof _StateMachine)) {
|
|
destination.action?.(data);
|
|
}
|
|
exitFn?.();
|
|
this.enterEach?.(currentState, destinationState);
|
|
if (destinationState !== currentState && destinationState !== _StateMachine.child && destinationState !== _StateMachine.parent) {
|
|
this.states[destinationState].onEnter?.(currentState, data);
|
|
}
|
|
}
|
|
transitionAsync(event, data) {
|
|
setTimeout(() => {
|
|
this.transition(event, data);
|
|
}, 0);
|
|
}
|
|
is(value) {
|
|
if (this.state === _StateMachine.child && this.childState) {
|
|
return this.childState.is(value);
|
|
}
|
|
return this.state === value;
|
|
}
|
|
resetHierarchy() {
|
|
this.debug(
|
|
`%c${this.constructor.name} | ${this.state} -> [resetHierarchy] -> ${this.defaultState}`,
|
|
"color: green"
|
|
);
|
|
this.state = this.defaultState;
|
|
}
|
|
transitionChild(event, data) {
|
|
if (this.state !== _StateMachine.child || !this.childState)
|
|
return true;
|
|
applyProperties(this, this.childState);
|
|
this.childState.transition(event, data);
|
|
if (!this.childState.is(_StateMachine.parent))
|
|
return true;
|
|
this.debug(`%c${this.constructor.name} | ${this.state} -> ${event} -> ${this.defaultState}`, debugColor);
|
|
this.state = this.defaultState;
|
|
this.states[this.state].onEnter?.();
|
|
this.childState.resetHierarchy();
|
|
return false;
|
|
}
|
|
getDestinationState(destination) {
|
|
let state = this.state;
|
|
if (typeof destination === "string") {
|
|
state = destination;
|
|
} else if (destination instanceof _StateMachine) {
|
|
this.childState = destination;
|
|
this.childState.parent = this;
|
|
state = _StateMachine.child;
|
|
} else if (typeof destination === "object") {
|
|
if (destination.target instanceof _StateMachine) {
|
|
this.childState = destination.target;
|
|
this.childState.parent = this;
|
|
state = _StateMachine.child;
|
|
} else if (destination.target != null) {
|
|
state = destination.target;
|
|
}
|
|
}
|
|
return state;
|
|
}
|
|
};
|
|
_StateMachine.child = "__child";
|
|
_StateMachine.parent = "__parent";
|
|
var StateMachine = _StateMachine;
|
|
var ParallelStateMachine = class extends AbstractStateMachine {
|
|
constructor(...stateMachines) {
|
|
super();
|
|
this.stateMachines = stateMachines;
|
|
for (const stateMachine of stateMachines) {
|
|
stateMachine.parent = this;
|
|
}
|
|
}
|
|
transition(event, data) {
|
|
for (const stateMachine of this.stateMachines) {
|
|
applyProperties(this, stateMachine);
|
|
stateMachine.transition(event, data);
|
|
}
|
|
}
|
|
transitionAsync(event, data) {
|
|
for (const stateMachine of this.stateMachines) {
|
|
applyProperties(this, stateMachine);
|
|
stateMachine.transitionAsync(event, data);
|
|
}
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-core/src/rendering/textMeasurer.ts
|
|
var TextMeasurer = class {
|
|
constructor(ctx, measureTextCached) {
|
|
this.ctx = ctx;
|
|
this.measureTextCached = measureTextCached;
|
|
this.baselineMap = /* @__PURE__ */ new Map();
|
|
this.charMap = /* @__PURE__ */ new Map();
|
|
this.lineHeightCache = null;
|
|
}
|
|
baselineDistance(textBaseline) {
|
|
if (textBaseline === "alphabetic")
|
|
return 0;
|
|
if (this.baselineMap.has(textBaseline)) {
|
|
return this.baselineMap.get(textBaseline);
|
|
}
|
|
this.ctx.textBaseline = textBaseline;
|
|
const { alphabeticBaseline } = this.ctx.measureText("");
|
|
this.baselineMap.set(textBaseline, alphabeticBaseline);
|
|
this.ctx.textBaseline = "alphabetic";
|
|
return alphabeticBaseline;
|
|
}
|
|
lineHeight() {
|
|
this.lineHeightCache ?? (this.lineHeightCache = this.measureText("").height);
|
|
return this.lineHeightCache;
|
|
}
|
|
measureText(text) {
|
|
const m = this.measureTextCached?.(text) ?? this.ctx.measureText(text);
|
|
const {
|
|
width: width2,
|
|
// Apply fallbacks for environments like `node-canvas` where some metrics may be missing.
|
|
fontBoundingBoxAscent: ascent = m.emHeightAscent,
|
|
fontBoundingBoxDescent: descent = m.emHeightDescent
|
|
} = m;
|
|
const height2 = ascent + descent;
|
|
return { width: width2, height: height2, ascent, descent };
|
|
}
|
|
measureLines(text) {
|
|
const lines = typeof text === "string" ? text.split(LineSplitter) : text;
|
|
let width2 = 0;
|
|
let height2 = 0;
|
|
const lineMetrics = lines.map((line) => {
|
|
const b = this.measureText(line);
|
|
if (width2 < b.width) {
|
|
width2 = b.width;
|
|
}
|
|
height2 += b.height;
|
|
return { text: line, ...b };
|
|
});
|
|
return { width: width2, height: height2, 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.ctx.measureText(text).width;
|
|
}
|
|
return this.charMap.get(text) ?? this.charWidth(text);
|
|
}
|
|
charWidth(char) {
|
|
const { width: width2 } = this.ctx.measureText(char);
|
|
this.charMap.set(char, width2);
|
|
return width2;
|
|
}
|
|
};
|
|
var instanceMap = new LRUCache(50);
|
|
function cachedTextMeasurer(font) {
|
|
if (typeof font === "object") {
|
|
font = toFontString(font);
|
|
}
|
|
let cachedMeasurer = instanceMap.get(font);
|
|
if (cachedMeasurer)
|
|
return cachedMeasurer;
|
|
const cachedTextMetrics = new LRUCache(1e4);
|
|
const ctx = createCanvasContext();
|
|
ctx.font = font;
|
|
cachedMeasurer = new TextMeasurer(ctx, (text) => {
|
|
let textMetrics = cachedTextMetrics.get(text);
|
|
if (textMetrics)
|
|
return textMetrics;
|
|
textMetrics = ctx.measureText(text);
|
|
cachedTextMetrics.set(text, textMetrics);
|
|
return textMetrics;
|
|
});
|
|
instanceMap.set(font, cachedMeasurer);
|
|
return cachedMeasurer;
|
|
}
|
|
cachedTextMeasurer.clear = () => instanceMap.clear();
|
|
function measureTextSegments(textSegments, defaultFont) {
|
|
let currentLine = { segments: [], width: 0, height: 0, ascent: 0, descent: 0 };
|
|
const lineMetrics = [currentLine];
|
|
for (const segment of textSegments) {
|
|
const {
|
|
text,
|
|
fontSize = defaultFont.fontSize,
|
|
fontStyle = defaultFont.fontStyle,
|
|
fontWeight: fontWeight2 = defaultFont.fontWeight,
|
|
fontFamily = defaultFont.fontFamily,
|
|
...rest
|
|
} = segment;
|
|
const font = { fontSize, fontStyle, fontWeight: fontWeight2, fontFamily };
|
|
const measurer = cachedTextMeasurer(font);
|
|
const textLines = toTextString(text).split(LineSplitter);
|
|
for (let i = 0; i < textLines.length; i++) {
|
|
const textLine = textLines[i];
|
|
const textMetrics = measurer.measureText(textLine);
|
|
if (i > 0) {
|
|
currentLine = { segments: [], width: 0, height: 0, ascent: 0, descent: 0 };
|
|
lineMetrics.push(currentLine);
|
|
}
|
|
if (textLine) {
|
|
currentLine.width += textMetrics.width;
|
|
currentLine.ascent = Math.max(currentLine.ascent, textMetrics.ascent);
|
|
currentLine.descent = Math.max(currentLine.descent, textMetrics.descent);
|
|
currentLine.height = Math.max(currentLine.height, currentLine.ascent + currentLine.descent);
|
|
currentLine.segments.push({ ...font, ...rest, text: textLine, textMetrics });
|
|
}
|
|
}
|
|
}
|
|
let maxWidth = 0;
|
|
let totalHeight = 0;
|
|
for (const line of lineMetrics) {
|
|
maxWidth = Math.max(maxWidth, line.width);
|
|
totalHeight += line.height;
|
|
}
|
|
return { width: maxWidth, height: totalHeight, lineMetrics };
|
|
}
|
|
|
|
// packages/ag-charts-core/src/utils/dom/domElements.ts
|
|
function createElement(tagName, className, style2) {
|
|
const element = getDocument().createElement(tagName);
|
|
if (typeof className === "object") {
|
|
style2 = className;
|
|
className = void 0;
|
|
}
|
|
if (className) {
|
|
for (const name of className.split(" ")) {
|
|
element.classList.add(name);
|
|
}
|
|
}
|
|
if (style2) {
|
|
Object.assign(element.style, style2);
|
|
}
|
|
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(() => element.remove());
|
|
}
|
|
|
|
// packages/ag-charts-core/src/utils/text/textWrapper.ts
|
|
function shouldHideOverflow(clippedResult, options) {
|
|
return options.overflow === "hide" && clippedResult.some(isTextTruncated);
|
|
}
|
|
function wrapTextOrSegments(input, options) {
|
|
return isArray(input) ? wrapTextSegments(input, options) : wrapLines(toTextString(input), options).join("\n");
|
|
}
|
|
function wrapText(text, options) {
|
|
return wrapLines(text, options).join("\n");
|
|
}
|
|
function wrapLines(text, options) {
|
|
return textWrap(text, options);
|
|
}
|
|
function truncateLine(text, measurer, maxWidth, ellipsisForce) {
|
|
const ellipsisWidth = measurer.textWidth(EllipsisChar);
|
|
let estimatedWidth = 0;
|
|
let i = 0;
|
|
for (; i < text.length; i++) {
|
|
const charWidth = measurer.textWidth(text.charAt(i));
|
|
if (estimatedWidth + charWidth > maxWidth)
|
|
break;
|
|
estimatedWidth += charWidth;
|
|
}
|
|
if (text.length === i && (!ellipsisForce || estimatedWidth + ellipsisWidth <= maxWidth)) {
|
|
return ellipsisForce ? appendEllipsis(text) : text;
|
|
}
|
|
text = text.slice(0, i).trimEnd();
|
|
while (text.length && measurer.textWidth(text) + ellipsisWidth > maxWidth) {
|
|
text = text.slice(0, -1).trimEnd();
|
|
}
|
|
return appendEllipsis(text);
|
|
}
|
|
function textWrap(text, options, widthOffset = 0) {
|
|
const lines = text.split(LineSplitter);
|
|
const measurer = cachedTextMeasurer(options.font);
|
|
const result = [];
|
|
if (options.textWrap === "never") {
|
|
for (const line of lines) {
|
|
const truncatedLine = truncateLine(line.trimEnd(), measurer, Math.max(0, options.maxWidth - widthOffset));
|
|
if (!truncatedLine)
|
|
break;
|
|
result.push(truncatedLine);
|
|
widthOffset = 0;
|
|
}
|
|
return shouldHideOverflow(result, options) ? [] : result;
|
|
}
|
|
const wrapHyphenate = options.textWrap === "hyphenate";
|
|
const wrapOnSpace = options.textWrap == null || options.textWrap === "on-space";
|
|
for (const untrimmedLine of lines) {
|
|
let line = untrimmedLine.trimEnd();
|
|
if (line === "") {
|
|
result.push(line);
|
|
continue;
|
|
}
|
|
let i = 0;
|
|
let estimatedWidth = 0;
|
|
let lastSpaceIndex = 0;
|
|
if (!result.length) {
|
|
estimatedWidth = widthOffset;
|
|
}
|
|
while (i < line.length) {
|
|
const char = line.charAt(i);
|
|
if (char === " ") {
|
|
lastSpaceIndex = i;
|
|
}
|
|
estimatedWidth += measurer.textWidth(char);
|
|
if (estimatedWidth > options.maxWidth) {
|
|
if (i === 0) {
|
|
line = "";
|
|
break;
|
|
}
|
|
let actualWidth = measurer.textWidth(line.slice(0, i + 1));
|
|
if (!result.length) {
|
|
actualWidth += widthOffset;
|
|
}
|
|
if (actualWidth <= options.maxWidth) {
|
|
estimatedWidth = actualWidth;
|
|
i++;
|
|
continue;
|
|
}
|
|
if (lastSpaceIndex) {
|
|
const nextWord = getWordAt(line, lastSpaceIndex + 1);
|
|
const textWidth = measurer.textWidth(nextWord);
|
|
if (textWidth <= options.maxWidth) {
|
|
result.push(line.slice(0, lastSpaceIndex).trimEnd());
|
|
line = line.slice(lastSpaceIndex).trimStart();
|
|
i = 0;
|
|
estimatedWidth = 0;
|
|
lastSpaceIndex = 0;
|
|
continue;
|
|
} else if (wrapOnSpace && textWidth > options.maxWidth) {
|
|
result.push(
|
|
line.slice(0, lastSpaceIndex).trimEnd(),
|
|
truncateLine(line.slice(lastSpaceIndex).trimStart(), measurer, options.maxWidth, true)
|
|
);
|
|
}
|
|
} else if (wrapOnSpace) {
|
|
const newLine2 = truncateLine(line, measurer, options.maxWidth, true);
|
|
if (newLine2) {
|
|
result.push(newLine2);
|
|
}
|
|
}
|
|
if (wrapOnSpace) {
|
|
line = "";
|
|
break;
|
|
}
|
|
const postfix = wrapHyphenate ? "-" : "";
|
|
let newLine = line.slice(0, i).trim();
|
|
while (newLine.length && measurer.textWidth(newLine + postfix) > options.maxWidth) {
|
|
newLine = newLine.slice(0, -1).trimEnd();
|
|
}
|
|
if (newLine && newLine !== TrimEdgeGuard) {
|
|
result.push(newLine + postfix);
|
|
} else {
|
|
line = "";
|
|
break;
|
|
}
|
|
line = line.slice(newLine.length).trimStart();
|
|
i = -1;
|
|
estimatedWidth = 0;
|
|
lastSpaceIndex = 0;
|
|
}
|
|
i++;
|
|
}
|
|
if (line) {
|
|
result.push(line);
|
|
}
|
|
}
|
|
avoidOrphans(result, measurer, options);
|
|
const clippedResult = clipLines(result, measurer, options);
|
|
return shouldHideOverflow(clippedResult, options) ? [] : clippedResult;
|
|
}
|
|
function getWordAt(text, position) {
|
|
const nextSpaceIndex = text.indexOf(" ", position);
|
|
return nextSpaceIndex === -1 ? text.slice(position) : text.slice(position, nextSpaceIndex);
|
|
}
|
|
function clipLines(lines, measurer, options) {
|
|
if (!isFiniteNumber(options.maxHeight)) {
|
|
return lines;
|
|
}
|
|
const { height: height2, lineMetrics } = measurer.measureLines(lines);
|
|
if (height2 <= options.maxHeight) {
|
|
return lines;
|
|
}
|
|
for (let i = 0, cumulativeHeight = 0; i < lineMetrics.length; i++) {
|
|
cumulativeHeight += lineMetrics[i].height;
|
|
if (cumulativeHeight > options.maxHeight) {
|
|
if (options.overflow === "hide" || i === 0)
|
|
return [];
|
|
const clippedResults = lines.slice(0, i);
|
|
const lastLine = clippedResults.pop();
|
|
return clippedResults.concat(
|
|
isTextTruncated(lastLine) ? lastLine : truncateLine(lastLine, measurer, options.maxWidth, true)
|
|
);
|
|
}
|
|
}
|
|
return lines;
|
|
}
|
|
function avoidOrphans(lines, measurer, options) {
|
|
if (options.avoidOrphans === false || lines.length < 2)
|
|
return;
|
|
const { length: length2 } = lines;
|
|
const lastLine = lines[length2 - 1];
|
|
const beforeLast = lines[length2 - 2];
|
|
if (beforeLast.length < lastLine.length)
|
|
return;
|
|
const lastSpaceIndex = beforeLast.lastIndexOf(" ");
|
|
if (lastSpaceIndex === -1 || lastSpaceIndex === beforeLast.indexOf(" ") || lastLine.includes(" "))
|
|
return;
|
|
const lastWord = beforeLast.slice(lastSpaceIndex + 1);
|
|
if (measurer.textWidth(lastLine + lastWord) <= options.maxWidth) {
|
|
lines[length2 - 2] = beforeLast.slice(0, lastSpaceIndex);
|
|
lines[length2 - 1] = lastWord + " " + lastLine;
|
|
}
|
|
}
|
|
function wrapTextSegments(textSegments, options) {
|
|
const { maxHeight = Infinity } = options;
|
|
const result = [];
|
|
let lineWidth = 0;
|
|
let totalHeight = 0;
|
|
function truncateLastSegment() {
|
|
const lastSegment = result.pop();
|
|
if (!lastSegment)
|
|
return;
|
|
const measurer = cachedTextMeasurer(lastSegment);
|
|
const truncatedText = truncateLine(lastSegment.text, measurer, options.maxWidth, true);
|
|
const textMetrics = measurer.measureText(truncatedText);
|
|
result.push({ ...lastSegment, text: truncatedText, textMetrics });
|
|
}
|
|
for (const { width: width2, height: height2, segments } of measureTextSegments(textSegments, options.font).lineMetrics) {
|
|
if (totalHeight + height2 > maxHeight) {
|
|
if (result.length) {
|
|
truncateLastSegment();
|
|
}
|
|
break;
|
|
}
|
|
if (lineWidth + width2 <= options.maxWidth) {
|
|
lineWidth += width2;
|
|
totalHeight += height2;
|
|
result.push(...segments);
|
|
continue;
|
|
}
|
|
for (const segment of segments) {
|
|
if (lineWidth + segment.textMetrics.width <= options.maxWidth) {
|
|
lineWidth += segment.textMetrics.width;
|
|
result.push(segment);
|
|
continue;
|
|
}
|
|
const measurer = cachedTextMeasurer(segment);
|
|
const guardedText = guardTextEdges(segment.text);
|
|
const wrapOptions = { ...options, font: segment, maxHeight: maxHeight - totalHeight };
|
|
let wrappedLines = textWrap(guardedText, { ...wrapOptions, overflow: "hide" }, lineWidth);
|
|
if (wrappedLines.length === 0) {
|
|
if (options.textWrap === "never") {
|
|
wrappedLines = textWrap(guardedText, wrapOptions, lineWidth);
|
|
} else {
|
|
wrappedLines = textWrap(guardedText, wrapOptions);
|
|
const lastSegment = result.at(-1);
|
|
if (lastSegment) {
|
|
lastSegment.text += "\n";
|
|
lineWidth = 0;
|
|
}
|
|
}
|
|
}
|
|
if (wrappedLines.length === 0) {
|
|
truncateLastSegment();
|
|
break;
|
|
}
|
|
const truncationIndex = wrappedLines.findIndex(isTextTruncated);
|
|
if (truncationIndex !== -1) {
|
|
wrappedLines = wrappedLines.slice(0, truncationIndex + 1);
|
|
}
|
|
const lastLine = wrappedLines.at(-1);
|
|
for (const wrappedLine of wrappedLines) {
|
|
const cleanLine = unguardTextEdges(wrappedLine);
|
|
const textMetrics = measurer.measureText(cleanLine);
|
|
const subSegment = { ...segment, text: cleanLine, textMetrics };
|
|
if (wrappedLine === lastLine) {
|
|
lineWidth += textMetrics.width;
|
|
} else {
|
|
subSegment.text += "\n";
|
|
lineWidth = 0;
|
|
}
|
|
totalHeight += textMetrics.height;
|
|
result.push(subSegment);
|
|
}
|
|
if (truncationIndex !== -1)
|
|
break;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// packages/ag-charts-core/src/utils/data/visibleRange.ts
|
|
function rescaleVisibleRange(visibleRange, [s0, s1], [d0, d1]) {
|
|
const dr = d1 - d0;
|
|
const vr = s1 - s0;
|
|
const vd0 = s0 + vr * visibleRange[0];
|
|
const vd1 = s0 + vr * visibleRange[1];
|
|
return [(vd0 - d0) / dr, (vd1 - d0) / dr];
|
|
}
|
|
|
|
// packages/ag-charts-core/src/utils/time/time/duration.ts
|
|
var durationSecond = 1e3;
|
|
var durationMinute = durationSecond * 60;
|
|
var durationHour = durationMinute * 60;
|
|
var durationDay = durationHour * 24;
|
|
var durationWeek = durationDay * 7;
|
|
var durationMonth = durationDay * 30;
|
|
var durationYear = durationDay * 365;
|
|
|
|
// packages/ag-charts-core/src/utils/time/time/encoding.ts
|
|
var tzOffset = (/* @__PURE__ */ new Date()).getTimezoneOffset() * durationMinute;
|
|
var unitEncoding = {
|
|
millisecond: {
|
|
milliseconds: 1,
|
|
hierarchy: "day",
|
|
encode(date2) {
|
|
return date2.getTime();
|
|
},
|
|
decode(encoded) {
|
|
return new Date(encoded);
|
|
}
|
|
},
|
|
second: {
|
|
milliseconds: durationSecond,
|
|
hierarchy: "day",
|
|
encode(date2, utc) {
|
|
const offset = utc ? 0 : tzOffset;
|
|
return Math.floor((date2.getTime() - offset) / durationSecond);
|
|
},
|
|
decode(encoded, utc) {
|
|
const offset = utc ? 0 : tzOffset;
|
|
return new Date(offset + encoded * durationSecond);
|
|
}
|
|
},
|
|
minute: {
|
|
milliseconds: durationMinute,
|
|
hierarchy: "day",
|
|
encode(date2, utc) {
|
|
const offset = utc ? 0 : tzOffset;
|
|
return Math.floor((date2.getTime() - offset) / durationMinute);
|
|
},
|
|
decode(encoded, utc) {
|
|
const offset = utc ? 0 : tzOffset;
|
|
return new Date(offset + encoded * durationMinute);
|
|
}
|
|
},
|
|
hour: {
|
|
milliseconds: durationHour,
|
|
hierarchy: "day",
|
|
encode(date2, utc) {
|
|
const offset = utc ? 0 : tzOffset;
|
|
return Math.floor((date2.getTime() - offset) / durationHour);
|
|
},
|
|
decode(encoded, utc) {
|
|
const offset = utc ? 0 : tzOffset;
|
|
return new Date(offset + encoded * durationHour);
|
|
}
|
|
},
|
|
day: {
|
|
milliseconds: durationDay,
|
|
hierarchy: "month",
|
|
encode(date2, utc) {
|
|
const tzOffsetMs2 = utc ? 0 : date2.getTimezoneOffset() * durationMinute;
|
|
return Math.floor((date2.getTime() - tzOffsetMs2) / durationDay);
|
|
},
|
|
decode(encoded, utc) {
|
|
let d;
|
|
if (utc) {
|
|
d = /* @__PURE__ */ new Date(0);
|
|
d.setUTCDate(d.getUTCDate() + encoded);
|
|
d.setUTCHours(0, 0, 0, 0);
|
|
} else {
|
|
d = new Date(1970, 0, 1);
|
|
d.setDate(d.getDate() + encoded);
|
|
}
|
|
return d;
|
|
}
|
|
},
|
|
month: {
|
|
milliseconds: durationMonth,
|
|
hierarchy: "year",
|
|
encode(date2, utc) {
|
|
if (utc) {
|
|
return date2.getUTCFullYear() * 12 + date2.getUTCMonth();
|
|
} else {
|
|
return date2.getFullYear() * 12 + date2.getMonth();
|
|
}
|
|
},
|
|
decode(encoded, utc) {
|
|
if (utc) {
|
|
const year = Math.floor(encoded / 12);
|
|
const m = encoded - year * 12;
|
|
return new Date(Date.UTC(year, m, 1));
|
|
} else {
|
|
const y = Math.floor(encoded / 12);
|
|
const month = encoded - y * 12;
|
|
return new Date(y, month, 1);
|
|
}
|
|
}
|
|
},
|
|
year: {
|
|
milliseconds: durationYear,
|
|
hierarchy: void 0,
|
|
encode(date2, utc) {
|
|
if (utc) {
|
|
return date2.getUTCFullYear();
|
|
} else {
|
|
return date2.getFullYear();
|
|
}
|
|
},
|
|
decode(encoded, utc) {
|
|
let d;
|
|
if (utc) {
|
|
d = /* @__PURE__ */ new Date();
|
|
d.setUTCFullYear(encoded);
|
|
d.setUTCMonth(0, 1);
|
|
d.setUTCHours(0, 0, 0, 0);
|
|
} else {
|
|
d = new Date(encoded, 0, 1, 0, 0, 0, 0);
|
|
}
|
|
return d;
|
|
}
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-core/src/utils/time/time/range.ts
|
|
function timeInterval(interval) {
|
|
return typeof interval === "string" ? { unit: interval, step: 1, epoch: void 0, utc: false } : {
|
|
unit: interval.unit,
|
|
step: interval.step ?? 1,
|
|
epoch: interval.epoch,
|
|
utc: interval.utc ?? false
|
|
};
|
|
}
|
|
function getOffset(unit, step, epoch, utc) {
|
|
if (epoch == null)
|
|
return 0;
|
|
const encoding = unitEncoding[unit];
|
|
return Math.floor(encoding.encode(new Date(epoch), utc)) % step;
|
|
}
|
|
function encode(d, unit, step, utc, offset) {
|
|
const encoding = unitEncoding[unit];
|
|
return Math.floor((encoding.encode(new Date(d), utc) - offset) / step);
|
|
}
|
|
function decode(encoded, unit, step, utc, offset) {
|
|
const encoding = unitEncoding[unit];
|
|
return encoding.decode(encoded * step + offset, utc);
|
|
}
|
|
function encodingFloor(date2, unit, step, utc, offset) {
|
|
const d = new Date(date2);
|
|
const e = encode(d, unit, step, utc, offset);
|
|
return decode(e, unit, step, utc, offset);
|
|
}
|
|
function encodingCeil(date2, unit, step, utc, offset) {
|
|
const d = new Date(Number(date2) - 1);
|
|
const e = encode(d, unit, step, utc, offset);
|
|
return decode(e + 1, unit, step, utc, offset);
|
|
}
|
|
function intervalFloor(interval, date2) {
|
|
const { unit, step, epoch, utc } = timeInterval(interval);
|
|
const offset = getOffset(unit, step, epoch, utc);
|
|
return encodingFloor(date2, unit, step, utc, offset);
|
|
}
|
|
function intervalCeil(interval, date2) {
|
|
const { unit, step, epoch, utc } = timeInterval(interval);
|
|
const offset = getOffset(unit, step, epoch, utc);
|
|
return encodingCeil(date2, unit, step, utc, offset);
|
|
}
|
|
function intervalPrevious(interval, date2) {
|
|
const { unit, step, epoch, utc } = timeInterval(interval);
|
|
const offset = getOffset(unit, step, epoch, utc);
|
|
return decode(
|
|
encode(encodingCeil(date2, unit, step, utc, offset), unit, step, utc, offset) - 1,
|
|
unit,
|
|
step,
|
|
utc,
|
|
offset
|
|
);
|
|
}
|
|
function intervalNext(interval, date2) {
|
|
const { unit, step, epoch, utc } = timeInterval(interval);
|
|
const offset = getOffset(unit, step, epoch, utc);
|
|
return decode(
|
|
encode(encodingFloor(date2, unit, step, utc, offset), unit, step, utc, offset) + 1,
|
|
unit,
|
|
step,
|
|
utc,
|
|
offset
|
|
);
|
|
}
|
|
function intervalExtent(start2, stop, visibleRange) {
|
|
if (start2.valueOf() > stop.valueOf()) {
|
|
[start2, stop] = [stop, start2];
|
|
if (visibleRange != null) {
|
|
visibleRange = [1 - visibleRange[1], 1 - visibleRange[0]];
|
|
}
|
|
}
|
|
if (visibleRange != null) {
|
|
const delta = stop.valueOf() - start2.valueOf();
|
|
const t0 = start2.valueOf();
|
|
start2 = new Date(t0 + visibleRange[0] * delta);
|
|
stop = new Date(t0 + visibleRange[1] * delta);
|
|
}
|
|
return [new Date(start2), new Date(stop)];
|
|
}
|
|
function rangeData(interval, start2, stop, { extend = false, visibleRange = [0, 1], limit, defaultAlignment = "start" } = {}) {
|
|
const params = timeInterval(interval);
|
|
const { unit, step, utc } = params;
|
|
let epoch;
|
|
if (params.epoch != null) {
|
|
epoch = params.epoch;
|
|
} else if (defaultAlignment === "interval") {
|
|
epoch = void 0;
|
|
} else if (start2.valueOf() > stop.valueOf()) {
|
|
epoch = stop;
|
|
} else {
|
|
epoch = start2;
|
|
}
|
|
const offset = getOffset(params.unit, params.step, epoch, params.utc);
|
|
let [d0, d1] = intervalExtent(start2, stop, visibleRange);
|
|
d0 = extend ? encodingFloor(d0, unit, step, utc, offset) : encodingCeil(d0, unit, step, utc, offset);
|
|
d1 = extend ? encodingCeil(d1, unit, step, utc, offset) : encodingFloor(d1, unit, step, utc, offset);
|
|
const e0 = encode(d0, unit, step, utc, offset);
|
|
let e1 = encode(d1, unit, step, utc, offset);
|
|
if (limit != null && e1 - e0 > limit) {
|
|
e1 = e0 + limit;
|
|
}
|
|
return {
|
|
range: [e0, e1],
|
|
unit,
|
|
step,
|
|
utc,
|
|
offset
|
|
};
|
|
}
|
|
function intervalRangeCount(interval, start2, stop, params) {
|
|
const {
|
|
range: [e0, e1]
|
|
} = rangeData(interval, start2, stop, params);
|
|
return Math.abs(e1 - e0);
|
|
}
|
|
function intervalRange(interval, start2, stop, params) {
|
|
const {
|
|
range: [e0, e1],
|
|
unit,
|
|
step,
|
|
utc,
|
|
offset
|
|
} = rangeData(interval, start2, stop, params);
|
|
const values = [];
|
|
for (let e = e0; e <= e1; e += 1) {
|
|
const d = decode(e, unit, step, utc, offset);
|
|
values.push(d);
|
|
}
|
|
return values;
|
|
}
|
|
function intervalRangeNumeric(interval, start2, stop, params) {
|
|
const {
|
|
range: [e0, e1],
|
|
unit,
|
|
step,
|
|
utc,
|
|
offset
|
|
} = rangeData(interval, start2, stop, params);
|
|
const count = Math.max(0, e1 - e0 + 1);
|
|
const encodedValues = new Array(count);
|
|
for (let i = 0; i < count; i++) {
|
|
encodedValues[i] = e0 + i;
|
|
}
|
|
return {
|
|
encodedValues,
|
|
encodingParams: { unit, step, utc, offset }
|
|
};
|
|
}
|
|
function decodeIntervalValue(encoded, encodingParams) {
|
|
return decode(encoded, encodingParams.unit, encodingParams.step, encodingParams.utc, encodingParams.offset);
|
|
}
|
|
var tzOffsetMs = (/* @__PURE__ */ new Date()).getTimezoneOffset() * 6e4;
|
|
var DURATION_SECOND = 1e3;
|
|
var DURATION_MINUTE = 6e4;
|
|
var DURATION_HOUR = 36e5;
|
|
function encodedToTimestamp(encoded, encodingParams) {
|
|
const { unit, step, utc, offset } = encodingParams;
|
|
const rawEncoded = encoded * step + offset;
|
|
switch (unit) {
|
|
case "millisecond":
|
|
return rawEncoded;
|
|
case "second": {
|
|
const tzOffset2 = utc ? 0 : tzOffsetMs;
|
|
return tzOffset2 + rawEncoded * DURATION_SECOND;
|
|
}
|
|
case "minute": {
|
|
const tzOffset2 = utc ? 0 : tzOffsetMs;
|
|
return tzOffset2 + rawEncoded * DURATION_MINUTE;
|
|
}
|
|
case "hour": {
|
|
const tzOffset2 = utc ? 0 : tzOffsetMs;
|
|
return tzOffset2 + rawEncoded * DURATION_HOUR;
|
|
}
|
|
default: {
|
|
const encoding = unitEncoding[unit];
|
|
return encoding.decode(rawEncoded, utc).valueOf();
|
|
}
|
|
}
|
|
}
|
|
function intervalRangeStartIndex(interval, start2, stop, { extend, visibleRange, limit, defaultAlignment } = {}) {
|
|
const {
|
|
range: [s]
|
|
} = rangeData(interval, start2, stop, { extend, visibleRange, limit, defaultAlignment });
|
|
const {
|
|
range: [s0]
|
|
} = rangeData(interval, start2, stop, { extend, limit, defaultAlignment });
|
|
return s - s0;
|
|
}
|
|
|
|
// packages/ag-charts-core/src/utils/time/time/index.ts
|
|
function intervalUnit(interval) {
|
|
return typeof interval === "string" ? interval : interval.unit;
|
|
}
|
|
function intervalStep(interval) {
|
|
return typeof interval === "string" ? 1 : interval.step ?? 1;
|
|
}
|
|
function intervalEpoch(interval) {
|
|
return typeof interval === "string" ? void 0 : interval.epoch;
|
|
}
|
|
function intervalHierarchy(interval) {
|
|
return unitEncoding[intervalUnit(interval)].hierarchy;
|
|
}
|
|
function intervalMilliseconds(interval) {
|
|
const step = intervalStep(interval);
|
|
return step * unitEncoding[intervalUnit(interval)].milliseconds;
|
|
}
|
|
|
|
// packages/ag-charts-core/src/utils/time/ticks.ts
|
|
var tInterval = (timeInterval2, step) => ({
|
|
duration: intervalMilliseconds(timeInterval2) * step,
|
|
timeInterval: timeInterval2,
|
|
step
|
|
});
|
|
var TickIntervals = [
|
|
tInterval({ unit: "second" }, 1),
|
|
tInterval({ unit: "second" }, 5),
|
|
tInterval({ unit: "second" }, 15),
|
|
tInterval({ unit: "second" }, 30),
|
|
tInterval({ unit: "minute" }, 1),
|
|
tInterval({ unit: "minute" }, 5),
|
|
tInterval({ unit: "minute" }, 15),
|
|
tInterval({ unit: "minute" }, 30),
|
|
tInterval({ unit: "hour" }, 1),
|
|
tInterval({ unit: "hour" }, 3),
|
|
tInterval({ unit: "hour" }, 6),
|
|
tInterval({ unit: "hour" }, 12),
|
|
tInterval({ unit: "day" }, 1),
|
|
tInterval({ unit: "day" }, 2),
|
|
tInterval({ unit: "day", step: 7 }, 1),
|
|
tInterval({ unit: "day", step: 7 }, 2),
|
|
tInterval({ unit: "day", step: 7 }, 3),
|
|
tInterval({ unit: "month" }, 1),
|
|
tInterval({ unit: "month" }, 2),
|
|
tInterval({ unit: "month" }, 3),
|
|
tInterval({ unit: "month" }, 4),
|
|
tInterval({ unit: "month" }, 6),
|
|
tInterval({ unit: "year" }, 1)
|
|
];
|
|
var TickMultipliers = [1, 2, 5, 10];
|
|
function isCloseToInteger(n, delta) {
|
|
return Math.abs(Math.round(n) - n) < delta;
|
|
}
|
|
function countTicks(d0, d1, step) {
|
|
const extent2 = Math.abs(d1 - d0);
|
|
return extent2 >= step ? Math.abs(d1 - d0) / step + 1 : 1;
|
|
}
|
|
function createTicks(start2, stop, count, minCount, maxCount, visibleRange) {
|
|
if (start2 === stop)
|
|
return { ticks: [start2], count: 1, firstTickIndex: 0 };
|
|
if (count < 2)
|
|
return { ticks: [start2, stop], count: 2, firstTickIndex: 0 };
|
|
const step = tickStep(start2, stop, count, minCount, maxCount);
|
|
if (!Number.isFinite(step))
|
|
return { ticks: [], count: 0, firstTickIndex: void 0 };
|
|
let d0 = start2;
|
|
let d1 = stop;
|
|
if (!isCloseToInteger(d0 / step, 1e-12)) {
|
|
d0 = Math.ceil(d0 / step) * step;
|
|
}
|
|
if (!isCloseToInteger(d1 / step, 1e-12)) {
|
|
d1 = Math.floor(d1 / step) * step;
|
|
}
|
|
if (visibleRange != null) {
|
|
visibleRange = rescaleVisibleRange(visibleRange, [start2, stop], [d0, d1]);
|
|
}
|
|
const { ticks } = range(d0, d1, step, visibleRange);
|
|
const firstTick = ticks.at(0);
|
|
return {
|
|
ticks,
|
|
count: countTicks(d0, d1, step),
|
|
firstTickIndex: firstTick == null ? void 0 : Math.round((firstTick - d0) / step)
|
|
};
|
|
}
|
|
var minPrimaryTickRatio = Math.floor(2 * durationWeek / durationMonth * 10) / 10;
|
|
function isPrimaryTickInterval({ timeInterval: timeInterval2, step }) {
|
|
const milliseconds = intervalMilliseconds(timeInterval2) * step;
|
|
const hierarchy = intervalHierarchy(timeInterval2);
|
|
const hierarchyMilliseconds = hierarchy ? intervalMilliseconds(hierarchy) : void 0;
|
|
return milliseconds <= (hierarchyMilliseconds ?? Infinity) * minPrimaryTickRatio;
|
|
}
|
|
function defaultEpoch(timeInterval2, { weekStart }) {
|
|
if (timeInterval2.unit === "day" && timeInterval2.step === 7) {
|
|
return weekStart;
|
|
}
|
|
}
|
|
function getTickTimeInterval(start2, stop, count, minCount, maxCount, {
|
|
weekStart,
|
|
primaryOnly = false,
|
|
targetInterval
|
|
}) {
|
|
if (count <= 0)
|
|
return;
|
|
const target = targetInterval ?? Math.abs(stop - start2) / Math.max(count, 1);
|
|
const i0 = TickIntervals.findLast((t) => (!primaryOnly || isPrimaryTickInterval(t)) && target > t.duration);
|
|
const i1 = TickIntervals.find((t) => (!primaryOnly || isPrimaryTickInterval(t)) && target <= t.duration);
|
|
if (i0 == null) {
|
|
const step2 = Math.max(tickStep(start2, stop, count, minCount, maxCount), 1);
|
|
return { unit: "millisecond", step: step2 };
|
|
} else if (i1 == null) {
|
|
const step2 = targetInterval == null ? tickStep(start2 / durationYear, stop / durationYear, count, minCount, maxCount) : 1;
|
|
return { unit: "year", step: step2 };
|
|
}
|
|
const { timeInterval: timeInterval2, step } = target - i0.duration < i1.duration - target ? i0 : i1;
|
|
return {
|
|
unit: timeInterval2.unit,
|
|
step: intervalStep(timeInterval2) * step,
|
|
epoch: defaultEpoch(timeInterval2, { weekStart })
|
|
};
|
|
}
|
|
function tickStep(start2, end2, count, minCount = 0, maxCount = Infinity) {
|
|
if (start2 === end2) {
|
|
return clamp(1, minCount, maxCount);
|
|
} else if (count < 1) {
|
|
return Number.NaN;
|
|
}
|
|
const extent2 = Math.abs(end2 - start2);
|
|
const step = 10 ** Math.floor(Math.log10(extent2 / count));
|
|
let m = Number.NaN, minDiff = Infinity, isInBounds = false;
|
|
for (const multiplier of TickMultipliers) {
|
|
const c = Math.ceil(extent2 / (multiplier * step));
|
|
const validBounds = c >= minCount && c <= maxCount;
|
|
if (isInBounds && !validBounds)
|
|
continue;
|
|
const diffCount = Math.abs(c - count);
|
|
if (minDiff > diffCount || isInBounds !== validBounds) {
|
|
isInBounds || (isInBounds = validBounds);
|
|
minDiff = diffCount;
|
|
m = multiplier;
|
|
}
|
|
}
|
|
return m * step;
|
|
}
|
|
function decimalPlaces(decimal) {
|
|
for (let i = decimal.length - 1; i >= 0; i -= 1) {
|
|
if (decimal[i] !== "0") {
|
|
return i + 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
function tickFormat(ticks, format) {
|
|
const options = parseNumberFormat(format ?? ",f");
|
|
if (options == null)
|
|
return;
|
|
if (options.precision == null || Number.isNaN(options.precision)) {
|
|
if (!options.type || "eEFgGnprs".includes(options.type)) {
|
|
options.precision = Math.max(
|
|
...ticks.map((x) => {
|
|
if (!Number.isFinite(x))
|
|
return 0;
|
|
const [integer, decimal] = x.toExponential((options.type ? 6 : 12) - 1).split(/[.e]/g);
|
|
return (integer !== "1" && integer !== "-1" ? 1 : 0) + decimalPlaces(decimal) + 1;
|
|
})
|
|
);
|
|
} else if ("f%".includes(options.type)) {
|
|
options.precision = Math.max(
|
|
...ticks.map((x) => {
|
|
if (!Number.isFinite(x) || x === 0)
|
|
return 0;
|
|
const l = Math.floor(Math.log10(Math.abs(x)));
|
|
const digits = options.type ? 6 : 12;
|
|
const decimal = x.toExponential(digits - 1).split(/[.e]/g)[1];
|
|
const decimalLength = decimalPlaces(decimal);
|
|
return Math.max(0, decimalLength - l);
|
|
})
|
|
);
|
|
}
|
|
}
|
|
const formatter2 = createNumberFormatter(options);
|
|
return (n) => formatter2(Number(n));
|
|
}
|
|
function range(start2, end2, step, visibleRange) {
|
|
if (!Number.isFinite(step) || step <= 0) {
|
|
return { ticks: [], count: 0, firstTickIndex: void 0 };
|
|
} else if (start2 === end2) {
|
|
return { ticks: [start2], count: 1, firstTickIndex: 0 };
|
|
}
|
|
const f = 10 ** countFractionDigits(step);
|
|
const d0 = Math.min(start2, end2);
|
|
const d1 = Math.max(start2, end2);
|
|
let vd0;
|
|
let vd1;
|
|
if (visibleRange != null && (visibleRange[0] !== 0 || visibleRange[1] !== 1)) {
|
|
const rangeExtent = end2 - start2;
|
|
const adjustedStart = start2 + rangeExtent * visibleRange[0];
|
|
const adjustedEnd = end2 - rangeExtent * (1 - visibleRange[1]);
|
|
vd0 = Math.min(adjustedStart, adjustedEnd);
|
|
vd1 = Math.max(adjustedStart, adjustedEnd);
|
|
} else {
|
|
vd0 = d0;
|
|
vd1 = d1;
|
|
}
|
|
vd0 = Math.floor(vd0 * f) / f;
|
|
vd1 = Math.ceil(vd1 * f) / f;
|
|
const ticks = [];
|
|
for (let i = 0; ; i += 1) {
|
|
const p = Math.round((d0 + step * i) * f) / f;
|
|
if (p > d1)
|
|
break;
|
|
if (p >= vd0 && p <= vd1) {
|
|
ticks.push(p);
|
|
}
|
|
}
|
|
const firstTick = ticks.at(0);
|
|
return {
|
|
ticks,
|
|
count: countTicks(d0, d1, step),
|
|
firstTickIndex: firstTick == null ? void 0 : Math.round((firstTick - d0) / step)
|
|
};
|
|
}
|
|
function isDenseInterval(count, availableRange) {
|
|
if (count >= availableRange) {
|
|
warnOnce(
|
|
`the configured interval results in more than 1 item per pixel, ignoring. Supply a larger interval or omit this configuration`
|
|
);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
function niceTicksDomain(start2, end2) {
|
|
const extent2 = Math.abs(end2 - start2);
|
|
const step = 10 ** Math.floor(Math.log10(extent2));
|
|
let minError = Infinity, ticks = [start2, end2];
|
|
for (const multiplier of TickMultipliers) {
|
|
const m = multiplier * step;
|
|
const d0 = Math.floor(start2 / m) * m;
|
|
const d1 = Math.ceil(end2 / m) * m;
|
|
const error2 = 1 - extent2 / Math.abs(d1 - d0);
|
|
if (minError > error2) {
|
|
minError = error2;
|
|
ticks = [d0, d1];
|
|
}
|
|
}
|
|
return ticks;
|
|
}
|
|
function estimateTickCount(rangeExtent, zoomExtent, minSpacing, maxSpacing, defaultTickCount, defaultMinSpacing) {
|
|
if (rangeExtent <= 0) {
|
|
return { minTickCount: 0, maxTickCount: 0, tickCount: 0 };
|
|
}
|
|
defaultMinSpacing = Math.max(defaultMinSpacing, rangeExtent / (defaultTickCount + 1));
|
|
minSpacing ?? (minSpacing = defaultMinSpacing);
|
|
maxSpacing ?? (maxSpacing = rangeExtent);
|
|
if (minSpacing > maxSpacing) {
|
|
if (minSpacing === defaultMinSpacing) {
|
|
minSpacing = maxSpacing;
|
|
} else {
|
|
maxSpacing = minSpacing;
|
|
}
|
|
}
|
|
minSpacing = Math.max(minSpacing, 1);
|
|
const maxTickCount = Math.max(1, Math.floor(rangeExtent / (zoomExtent * minSpacing)));
|
|
const minTickCount = Math.min(maxTickCount, Math.ceil(rangeExtent / (zoomExtent * maxSpacing)));
|
|
const tickCount = clamp(minTickCount, Math.floor(defaultTickCount / zoomExtent), maxTickCount);
|
|
return { minTickCount, maxTickCount, tickCount };
|
|
}
|
|
|
|
// packages/ag-charts-core/src/utils/time/timeFormatDefaults.ts
|
|
function dateToNumber(value) {
|
|
return value instanceof Date ? value.getTime() : value;
|
|
}
|
|
function lowestGranularityForInterval(interval) {
|
|
if (interval < durationSecond) {
|
|
return "millisecond";
|
|
} else if (interval < durationMinute) {
|
|
return "second";
|
|
} else if (interval < durationHour) {
|
|
return "minute";
|
|
} else if (interval < durationHour * 23) {
|
|
return "hour";
|
|
} else if (interval < 28 * durationDay) {
|
|
return "day";
|
|
} else if (interval < durationYear) {
|
|
return "month";
|
|
} else {
|
|
return "year";
|
|
}
|
|
}
|
|
function lowestGranularityUnitForTicks(ticks) {
|
|
if (ticks.length === 0) {
|
|
return "millisecond";
|
|
} else if (ticks.length === 1) {
|
|
return lowestGranularityUnitForValue(ticks[0]);
|
|
}
|
|
let minInterval = Infinity;
|
|
for (let i = 1; i < ticks.length; i++) {
|
|
minInterval = Math.min(minInterval, Math.abs(ticks[i].valueOf() - ticks[i - 1].valueOf()));
|
|
}
|
|
return lowestGranularityForInterval(minInterval);
|
|
}
|
|
function lowestGranularityUnitForValue(value) {
|
|
if (intervalFloor("second", value) < value) {
|
|
return "millisecond";
|
|
} else if (intervalFloor("minute", value) < value) {
|
|
return "second";
|
|
} else if (intervalFloor("hour", value) < value) {
|
|
return "minute";
|
|
} else if (intervalFloor("day", value) < value) {
|
|
return "hour";
|
|
} else if (intervalFloor("month", value) < value) {
|
|
return "day";
|
|
} else if (intervalFloor("year", value) < value) {
|
|
return "month";
|
|
}
|
|
return "year";
|
|
}
|
|
function dateTruncationForDomain(domain) {
|
|
const [d0, d1] = domain.length === 0 ? [0, 0] : findMinMax([domain[0].valueOf(), domain.at(-1).valueOf()]);
|
|
const startYear = new Date(d0).getFullYear();
|
|
const stopYear = new Date(d1).getFullYear();
|
|
if (startYear !== stopYear)
|
|
return;
|
|
const startMonth = new Date(d0).getMonth();
|
|
const stopMonth = new Date(d1).getMonth();
|
|
if (startMonth !== stopMonth)
|
|
return "year";
|
|
const startDate = new Date(d0).getDate();
|
|
const stopDate = new Date(d1).getDate();
|
|
if (startDate !== stopDate)
|
|
return "month";
|
|
return "day";
|
|
}
|
|
|
|
// packages/ag-charts-core/src/identity/idGenerator.ts
|
|
function createIdsGenerator() {
|
|
const idsCounter = /* @__PURE__ */ new Map();
|
|
return (name) => {
|
|
const counter = idsCounter.get(name);
|
|
if (counter) {
|
|
idsCounter.set(name, counter + 1);
|
|
return `${name}_${counter}`;
|
|
}
|
|
idsCounter.set(name, 1);
|
|
return name;
|
|
};
|
|
}
|
|
|
|
// packages/ag-charts-core/src/utils/data/value.ts
|
|
function isStringObject(value) {
|
|
return value != null && Object.hasOwn(value, "toString") && isString(value.toString());
|
|
}
|
|
function isNumberObject(value) {
|
|
return value != null && Object.hasOwn(value, "valueOf") && isFiniteNumber(value.valueOf());
|
|
}
|
|
function isContinuous(value) {
|
|
return isFiniteNumber(value) || isValidDate(value) || isNumberObject(value);
|
|
}
|
|
function checkDatum(value, isContinuousScale) {
|
|
return value != null && (!isContinuousScale || isContinuous(value));
|
|
}
|
|
function transformIntegratedCategoryValue(value) {
|
|
if (isStringObject(value) && Object.hasOwn(value, "id")) {
|
|
return value.id;
|
|
}
|
|
return value;
|
|
}
|
|
function readIntegratedWrappedValue(value) {
|
|
if (isStringObject(value) && Object.hasOwn(value, "value")) {
|
|
return value.value;
|
|
}
|
|
return value;
|
|
}
|
|
|
|
// packages/ag-charts-core/src/utils/geometry/vector.ts
|
|
var vector_exports = {};
|
|
__export(vector_exports, {
|
|
add: () => add,
|
|
angle: () => angle,
|
|
apply: () => apply,
|
|
distance: () => distance,
|
|
distanceSquared: () => distanceSquared,
|
|
equal: () => equal,
|
|
from: () => from,
|
|
gradient: () => gradient,
|
|
intercept: () => intercept,
|
|
intersectAtX: () => intersectAtX,
|
|
intersectAtY: () => intersectAtY,
|
|
length: () => length,
|
|
lengthSquared: () => lengthSquared,
|
|
multiply: () => multiply,
|
|
normalized: () => normalized,
|
|
origin: () => origin,
|
|
required: () => required2,
|
|
rotate: () => rotate,
|
|
round: () => round,
|
|
sub: () => sub
|
|
});
|
|
function add(a, b) {
|
|
if (typeof b === "number") {
|
|
return { x: a.x + b, y: a.y + b };
|
|
}
|
|
return { x: a.x + b.x, y: a.y + b.y };
|
|
}
|
|
function sub(a, b) {
|
|
if (typeof b === "number") {
|
|
return { x: a.x - b, y: a.y - b };
|
|
}
|
|
return { x: a.x - b.x, y: a.y - b.y };
|
|
}
|
|
function multiply(a, b) {
|
|
if (typeof b === "number") {
|
|
return { x: a.x * b, y: a.y * b };
|
|
}
|
|
return { x: a.x * b.x, y: a.y * b.y };
|
|
}
|
|
function length(a) {
|
|
return Math.hypot(a.x, a.y);
|
|
}
|
|
function lengthSquared(a) {
|
|
return a.x * a.x + a.y * a.y;
|
|
}
|
|
function distance(a, b) {
|
|
return length(sub(a, b));
|
|
}
|
|
function distanceSquared(a, b) {
|
|
return lengthSquared(sub(a, b));
|
|
}
|
|
function normalized(a) {
|
|
const l = length(a);
|
|
return { x: a.x / l, y: a.y / l };
|
|
}
|
|
function angle(a, b) {
|
|
if (b == null)
|
|
return Math.atan2(a.y, a.x);
|
|
return Math.atan2(a.y, a.x) - Math.atan2(b.y, b.x);
|
|
}
|
|
function rotate(a, theta, b = origin()) {
|
|
const l = length(a);
|
|
return { x: b.x + l * Math.cos(theta), y: b.y + l * Math.sin(theta) };
|
|
}
|
|
function gradient(a, b, reflection) {
|
|
const dx = b.x - a.x;
|
|
const dy = reflection == null ? b.y - a.y : reflection - b.y - (reflection - a.y);
|
|
return dy / dx;
|
|
}
|
|
function intercept(a, gradient2, reflection) {
|
|
const y = reflection == null ? a.y : reflection - a.y;
|
|
return y - gradient2 * a.x;
|
|
}
|
|
function intersectAtY(gradient2, coefficient, y = 0, reflection) {
|
|
return {
|
|
x: gradient2 === Infinity ? Infinity : (y - coefficient) / gradient2,
|
|
y: reflection == null ? y : reflection - y
|
|
};
|
|
}
|
|
function intersectAtX(gradient2, coefficient, x = 0, reflection) {
|
|
const y = gradient2 === Infinity ? Infinity : gradient2 * x + coefficient;
|
|
return { x, y: reflection == null ? y : reflection - y };
|
|
}
|
|
function round(a, decimals = 2) {
|
|
return { x: roundTo(a.x, decimals), y: roundTo(a.y, decimals) };
|
|
}
|
|
function equal(a, b) {
|
|
return a.x === b.x && a.y === b.y;
|
|
}
|
|
function from(a, b) {
|
|
if (typeof a === "number") {
|
|
return { x: a, y: b };
|
|
}
|
|
if ("currentX" in a) {
|
|
return { x: a.currentX, y: a.currentY };
|
|
}
|
|
if ("offsetWidth" in a) {
|
|
return { x: a.offsetWidth, y: a.offsetHeight };
|
|
}
|
|
if ("width" in a) {
|
|
return [
|
|
{ x: a.x, y: a.y },
|
|
{ x: a.x + a.width, y: a.y + a.height }
|
|
];
|
|
}
|
|
if ("x1" in a) {
|
|
return [
|
|
{ x: a.x1, y: a.y1 },
|
|
{ x: a.x2, y: a.y2 }
|
|
];
|
|
}
|
|
throw new Error(`Values can not be converted into a vector: [${JSON.stringify(a)}] [${b}]`);
|
|
}
|
|
function apply(a, b) {
|
|
a.x = b.x;
|
|
a.y = b.y;
|
|
return a;
|
|
}
|
|
function required2(a) {
|
|
return { x: a?.x ?? 0, y: a?.y ?? 0 };
|
|
}
|
|
function origin() {
|
|
return { x: 0, y: 0 };
|
|
}
|
|
|
|
// packages/ag-charts-core/src/utils/geometry/vector4.ts
|
|
var vector4_exports = {};
|
|
__export(vector4_exports, {
|
|
bottomCenter: () => bottomCenter,
|
|
center: () => center,
|
|
clone: () => clone,
|
|
collides: () => collides,
|
|
end: () => end,
|
|
from: () => from2,
|
|
height: () => height,
|
|
normalise: () => normalise,
|
|
origin: () => origin2,
|
|
round: () => round2,
|
|
start: () => start,
|
|
topCenter: () => topCenter,
|
|
width: () => width
|
|
});
|
|
function start(a) {
|
|
return { x: a.x1, y: a.y1 };
|
|
}
|
|
function end(a) {
|
|
return { x: a.x2, y: a.y2 };
|
|
}
|
|
function topCenter(a) {
|
|
return { x: (a.x1 + a.x2) / 2, y: Math.min(a.y1, a.y2) };
|
|
}
|
|
function center(a) {
|
|
return { x: (a.x1 + a.x2) / 2, y: (a.y1 + a.y2) / 2 };
|
|
}
|
|
function bottomCenter(a) {
|
|
return { x: (a.x1 + a.x2) / 2, y: Math.max(a.y1, a.y2) };
|
|
}
|
|
function width(a) {
|
|
return Math.abs(a.x2 - a.x1);
|
|
}
|
|
function height(a) {
|
|
return Math.abs(a.y2 - a.y1);
|
|
}
|
|
function round2(a) {
|
|
return { x1: Math.round(a.x1), y1: Math.round(a.y1), x2: Math.round(a.x2), y2: Math.round(a.y2) };
|
|
}
|
|
function clone(a) {
|
|
return { x1: a.x1, y1: a.y1, x2: a.x2, y2: a.y2 };
|
|
}
|
|
function collides(a, b) {
|
|
const an = normalise(a);
|
|
const bn = normalise(b);
|
|
return an.x1 <= bn.x2 && an.x2 >= bn.x1 && an.y1 <= bn.y2 && an.y2 >= bn.y1;
|
|
}
|
|
function normalise(a) {
|
|
return {
|
|
x1: Math.min(a.x1, a.x2),
|
|
x2: Math.max(a.x1, a.x2),
|
|
y1: Math.min(a.y1, a.y2),
|
|
y2: Math.max(a.y1, a.y2)
|
|
};
|
|
}
|
|
function from2(a, b, c, d) {
|
|
if (typeof a === "number") {
|
|
return { x1: a, y1: b, x2: c, y2: d };
|
|
}
|
|
if ("width" in a) {
|
|
return normalise({
|
|
x1: a.x,
|
|
y1: a.y,
|
|
x2: a.x + a.width,
|
|
y2: a.y + a.height
|
|
});
|
|
}
|
|
throw new Error(`Values can not be converted into a vector4: [${JSON.stringify(a)}] [${b}] [${c}] [${d}]`);
|
|
}
|
|
function origin2() {
|
|
return { x1: 0, y1: 0, x2: 0, y2: 0 };
|
|
}
|
|
|
|
// packages/ag-charts-core/src/utils/geometry/fill.ts
|
|
function isGradientFill(fill) {
|
|
return isObject(fill) && fill.type == "gradient";
|
|
}
|
|
function isGradientFillArray(fills) {
|
|
return isArray(fills) && fills.every(isGradientFill);
|
|
}
|
|
function isStringFillArray(fills) {
|
|
return isArray(fills) && fills.every((fill) => typeof fill === "string");
|
|
}
|
|
function isPatternFill(fill) {
|
|
return fill !== null && isObject(fill) && fill.type == "pattern";
|
|
}
|
|
function isImageFill(fill) {
|
|
return fill !== null && isObject(fill) && fill.type == "image";
|
|
}
|
|
function isGradientOrPatternFill(fill) {
|
|
return isGradientFill(fill) || isPatternFill(fill);
|
|
}
|
|
|
|
// packages/ag-charts-core/src/utils/geometry/bezier.ts
|
|
function evaluateBezier(p0, p1, p2, p3, t) {
|
|
return (1 - t) ** 3 * p0 + 3 * (1 - t) ** 2 * t * p1 + 3 * (1 - t) * t ** 2 * p2 + t ** 3 * p3;
|
|
}
|
|
function solveBezier(p0, p1, p2, p3, value) {
|
|
if (value <= Math.min(p0, p3)) {
|
|
return p0 < p3 ? 0 : 1;
|
|
} else if (value >= Math.max(p0, p3)) {
|
|
return p0 < p3 ? 1 : 0;
|
|
}
|
|
let t0 = 0;
|
|
let t1 = 1;
|
|
let t = Number.NaN;
|
|
for (let i = 0; i < 12; i += 1) {
|
|
t = (t0 + t1) / 2;
|
|
const curveValue = evaluateBezier(p0, p1, p2, p3, t);
|
|
if (curveValue < value) {
|
|
t0 = t;
|
|
} else {
|
|
t1 = t;
|
|
}
|
|
}
|
|
return t;
|
|
}
|
|
function splitBezier2D(p0x, p0y, p1x, p1y, p2x, p2y, p3x, p3y, t) {
|
|
const x01 = (1 - t) * p0x + t * p1x;
|
|
const y01 = (1 - t) * p0y + t * p1y;
|
|
const x12 = (1 - t) * p1x + t * p2x;
|
|
const y12 = (1 - t) * p1y + t * p2y;
|
|
const x23 = (1 - t) * p2x + t * p3x;
|
|
const y23 = (1 - t) * p2y + t * p3y;
|
|
const x012 = (1 - t) * x01 + t * x12;
|
|
const y012 = (1 - t) * y01 + t * y12;
|
|
const x123 = (1 - t) * x12 + t * x23;
|
|
const y123 = (1 - t) * y12 + t * y23;
|
|
const x0123 = (1 - t) * x012 + t * x123;
|
|
const y0123 = (1 - t) * y012 + t * y123;
|
|
return [
|
|
[
|
|
{ x: p0x, y: p0y },
|
|
{ x: x01, y: y01 },
|
|
{ x: x012, y: y012 },
|
|
{ x: x0123, y: y0123 }
|
|
],
|
|
[
|
|
{ x: x0123, y: y0123 },
|
|
{ x: x123, y: y123 },
|
|
{ x: x23, y: y23 },
|
|
{ x: p3x, y: p3y }
|
|
]
|
|
];
|
|
}
|
|
function calculateDerivativeExtrema(p0, p1, p2, p3) {
|
|
const a = -p0 + 3 * p1 - 3 * p2 + p3;
|
|
const b = 2 * (p0 - 2 * p1 + p2);
|
|
const c = -p0 + p1;
|
|
if (a === 0) {
|
|
if (b !== 0) {
|
|
const t = -c / b;
|
|
if (t > 0 && t < 1) {
|
|
return [t];
|
|
}
|
|
}
|
|
return [];
|
|
}
|
|
const discriminant = b * b - 4 * a * c;
|
|
if (discriminant >= 0) {
|
|
const sqrtDiscriminant = Math.sqrt(discriminant);
|
|
const t1 = (-b + sqrtDiscriminant) / (2 * a);
|
|
const t2 = (-b - sqrtDiscriminant) / (2 * a);
|
|
return [t1, t2].filter((t) => t > 0 && t < 1);
|
|
}
|
|
return [];
|
|
}
|
|
function bezier2DExtrema(cp0x, cp0y, cp1x, cp1y, cp2x, cp2y, cp3x, cp3y) {
|
|
const tx = calculateDerivativeExtrema(cp0x, cp1x, cp2x, cp3x);
|
|
const ty = calculateDerivativeExtrema(cp0y, cp1y, cp2y, cp3y);
|
|
return [...tx, ...ty];
|
|
}
|
|
function bezierCandidate(points, x, y) {
|
|
const midX = evaluateBezier(points[0].x, points[1].x, points[2].x, points[3].x, 0.5);
|
|
const midY = evaluateBezier(points[0].y, points[1].y, points[2].y, points[3].y, 0.5);
|
|
const distance2 = Math.hypot(midX - x, midY - y);
|
|
const minDistance = Math.min(
|
|
Math.hypot(points[0].x - x, points[0].y - y),
|
|
Math.hypot(points[1].x - x, points[1].y - y),
|
|
Math.hypot(points[2].x - x, points[2].y - y),
|
|
Math.hypot(points[3].x - x, points[3].y - y)
|
|
);
|
|
return { points, distance: distance2, minDistance };
|
|
}
|
|
function bezier2DDistance(cp0x, cp0y, cp1x, cp1y, cp2x, cp2y, cp3x, cp3y, x, y, precision = 1) {
|
|
const points0 = [
|
|
{ x: cp0x, y: cp0y },
|
|
{ x: cp1x, y: cp1y },
|
|
{ x: cp2x, y: cp2y },
|
|
{ x: cp3x, y: cp3y }
|
|
];
|
|
let queue = {
|
|
value: bezierCandidate(points0, x, y),
|
|
next: null
|
|
};
|
|
let bestResult;
|
|
while (queue != null) {
|
|
const { points, distance: distance2, minDistance } = queue.value;
|
|
queue = queue.next;
|
|
if (bestResult == null || distance2 < bestResult.distance) {
|
|
bestResult = { distance: distance2, minDistance };
|
|
}
|
|
if (bestResult != null && bestResult.distance - minDistance <= precision) {
|
|
continue;
|
|
}
|
|
const [leftPoints, rightPoints] = splitBezier2D(
|
|
points[0].x,
|
|
points[0].y,
|
|
points[1].x,
|
|
points[1].y,
|
|
points[2].x,
|
|
points[2].y,
|
|
points[3].x,
|
|
points[3].y,
|
|
0.5
|
|
);
|
|
const newCandidates = [bezierCandidate(leftPoints, x, y), bezierCandidate(rightPoints, x, y)].sort(
|
|
bezierCandidateCmp
|
|
);
|
|
queue = insertListItemsSorted(queue, newCandidates, bezierCandidateCmp);
|
|
}
|
|
return bestResult?.distance ?? Infinity;
|
|
}
|
|
var bezierCandidateCmp = (a, b) => b.minDistance - a.minDistance;
|
|
|
|
// packages/ag-charts-core/src/utils/geometry/labelPlacement.ts
|
|
function circleRectOverlap({ point: c, anchor: unitCenter }, x, y, w, h) {
|
|
if (c.size === 0) {
|
|
return false;
|
|
}
|
|
let cx = c.x;
|
|
let cy = c.y;
|
|
if (unitCenter != null) {
|
|
cx -= (unitCenter.x - 0.5) * c.size;
|
|
cy -= (unitCenter.y - 0.5) * c.size;
|
|
}
|
|
let edgeX = cx;
|
|
if (cx < x) {
|
|
edgeX = x;
|
|
} else if (cx > x + w) {
|
|
edgeX = x + w;
|
|
}
|
|
let edgeY = cy;
|
|
if (cy < y) {
|
|
edgeY = y;
|
|
} else if (cy > y + h) {
|
|
edgeY = y + h;
|
|
}
|
|
const dx = cx - edgeX;
|
|
const dy = cy - edgeY;
|
|
const d = Math.hypot(dx, dy);
|
|
return d <= c.size / 2;
|
|
}
|
|
function isPointLabelDatum(x) {
|
|
return x != null && typeof x.point === "object" && typeof x.label === "object";
|
|
}
|
|
var labelPlacements = {
|
|
top: { x: 0, y: -1 },
|
|
bottom: { x: 0, y: 1 },
|
|
left: { x: -1, y: 0 },
|
|
right: { x: 1, y: 0 },
|
|
"top-left": { x: -1, y: -1 },
|
|
"top-right": { x: 1, y: -1 },
|
|
"bottom-left": { x: -1, y: 1 },
|
|
"bottom-right": { x: 1, y: 1 }
|
|
};
|
|
function placeLabels(data, bounds, padding2 = 5) {
|
|
const result = /* @__PURE__ */ new Map();
|
|
const previousResults = [];
|
|
const sortedDataClone = new Map(
|
|
Array.from(data.entries(), ([k, d]) => [k, d.toSorted((a, b) => b.point.size - a.point.size)])
|
|
);
|
|
const dataValues = [...sortedDataClone.values()].flat();
|
|
for (const [seriesId, datums] of sortedDataClone.entries()) {
|
|
const labels = [];
|
|
if (!datums[0]?.label)
|
|
continue;
|
|
for (let index = 0, ln = datums.length; index < ln; index++) {
|
|
const d = datums[index];
|
|
const { point, label, anchor } = d;
|
|
const { text, width: width2, height: height2 } = label;
|
|
const r = point.size / 2;
|
|
let dx = 0;
|
|
let dy = 0;
|
|
if (r > 0 && d.placement != null) {
|
|
const placement = labelPlacements[d.placement];
|
|
dx = (width2 / 2 + r + padding2) * placement.x;
|
|
dy = (height2 / 2 + r + padding2) * placement.y;
|
|
}
|
|
let x = point.x - width2 / 2 + dx;
|
|
let y = point.y - height2 / 2 + dy;
|
|
if (anchor) {
|
|
x -= (anchor.x - 0.5) * point.size;
|
|
y -= (anchor.y - 0.5) * point.size;
|
|
}
|
|
if (boxContains(bounds, x, y, width2, height2) && !dataValues.some((dataDatum) => circleRectOverlap(dataDatum, x, y, width2, height2)) && !previousResults.some((pr) => boxCollides(pr, x, y, width2, height2))) {
|
|
const resultDatum = { index, text, x, y, width: width2, height: height2, datum: d };
|
|
labels.push(resultDatum);
|
|
previousResults.push(resultDatum);
|
|
}
|
|
}
|
|
result.set(seriesId, labels);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// packages/ag-charts-core/src/utils/geometry/scaling.ts
|
|
function isContinuousScaling(scaling) {
|
|
return scaling.type === "continuous" || scaling.type === "log";
|
|
}
|
|
function isCategoryScaling(scaling) {
|
|
return scaling.type === "category";
|
|
}
|
|
function isUnitTimeCategoryScaling(scaling) {
|
|
return "variant" in scaling && scaling.variant === "unit-time";
|
|
}
|
|
function isStandardCategoryScaling(scaling) {
|
|
return !("variant" in scaling);
|
|
}
|
|
function areScalingEqual(a, b) {
|
|
if (a === void 0 || b === void 0) {
|
|
return a !== void 0 || b !== void 0;
|
|
}
|
|
if (isContinuousScaling(a) && isContinuousScaling(b)) {
|
|
return a.type === b.type && arraysEqual(a.domain, b.domain) && arraysEqual(a.range, b.range);
|
|
}
|
|
if (isCategoryScaling(a) && isCategoryScaling(b)) {
|
|
if (isUnitTimeCategoryScaling(a) && isUnitTimeCategoryScaling(b)) {
|
|
return a.firstBandTime === b.firstBandTime && a.lastBandTime === b.lastBandTime && a.bandCount === b.bandCount && a.intervalMs === b.intervalMs && a.inset === b.inset && a.step === b.step;
|
|
}
|
|
if (isStandardCategoryScaling(a) && isStandardCategoryScaling(b)) {
|
|
return a.inset === b.inset && a.step === b.step && arraysEqual(a.domain, b.domain);
|
|
}
|
|
return false;
|
|
}
|
|
return false;
|
|
}
|
|
function isScaleValid(scale) {
|
|
if (scale == null)
|
|
return false;
|
|
if (scale.type === "category") {
|
|
if (isUnitTimeCategoryScaling(scale)) {
|
|
return Number.isFinite(scale.firstBandTime) && Number.isFinite(scale.lastBandTime) && Number.isFinite(scale.bandCount) && scale.bandCount > 0;
|
|
}
|
|
return scale.domain.every((v) => v != null);
|
|
}
|
|
return scale.domain.every((v) => Number.isFinite(v) || v instanceof Date) && scale.range.every((v) => Number.isFinite(v));
|
|
}
|
|
|
|
// packages/ag-charts-core/src/utils/geometry/lineInterpolation.ts
|
|
function spanRange(span) {
|
|
switch (span.type) {
|
|
case "linear":
|
|
case "step":
|
|
case "multi-line":
|
|
return [
|
|
{ x: span.x0, y: span.y0 },
|
|
{ x: span.x1, y: span.y1 }
|
|
];
|
|
case "cubic":
|
|
return [
|
|
{ x: span.cp0x, y: span.cp0y },
|
|
{ x: span.cp3x, y: span.cp3y }
|
|
];
|
|
}
|
|
}
|
|
function spanRangeNormalized(span) {
|
|
const range2 = spanRange(span);
|
|
if (range2[0].x > range2[1].x) {
|
|
range2.reverse();
|
|
}
|
|
return range2;
|
|
}
|
|
function collapseSpanToPoint(span, point) {
|
|
const { x, y } = point;
|
|
switch (span.type) {
|
|
case "linear":
|
|
return {
|
|
type: "linear",
|
|
moveTo: span.moveTo,
|
|
x0: x,
|
|
y0: y,
|
|
x1: x,
|
|
y1: y
|
|
};
|
|
case "step":
|
|
return {
|
|
type: "step",
|
|
moveTo: span.moveTo,
|
|
x0: x,
|
|
y0: y,
|
|
x1: x,
|
|
y1: y,
|
|
stepX: x
|
|
};
|
|
case "cubic":
|
|
return {
|
|
type: "cubic",
|
|
moveTo: span.moveTo,
|
|
cp0x: x,
|
|
cp0y: y,
|
|
cp1x: x,
|
|
cp1y: y,
|
|
cp2x: x,
|
|
cp2y: y,
|
|
cp3x: x,
|
|
cp3y: y
|
|
};
|
|
case "multi-line":
|
|
return {
|
|
type: "multi-line",
|
|
moveTo: span.moveTo,
|
|
x0: x,
|
|
y0: y,
|
|
x1: x,
|
|
y1: y,
|
|
midPoints: span.midPoints.map(() => ({ x, y }))
|
|
};
|
|
}
|
|
}
|
|
function rescaleSpan(span, nextStart, nextEnd) {
|
|
const [prevStart, prevEnd] = spanRange(span);
|
|
const widthScale = prevEnd.x === prevStart.x ? 0 : (nextEnd.x - nextStart.x) / (prevEnd.x - prevStart.x);
|
|
const heightScale = prevEnd.y === prevStart.y ? 0 : (nextEnd.y - nextStart.y) / (prevEnd.y - prevStart.y);
|
|
switch (span.type) {
|
|
case "linear":
|
|
return {
|
|
type: "linear",
|
|
moveTo: span.moveTo,
|
|
x0: nextStart.x,
|
|
y0: nextStart.y,
|
|
x1: nextEnd.x,
|
|
y1: nextEnd.y
|
|
};
|
|
case "cubic":
|
|
return {
|
|
type: "cubic",
|
|
moveTo: span.moveTo,
|
|
cp0x: nextStart.x,
|
|
cp0y: nextStart.y,
|
|
cp1x: nextEnd.x - (span.cp2x - prevStart.x) * widthScale,
|
|
cp1y: nextEnd.y - (span.cp2y - prevStart.y) * heightScale,
|
|
cp2x: nextEnd.x - (span.cp1x - prevStart.x) * widthScale,
|
|
cp2y: nextEnd.y - (span.cp1y - prevStart.y) * heightScale,
|
|
cp3x: nextEnd.x,
|
|
cp3y: nextEnd.y
|
|
};
|
|
case "step":
|
|
return {
|
|
type: "step",
|
|
moveTo: span.moveTo,
|
|
x0: nextStart.x,
|
|
y0: nextStart.y,
|
|
x1: nextEnd.x,
|
|
y1: nextEnd.y,
|
|
stepX: nextEnd.x - (span.stepX - prevStart.x) * widthScale
|
|
};
|
|
case "multi-line":
|
|
return {
|
|
type: "multi-line",
|
|
moveTo: span.moveTo,
|
|
x0: nextStart.x,
|
|
y0: nextStart.y,
|
|
x1: nextEnd.x,
|
|
y1: nextEnd.y,
|
|
midPoints: span.midPoints.map((midPoint) => ({
|
|
x: nextStart.x + (midPoint.x - prevStart.x) * widthScale,
|
|
y: nextStart.y + (midPoint.y - prevStart.y) * heightScale
|
|
}))
|
|
};
|
|
}
|
|
}
|
|
function clipSpanX(span, x0, x1) {
|
|
const { moveTo } = span;
|
|
const [start2, end2] = spanRangeNormalized(span);
|
|
const { x: spanX0, y: spanY0 } = start2;
|
|
const { x: spanX1, y: spanY1 } = end2;
|
|
if (x1 < spanX0) {
|
|
return rescaleSpan(span, start2, start2);
|
|
} else if (x0 > spanX1) {
|
|
return rescaleSpan(span, end2, end2);
|
|
}
|
|
switch (span.type) {
|
|
case "linear": {
|
|
const m = spanY0 === spanY1 ? void 0 : (spanY1 - spanY0) / (spanX1 - spanX0);
|
|
const y0 = m == null ? spanY0 : m * (x0 - spanX0) + spanY0;
|
|
const y1 = m == null ? spanY0 : m * (x1 - spanX0) + spanY0;
|
|
return { type: "linear", moveTo, x0, y0, x1, y1 };
|
|
}
|
|
case "step":
|
|
if (x1 <= span.stepX) {
|
|
const y = span.y0;
|
|
return { type: "step", moveTo, x0, y0: y, x1, y1: y, stepX: x1 };
|
|
} else if (x0 >= span.stepX) {
|
|
const y = span.y1;
|
|
return { type: "step", moveTo, x0, y0: y, x1, y1: y, stepX: x0 };
|
|
} else {
|
|
const { y0, y1, stepX } = span;
|
|
return { type: "step", moveTo, x0, y0, x1, y1, stepX };
|
|
}
|
|
case "cubic": {
|
|
const t0 = solveBezier(span.cp0x, span.cp1x, span.cp2x, span.cp3x, x0);
|
|
let [_unused, bezier] = splitBezier2D(
|
|
span.cp0x,
|
|
span.cp0y,
|
|
span.cp1x,
|
|
span.cp1y,
|
|
span.cp2x,
|
|
span.cp2y,
|
|
span.cp3x,
|
|
span.cp3y,
|
|
t0
|
|
);
|
|
const t1 = solveBezier(bezier[0].x, bezier[1].x, bezier[2].x, bezier[3].x, x1);
|
|
[bezier, _unused] = splitBezier2D(
|
|
bezier[0].x,
|
|
bezier[0].y,
|
|
bezier[1].x,
|
|
bezier[1].y,
|
|
bezier[2].x,
|
|
bezier[2].y,
|
|
bezier[3].x,
|
|
bezier[3].y,
|
|
t1
|
|
);
|
|
return {
|
|
type: "cubic",
|
|
moveTo,
|
|
cp0x: bezier[0].x,
|
|
cp0y: bezier[0].y,
|
|
cp1x: bezier[1].x,
|
|
cp1y: bezier[1].y,
|
|
cp2x: bezier[2].x,
|
|
cp2y: bezier[2].y,
|
|
cp3x: bezier[3].x,
|
|
cp3y: bezier[3].y
|
|
};
|
|
}
|
|
case "multi-line": {
|
|
const { midPoints } = span;
|
|
const midPointStartIndex = midPoints.findLastIndex((midPoint) => midPoint.x <= x0);
|
|
let midPointEndIndex = midPoints.findIndex((midPoint) => midPoint.x >= x1);
|
|
if (midPointEndIndex === -1)
|
|
midPointEndIndex = midPoints.length;
|
|
const startPoint = midPointStartIndex >= 0 ? midPoints[midPointStartIndex] : void 0;
|
|
const startX = startPoint?.x ?? spanX0;
|
|
const startY = startPoint?.y ?? spanY0;
|
|
const endPoint = midPointEndIndex < midPoints.length ? midPoints[midPointEndIndex] : void 0;
|
|
const endX = endPoint?.x ?? spanX1;
|
|
const endY = endPoint?.y ?? spanY1;
|
|
const m = startY === endY ? void 0 : (endY - startY) / (endX - startX);
|
|
const y0 = m == null ? startY : m * (startX - spanX0) + startY;
|
|
const y1 = m == null ? startY : m * (endX - spanX0) + startY;
|
|
return {
|
|
type: "multi-line",
|
|
moveTo,
|
|
x0,
|
|
y0,
|
|
x1,
|
|
y1,
|
|
midPoints: midPoints.slice(Math.max(midPointStartIndex, 0), midPointEndIndex)
|
|
};
|
|
}
|
|
}
|
|
}
|
|
var SpanJoin = /* @__PURE__ */ ((SpanJoin2) => {
|
|
SpanJoin2[SpanJoin2["MoveTo"] = 0] = "MoveTo";
|
|
SpanJoin2[SpanJoin2["LineTo"] = 1] = "LineTo";
|
|
SpanJoin2[SpanJoin2["Skip"] = 2] = "Skip";
|
|
return SpanJoin2;
|
|
})(SpanJoin || {});
|
|
function linearPoints(points) {
|
|
const spans = [];
|
|
let i = 0;
|
|
let x0 = Number.NaN;
|
|
let y0 = Number.NaN;
|
|
for (const { x: x1, y: y1 } of points) {
|
|
if (i > 0) {
|
|
const moveTo = i === 1;
|
|
spans.push({ type: "linear", moveTo, x0, y0, x1, y1 });
|
|
}
|
|
i += 1;
|
|
x0 = x1;
|
|
y0 = y1;
|
|
}
|
|
return spans;
|
|
}
|
|
var lineSteps = {
|
|
start: 0,
|
|
middle: 0.5,
|
|
end: 1
|
|
};
|
|
function stepPoints(points, position) {
|
|
const spans = [];
|
|
let i = 0;
|
|
let x0 = Number.NaN;
|
|
let y0 = Number.NaN;
|
|
const p0 = typeof position === "number" ? position : lineSteps[position];
|
|
for (const { x: x1, y: y1 } of points) {
|
|
if (i > 0) {
|
|
const moveTo = i === 1;
|
|
const stepX = x0 + (x1 - x0) * p0;
|
|
spans.push({ type: "step", moveTo, x0, y0, x1, y1, stepX });
|
|
}
|
|
i += 1;
|
|
x0 = x1;
|
|
y0 = y1;
|
|
}
|
|
return spans;
|
|
}
|
|
function smoothPoints(iPoints, tension) {
|
|
const points = Array.isArray(iPoints) ? iPoints : Array.from(iPoints);
|
|
if (points.length <= 1)
|
|
return [];
|
|
const flatnessRatio = 0.05;
|
|
const gradients = points.map((c, i) => {
|
|
const p = i === 0 ? c : points[i - 1];
|
|
const n = i === points.length - 1 ? c : points[i + 1];
|
|
const isTerminalPoint = i === 0 || i === points.length - 1;
|
|
if (Math.sign(p.y - c.y) === Math.sign(n.y - c.y)) {
|
|
return 0;
|
|
}
|
|
if (!isTerminalPoint) {
|
|
const range2 = Math.abs(p.y - n.y);
|
|
const prevRatio = Math.abs(c.y - p.y) / range2;
|
|
const nextRatio = Math.abs(c.y - n.y) / range2;
|
|
if (prevRatio <= flatnessRatio || 1 - prevRatio <= flatnessRatio || nextRatio <= flatnessRatio || 1 - nextRatio <= flatnessRatio) {
|
|
return 0;
|
|
}
|
|
}
|
|
return (n.y - p.y) / (n.x - p.x);
|
|
});
|
|
if (gradients[1] === 0) {
|
|
gradients[0] *= 2;
|
|
}
|
|
if (gradients.at(-2) === 0) {
|
|
gradients[gradients.length - 1] *= 2;
|
|
}
|
|
const spans = [];
|
|
for (let i = 1; i < points.length; i += 1) {
|
|
const prev = points[i - 1];
|
|
const prevM = gradients[i - 1];
|
|
const cur = points[i];
|
|
const curM = gradients[i];
|
|
const dx = cur.x - prev.x;
|
|
const dy = cur.y - prev.y;
|
|
let dcp1x = dx * tension / 3;
|
|
let dcp1y = dx * prevM * tension / 3;
|
|
let dcp2x = dx * tension / 3;
|
|
let dcp2y = dx * curM * tension / 3;
|
|
if (curM === 0 && Math.abs(dcp1y) > Math.abs(dy)) {
|
|
dcp1x *= Math.abs(dy / dcp1y);
|
|
dcp1y = Math.sign(dcp1y) * Math.abs(dy);
|
|
}
|
|
if (prevM === 0 && Math.abs(dcp2y) > Math.abs(dy)) {
|
|
dcp2x *= Math.abs(dy / dcp2y);
|
|
dcp2y = Math.sign(dcp2y) * Math.abs(dy);
|
|
}
|
|
spans.push({
|
|
type: "cubic",
|
|
moveTo: i === 1,
|
|
cp0x: prev.x,
|
|
cp0y: prev.y,
|
|
cp1x: prev.x + dcp1x,
|
|
cp1y: prev.y + dcp1y,
|
|
cp2x: cur.x - dcp2x,
|
|
cp2y: cur.y - dcp2y,
|
|
cp3x: cur.x,
|
|
cp3y: cur.y
|
|
});
|
|
}
|
|
return spans;
|
|
}
|
|
|
|
// packages/ag-charts-core/src/utils/zoomUtils.ts
|
|
var UNIT_MIN = 0;
|
|
var UNIT_MAX = 1;
|
|
function definedZoomState(zoom) {
|
|
return {
|
|
x: { min: zoom?.x?.min ?? UNIT_MIN, max: zoom?.x?.max ?? UNIT_MAX },
|
|
y: { min: zoom?.y?.min ?? UNIT_MIN, max: zoom?.y?.max ?? UNIT_MAX }
|
|
};
|
|
}
|
|
|
|
// packages/ag-charts-core/src/rendering/changeDetectableProperties.ts
|
|
var ChangeDetectableProperties = class extends BaseProperties {
|
|
constructor() {
|
|
super(...arguments);
|
|
this._dirty = true;
|
|
}
|
|
markDirty() {
|
|
this._dirty = true;
|
|
}
|
|
markClean(_opts) {
|
|
this._dirty = false;
|
|
}
|
|
isDirty() {
|
|
return this._dirty;
|
|
}
|
|
onChangeDetection(_property) {
|
|
this.markDirty();
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-core/src/utils/format/timeFormat.ts
|
|
var CONSTANTS = {
|
|
periods: ["AM", "PM"],
|
|
days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
|
|
shortDays: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
|
|
months: [
|
|
"January",
|
|
"February",
|
|
"March",
|
|
"April",
|
|
"May",
|
|
"June",
|
|
"July",
|
|
"August",
|
|
"September",
|
|
"October",
|
|
"November",
|
|
"December"
|
|
],
|
|
shortMonths: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
|
|
};
|
|
function dayOfYear(date2, startOfYear = new Date(date2.getFullYear(), 0, 1)) {
|
|
const startOffset = date2.getTimezoneOffset() - startOfYear.getTimezoneOffset();
|
|
const timeDiff = date2.getTime() - startOfYear.getTime() + startOffset * 6e4;
|
|
const timeOneDay = 36e5 * 24;
|
|
return Math.floor(timeDiff / timeOneDay);
|
|
}
|
|
function weekOfYear(date2, startDay) {
|
|
const startOfYear = new Date(date2.getFullYear(), 0, 1);
|
|
const startOfYearDay = startOfYear.getDay();
|
|
const firstWeekStartOffset = (startDay - startOfYearDay + 7) % 7;
|
|
const startOffset = new Date(date2.getFullYear(), 0, firstWeekStartOffset + 1);
|
|
if (startOffset <= date2) {
|
|
return Math.floor(dayOfYear(date2, startOffset) / 7) + 1;
|
|
}
|
|
return 0;
|
|
}
|
|
var SUNDAY = 0;
|
|
var MONDAY = 1;
|
|
var THURSDAY = 4;
|
|
function isoWeekOfYear(date2, year = date2.getFullYear()) {
|
|
const firstOfYear = new Date(year, 0, 1);
|
|
const firstOfYearDay = firstOfYear.getDay();
|
|
const firstThursdayOffset = (THURSDAY - firstOfYearDay + 7) % 7;
|
|
const startOffset = new Date(year, 0, firstThursdayOffset - (THURSDAY - MONDAY) + 1);
|
|
if (startOffset <= date2) {
|
|
return Math.floor(dayOfYear(date2, startOffset) / 7) + 1;
|
|
}
|
|
return isoWeekOfYear(date2, year - 1);
|
|
}
|
|
function timezone(date2) {
|
|
const offset = date2.getTimezoneOffset();
|
|
const unsignedOffset = Math.abs(offset);
|
|
const sign = offset > 0 ? "-" : "+";
|
|
return `${sign}${pad(Math.floor(unsignedOffset / 60), 2, "0")}${pad(Math.floor(unsignedOffset % 60), 2, "0")}`;
|
|
}
|
|
var FORMATTERS = {
|
|
a: (d) => CONSTANTS.shortDays[d.getDay()],
|
|
A: (d) => CONSTANTS.days[d.getDay()],
|
|
b: (d) => CONSTANTS.shortMonths[d.getMonth()],
|
|
B: (d) => CONSTANTS.months[d.getMonth()],
|
|
c: "%x, %X",
|
|
d: (d, p) => pad(d.getDate(), 2, p ?? "0"),
|
|
e: "%_d",
|
|
f: (d, p) => pad(d.getMilliseconds() * 1e3, 6, p ?? "0"),
|
|
H: (d, p) => pad(d.getHours(), 2, p ?? "0"),
|
|
I: (d, p) => {
|
|
const hours = d.getHours() % 12;
|
|
return hours === 0 ? "12" : pad(hours, 2, p ?? "0");
|
|
},
|
|
j: (d, p) => pad(dayOfYear(d) + 1, 3, p ?? "0"),
|
|
m: (d, p) => pad(d.getMonth() + 1, 2, p ?? "0"),
|
|
M: (d, p) => pad(d.getMinutes(), 2, p ?? "0"),
|
|
L: (d, p) => pad(d.getMilliseconds(), 3, p ?? "0"),
|
|
p: (d) => d.getHours() < 12 ? "AM" : "PM",
|
|
Q: (d) => String(d.getTime()),
|
|
s: (d) => String(Math.floor(d.getTime() / 1e3)),
|
|
S: (d, p) => pad(d.getSeconds(), 2, p ?? "0"),
|
|
u: (d) => {
|
|
let day = d.getDay();
|
|
if (day < 1)
|
|
day += 7;
|
|
return String(day % 7);
|
|
},
|
|
U: (d, p) => pad(weekOfYear(d, SUNDAY), 2, p ?? "0"),
|
|
V: (d, p) => pad(isoWeekOfYear(d), 2, p ?? "0"),
|
|
w: (d, p) => pad(d.getDay(), 2, p ?? "0"),
|
|
W: (d, p) => pad(weekOfYear(d, MONDAY), 2, p ?? "0"),
|
|
x: "%-m/%-d/%Y",
|
|
X: "%-I:%M:%S %p",
|
|
y: (d, p) => pad(d.getFullYear() % 100, 2, p ?? "0"),
|
|
Y: (d, p) => pad(d.getFullYear(), 4, p ?? "0"),
|
|
Z: (d) => timezone(d),
|
|
"%": () => "%"
|
|
};
|
|
var PADS = {
|
|
_: " ",
|
|
"0": "0",
|
|
"-": ""
|
|
};
|
|
function pad(value, size, padChar) {
|
|
const output = String(Math.floor(value));
|
|
if (output.length >= size) {
|
|
return output;
|
|
}
|
|
return `${padChar.repeat(size - output.length)}${output}`;
|
|
}
|
|
function buildDateFormatter(formatString) {
|
|
const formatParts = [];
|
|
while (formatString.length > 0) {
|
|
let nextEscapeIdx = formatString.indexOf("%");
|
|
if (nextEscapeIdx !== 0) {
|
|
const literalPart = nextEscapeIdx > 0 ? formatString.substring(0, nextEscapeIdx) : formatString;
|
|
formatParts.push(literalPart);
|
|
}
|
|
if (nextEscapeIdx < 0)
|
|
break;
|
|
const maybePadSpecifier = formatString[nextEscapeIdx + 1];
|
|
const maybePad = PADS[maybePadSpecifier];
|
|
if (maybePad != null) {
|
|
nextEscapeIdx++;
|
|
}
|
|
const maybeFormatterSpecifier = formatString[nextEscapeIdx + 1];
|
|
const maybeFormatter = FORMATTERS[maybeFormatterSpecifier];
|
|
if (typeof maybeFormatter === "function") {
|
|
formatParts.push([maybeFormatter, maybePad]);
|
|
} else if (typeof maybeFormatter === "string") {
|
|
const formatter2 = buildDateFormatter(maybeFormatter);
|
|
formatParts.push([formatter2, maybePad]);
|
|
} else {
|
|
formatParts.push(`${maybePad ?? ""}${maybeFormatterSpecifier}`);
|
|
}
|
|
formatString = formatString.substring(nextEscapeIdx + 2);
|
|
}
|
|
return (dateTime) => {
|
|
const dateTimeAsDate = typeof dateTime === "number" ? new Date(dateTime) : dateTime;
|
|
return formatParts.map((c) => typeof c === "string" ? c : c[0](dateTimeAsDate, c[1])).join("");
|
|
};
|
|
}
|
|
|
|
// packages/ag-charts-core/src/rendering/domElements.ts
|
|
function createButton(options, attrs) {
|
|
const button = createElement("button", getClassName("ag-charts-input ag-charts-button", attrs));
|
|
if (options.label === void 0) {
|
|
button.append(createIcon(options.icon));
|
|
button.ariaLabel = options.altText;
|
|
} else {
|
|
button.append(options.label);
|
|
}
|
|
button.addEventListener("click", options.onPress);
|
|
setAttributes(button, attrs);
|
|
return button;
|
|
}
|
|
function createCheckbox(options, attrs) {
|
|
const checkbox = createElement("input", getClassName("ag-charts-input ag-charts-checkbox", attrs));
|
|
checkbox.type = "checkbox";
|
|
checkbox.checked = options.checked;
|
|
checkbox.addEventListener("change", (event) => options.onChange(checkbox.checked, event));
|
|
checkbox.addEventListener("keydown", (event) => {
|
|
if (isButtonClickEvent(event)) {
|
|
event.preventDefault();
|
|
checkbox.click();
|
|
}
|
|
});
|
|
setAttributes(checkbox, attrs);
|
|
return checkbox;
|
|
}
|
|
function createSelect(options, attrs) {
|
|
const select = createElement("select", getClassName("ag-charts-input ag-charts-select", attrs));
|
|
select.append(
|
|
...options.options.map((option) => {
|
|
const optionEl = createElement("option");
|
|
optionEl.value = option.value;
|
|
optionEl.textContent = option.label;
|
|
return optionEl;
|
|
})
|
|
);
|
|
setAttribute(select, "data-preventdefault", false);
|
|
select.value = options.value;
|
|
select.addEventListener("change", (event) => options.onChange(select.value, event));
|
|
setAttributes(select, attrs);
|
|
return select;
|
|
}
|
|
function createTextArea(options, attrs) {
|
|
const textArea = createElement("textarea", getClassName("ag-charts-input ag-charts-textarea", attrs));
|
|
textArea.value = options.value;
|
|
textArea.addEventListener("input", (event) => options.onChange(textArea.value, event));
|
|
setAttributes(textArea, attrs);
|
|
setAttribute(textArea, "data-preventdefault", false);
|
|
return textArea;
|
|
}
|
|
function createIcon(icon) {
|
|
const el = createElement("span", `ag-charts-icon ag-charts-icon-${icon}`);
|
|
setAttribute(el, "aria-hidden", true);
|
|
return el;
|
|
}
|
|
function getClassName(baseClass, attrs) {
|
|
if (attrs == null)
|
|
return baseClass;
|
|
return `${baseClass} ${attrs.class}`;
|
|
}
|
|
|
|
// packages/ag-charts-core/src/rendering/easing.ts
|
|
var linear = (n) => n;
|
|
var easeIn = (n) => 1 - Math.cos(n * Math.PI / 2);
|
|
var easeOut = (n) => Math.sin(n * Math.PI / 2);
|
|
var easeInOut = (n) => -(Math.cos(n * Math.PI) - 1) / 2;
|
|
var easeInQuad = (n) => n * n;
|
|
var easeOutQuad = (n) => 1 - (1 - n) ** 2;
|
|
var easeInOutQuad = (n) => n < 0.5 ? 2 * n * n : 1 - (-2 * n + 2) ** 2 / 2;
|
|
var inverseEaseOut = (x) => 2 * Math.asin(x) / Math.PI;
|
|
|
|
// packages/ag-charts-core/src/rendering/changeDetectable.ts
|
|
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 SceneRefChangeDetection(opts) {
|
|
return SceneChangeDetection(opts);
|
|
}
|
|
function SceneObjectChangeDetection(opts) {
|
|
return SceneChangeDetection(opts);
|
|
}
|
|
function SceneArrayChangeDetection(opts) {
|
|
const baseOpts = opts ?? {};
|
|
baseOpts.equals = arraysEqual;
|
|
return SceneChangeDetection(opts);
|
|
}
|
|
function DeclaredSceneChangeDetection(opts) {
|
|
return function(target, key) {
|
|
const privateKey = `__${key}`;
|
|
if (target[key])
|
|
return;
|
|
prepareGetSet(target, key, privateKey, opts);
|
|
};
|
|
}
|
|
function DeclaredSceneObjectChangeDetection(opts) {
|
|
return function(target, key) {
|
|
const privateKey = `__${key}`;
|
|
if (target[key])
|
|
return;
|
|
prepareGetSet(target, key, privateKey, 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
|
|
);
|
|
function propertyGetter() {
|
|
return this[privateKey];
|
|
}
|
|
Object.defineProperty(target, key, {
|
|
set: setter,
|
|
get: propertyGetter,
|
|
enumerable: true,
|
|
configurable: true
|
|
});
|
|
}
|
|
function buildConvertorChain(setterFn, opts) {
|
|
const { convertor } = opts;
|
|
if (convertor) {
|
|
let convertValueAndSet2 = function(value) {
|
|
setterFn.call(this, convertValue(value));
|
|
};
|
|
var convertValueAndSet = convertValueAndSet2;
|
|
const convertValue = convertor;
|
|
return convertValueAndSet2;
|
|
}
|
|
return setterFn;
|
|
}
|
|
var NO_CHANGE = Symbol("no-change");
|
|
function buildChangeCallbackChain(setterFn, opts) {
|
|
const { changeCb } = opts;
|
|
if (changeCb) {
|
|
let invokeChangeCallback2 = function(value) {
|
|
const change = setterFn.call(this, value);
|
|
if (change !== NO_CHANGE) {
|
|
changeCallback.call(this, this);
|
|
}
|
|
return change;
|
|
};
|
|
var invokeChangeCallback = invokeChangeCallback2;
|
|
const changeCallback = changeCb;
|
|
return invokeChangeCallback2;
|
|
}
|
|
return setterFn;
|
|
}
|
|
function buildCheckDirtyChain(privateKey, setterFn, opts) {
|
|
const { checkDirtyOnAssignment } = opts;
|
|
if (checkDirtyOnAssignment) {
|
|
let checkDirtyOnAssignmentFn2 = function(value) {
|
|
const change = setterFn.call(this, value);
|
|
if (value?._dirty === true) {
|
|
this.markDirty(privateKey);
|
|
}
|
|
return change;
|
|
};
|
|
var checkDirtyOnAssignmentFn = checkDirtyOnAssignmentFn2;
|
|
return checkDirtyOnAssignmentFn2;
|
|
}
|
|
return setterFn;
|
|
}
|
|
function buildSetter(privateKey, opts) {
|
|
const { equals = TRIPLE_EQ } = opts;
|
|
function setWithChangeDetection(value) {
|
|
const oldValue = this[privateKey];
|
|
if (!equals(value, oldValue)) {
|
|
this[privateKey] = value;
|
|
this.onChangeDetection(privateKey);
|
|
return value;
|
|
}
|
|
return NO_CHANGE;
|
|
}
|
|
return setWithChangeDetection;
|
|
}
|
|
export {
|
|
AGGREGATION_INDEX_UNSET,
|
|
AGGREGATION_INDEX_X_MAX,
|
|
AGGREGATION_INDEX_X_MIN,
|
|
AGGREGATION_INDEX_Y_MAX,
|
|
AGGREGATION_INDEX_Y_MIN,
|
|
AGGREGATION_MAX_POINTS,
|
|
AGGREGATION_MIN_RANGE,
|
|
AGGREGATION_SPAN,
|
|
AGGREGATION_THRESHOLD,
|
|
AbstractModuleInstance,
|
|
ActionOnSet,
|
|
AdjacencyListGraph,
|
|
AsyncAwaitQueue,
|
|
BASE_FONT_SIZE,
|
|
BREAK_TRANSFORM_CHAIN,
|
|
BaseProperties,
|
|
Border,
|
|
CANVAS_HEIGHT,
|
|
CANVAS_TO_BUFFER_DEFAULTS,
|
|
CANVAS_WIDTH,
|
|
CARTESIAN_AXIS_TYPE,
|
|
CARTESIAN_POSITION,
|
|
CallbackCache,
|
|
ChangeDetectableProperties,
|
|
ChartAxisDirection,
|
|
ChartUpdateType,
|
|
CleanupRegistry,
|
|
Color,
|
|
ConfiguredCanvasMixin,
|
|
DEFAULT_ANNOTATION_HANDLE_FILL,
|
|
DEFAULT_ANNOTATION_STATISTICS_COLOR,
|
|
DEFAULT_ANNOTATION_STATISTICS_DIVIDER_STROKE,
|
|
DEFAULT_ANNOTATION_STATISTICS_DOWN_FILL,
|
|
DEFAULT_ANNOTATION_STATISTICS_DOWN_STROKE,
|
|
DEFAULT_ANNOTATION_STATISTICS_FILL,
|
|
DEFAULT_ANNOTATION_STATISTICS_STROKE,
|
|
DEFAULT_CAPTION_ALIGNMENT,
|
|
DEFAULT_CAPTION_LAYOUT_STYLE,
|
|
DEFAULT_FIBONACCI_STROKES,
|
|
DEFAULT_FINANCIAL_CHARTS_ANNOTATION_BACKGROUND_FILL,
|
|
DEFAULT_FINANCIAL_CHARTS_ANNOTATION_COLOR,
|
|
DEFAULT_POLAR_SERIES_STROKE,
|
|
DEFAULT_SHADOW_COLOUR,
|
|
DEFAULT_SPARKLINE_CROSSHAIR_STROKE,
|
|
DEFAULT_TEXTBOX_COLOR,
|
|
DEFAULT_TEXTBOX_FILL,
|
|
DEFAULT_TEXTBOX_STROKE,
|
|
DEFAULT_TEXT_ANNOTATION_COLOR,
|
|
DEFAULT_TOOLBAR_POSITION,
|
|
DIRECTION_SWAP_AXES,
|
|
debugLogger_exports as Debug,
|
|
debugMetrics_exports as DebugMetrics,
|
|
DeclaredSceneChangeDetection,
|
|
DeclaredSceneObjectChangeDetection,
|
|
Deprecated,
|
|
DeprecatedAndRenamedTo,
|
|
EllipsisChar,
|
|
ErrorType,
|
|
EventEmitter,
|
|
FILL_GRADIENT_BLANK_DEFAULTS,
|
|
FILL_GRADIENT_CONIC_SERIES_DEFAULTS,
|
|
FILL_GRADIENT_LINEAR_DEFAULTS,
|
|
FILL_GRADIENT_LINEAR_HIERARCHY_DEFAULTS,
|
|
FILL_GRADIENT_LINEAR_KEYED_DEFAULTS,
|
|
FILL_GRADIENT_LINEAR_SINGLE_DEFAULTS,
|
|
FILL_GRADIENT_RADIAL_DEFAULTS,
|
|
FILL_GRADIENT_RADIAL_REVERSED_DEFAULTS,
|
|
FILL_GRADIENT_RADIAL_REVERSED_SERIES_DEFAULTS,
|
|
FILL_GRADIENT_RADIAL_SERIES_DEFAULTS,
|
|
FILL_IMAGE_BLANK_DEFAULTS,
|
|
FILL_IMAGE_DEFAULTS,
|
|
FILL_PATTERN_BLANK_DEFAULTS,
|
|
FILL_PATTERN_DEFAULTS,
|
|
FILL_PATTERN_HIERARCHY_DEFAULTS,
|
|
FILL_PATTERN_KEYED_DEFAULTS,
|
|
FILL_PATTERN_SINGLE_DEFAULTS,
|
|
FONT_SIZE,
|
|
FONT_SIZE_RATIO,
|
|
IS_DARK_THEME,
|
|
InterpolationProperties,
|
|
LABEL_BOXING_DEFAULTS,
|
|
LEGEND_CONTAINER_THEME,
|
|
LRUCache,
|
|
LineSplitter,
|
|
logger_exports as Logger,
|
|
MARKER_SERIES_HIGHLIGHT_STYLE,
|
|
MULTI_SERIES_HIGHLIGHT_STYLE,
|
|
MementoCaretaker,
|
|
moduleRegistry_exports as ModuleRegistry,
|
|
ModuleType,
|
|
ObserveChanges,
|
|
PALETTE_ALT_DOWN_FILL,
|
|
PALETTE_ALT_DOWN_STROKE,
|
|
PALETTE_ALT_NEUTRAL_FILL,
|
|
PALETTE_ALT_NEUTRAL_STROKE,
|
|
PALETTE_ALT_UP_FILL,
|
|
PALETTE_ALT_UP_STROKE,
|
|
PALETTE_DOWN_FILL,
|
|
PALETTE_DOWN_STROKE,
|
|
PALETTE_NEUTRAL_FILL,
|
|
PALETTE_NEUTRAL_STROKE,
|
|
PALETTE_UP_FILL,
|
|
PALETTE_UP_STROKE,
|
|
PART_WHOLE_HIGHLIGHT_STYLE,
|
|
POLAR_AXIS_SHAPE,
|
|
POLAR_AXIS_TYPE,
|
|
PREV_NEXT_KEYS,
|
|
Padding,
|
|
ParallelStateMachine,
|
|
PolarZIndexMap,
|
|
PropertiesArray,
|
|
addFakeTransformToInstanceProperty as Property,
|
|
ProxyOnWrite,
|
|
ProxyProperty,
|
|
ProxyPropertyOnWrite,
|
|
SAFE_FILLS_OPERATION,
|
|
SAFE_FILL_OPERATION,
|
|
SAFE_RANGE2_OPERATION,
|
|
SAFE_STROKE_FILL_OPERATION,
|
|
SEGMENTATION_DEFAULTS,
|
|
SINGLE_SERIES_HIGHLIGHT_STYLE,
|
|
SKIP_JS_BUILTINS,
|
|
ScaleAlignment,
|
|
SceneArrayChangeDetection,
|
|
SceneChangeDetection,
|
|
SceneObjectChangeDetection,
|
|
SceneRefChangeDetection,
|
|
SeriesContentZIndexMap,
|
|
SeriesZIndexMap,
|
|
SimpleCache,
|
|
SpanJoin,
|
|
StateMachine,
|
|
StateMachineProperty,
|
|
TRIPLE_EQ,
|
|
TextMeasurer,
|
|
TickIntervals,
|
|
TrimCharsRegex,
|
|
TrimEdgeGuard,
|
|
UNIT_MAX,
|
|
UNIT_MIN,
|
|
UnknownError,
|
|
ValidationError,
|
|
vector_exports as Vec2,
|
|
vector4_exports as Vec4,
|
|
Vertex,
|
|
WeakCache,
|
|
ZIndexMap,
|
|
addEscapeEventListener,
|
|
addFakeTransformToInstanceProperty,
|
|
addMouseCloseListener,
|
|
addObserverToInstanceProperty,
|
|
addOverrideFocusVisibleEventListener,
|
|
addTouchCloseListener,
|
|
addTransformToInstanceProperty,
|
|
aggregationBucketForDatum,
|
|
aggregationDatumMatchesIndex,
|
|
aggregationDomain,
|
|
aggregationIndexForXRatio,
|
|
aggregationRangeFittingPoints,
|
|
aggregationXRatioForDatumIndex,
|
|
aggregationXRatioForXValue,
|
|
and,
|
|
angleBetween,
|
|
angularPadding,
|
|
appendEllipsis,
|
|
applySkiaPatches,
|
|
arcDistanceSquared,
|
|
areScalingEqual,
|
|
array,
|
|
arrayLength,
|
|
arrayOf,
|
|
arrayOfDefs,
|
|
arraysEqual,
|
|
assignIfNotStrictlyEqual,
|
|
attachDescription,
|
|
attachListener,
|
|
autoSizedLabelOptionsDefs,
|
|
barHighlightOptionsDef,
|
|
bezier2DDistance,
|
|
bezier2DExtrema,
|
|
boolean,
|
|
borderOptionsDef,
|
|
boxCollides,
|
|
boxContains,
|
|
boxEmpty,
|
|
boxesEqual,
|
|
buildDateFormatter,
|
|
cachedTextMeasurer,
|
|
calcLineHeight,
|
|
calculatePlacement,
|
|
callWithContext,
|
|
callback,
|
|
callbackDefs,
|
|
callbackOf,
|
|
ceilTo,
|
|
checkDatum,
|
|
circularSliceArray,
|
|
clamp,
|
|
clampArray,
|
|
clipLines,
|
|
clipSpanX,
|
|
collapseSpanToPoint,
|
|
collectAggregationLevels,
|
|
color,
|
|
colorStopsOrderValidator,
|
|
colorUnion,
|
|
commonChartOptionsDefs,
|
|
commonSeriesOptionsDefs,
|
|
commonSeriesThemeableOptionsDefs,
|
|
compactAggregationIndices,
|
|
compareDates,
|
|
computeExtremesAggregation,
|
|
computeExtremesAggregationPartial,
|
|
constant,
|
|
contextMenuItemsArray,
|
|
countFractionDigits,
|
|
countLines,
|
|
createAggregationIndices,
|
|
createButton,
|
|
createCanvasContext,
|
|
createCheckbox,
|
|
createDeprecationWarning,
|
|
createElement,
|
|
createElementId,
|
|
createIcon,
|
|
createId,
|
|
createIdsGenerator,
|
|
createNumberFormatter,
|
|
createSelect,
|
|
createSvgElement,
|
|
createTextArea,
|
|
createTicks,
|
|
date,
|
|
dateToNumber,
|
|
dateTruncationForDomain,
|
|
datesSortOrder,
|
|
debounce,
|
|
decodeIntervalValue,
|
|
deepClone,
|
|
deepFreeze,
|
|
defaultEpoch,
|
|
defined,
|
|
definedZoomState,
|
|
diffArrays,
|
|
distribute,
|
|
downloadUrl,
|
|
dropFirstWhile,
|
|
dropLastWhile,
|
|
durationDay,
|
|
durationHour,
|
|
durationMinute,
|
|
durationMonth,
|
|
durationSecond,
|
|
durationWeek,
|
|
durationYear,
|
|
easeIn,
|
|
easeInOut,
|
|
easeInOutQuad,
|
|
easeInQuad,
|
|
easeOut,
|
|
easeOutQuad,
|
|
encodedToTimestamp,
|
|
enterpriseRegistry,
|
|
entries,
|
|
errorBarOptionsDefs,
|
|
errorBarThemeableOptionsDefs,
|
|
estimateTickCount,
|
|
evaluateBezier,
|
|
every,
|
|
expandLegendPosition,
|
|
extent,
|
|
extractDecoratedProperties,
|
|
extractDomain,
|
|
fillGradientDefaults,
|
|
fillImageDefaults,
|
|
fillOptionsDef,
|
|
fillPatternDefaults,
|
|
findMaxIndex,
|
|
findMaxValue,
|
|
findMinIndex,
|
|
findMinMax,
|
|
findMinValue,
|
|
findRangeExtent,
|
|
first,
|
|
flush,
|
|
focusCursorAtEnd,
|
|
fontFamilyFull,
|
|
fontOptionsDef,
|
|
fontWeight,
|
|
formatNumber,
|
|
formatObjectValidator,
|
|
formatPercent,
|
|
formatValue,
|
|
fromPairs,
|
|
generateUUID,
|
|
geoJson,
|
|
getAngleRatioRadians,
|
|
getAttribute,
|
|
getDOMMatrix,
|
|
getDocument,
|
|
getElementBBox,
|
|
getIconClassNames,
|
|
getImage,
|
|
getLastFocus,
|
|
getMaxInnerRectSize,
|
|
getMidpointsForIndices,
|
|
getMinOuterRectSize,
|
|
getOffscreenCanvas,
|
|
getPath,
|
|
getPath2D,
|
|
getResizeObserver,
|
|
getSequentialColors,
|
|
getTickTimeInterval,
|
|
getWindow,
|
|
googleFont,
|
|
gradientColorStops,
|
|
gradientStrict,
|
|
greaterThan,
|
|
groupBy,
|
|
guardTextEdges,
|
|
hasNoModifiers,
|
|
hasRequiredInPath,
|
|
highlightOptionsDef,
|
|
htmlElement,
|
|
inRange,
|
|
initRovingTabIndex,
|
|
insertListItemsSorted,
|
|
instanceOf,
|
|
interpolationOptionsDefs,
|
|
intervalCeil,
|
|
intervalEpoch,
|
|
intervalExtent,
|
|
intervalFloor,
|
|
intervalHierarchy,
|
|
intervalMilliseconds,
|
|
intervalNext,
|
|
intervalPrevious,
|
|
intervalRange,
|
|
intervalRangeCount,
|
|
intervalRangeNumeric,
|
|
intervalRangeStartIndex,
|
|
intervalStep,
|
|
intervalUnit,
|
|
inverseEaseOut,
|
|
isArray,
|
|
isBetweenAngles,
|
|
isBoolean,
|
|
isButtonClickEvent,
|
|
isColor,
|
|
isContinuous,
|
|
isDate,
|
|
isDecoratedObject,
|
|
isDefined,
|
|
isDenseInterval,
|
|
isDocumentFragment,
|
|
isElement,
|
|
isEmptyObject,
|
|
isEnumKey,
|
|
isEnumValue,
|
|
isFiniteNumber,
|
|
isFunction,
|
|
isGradientFill,
|
|
isGradientFillArray,
|
|
isGradientOrPatternFill,
|
|
isHTMLElement,
|
|
isHtmlElement,
|
|
isImageFill,
|
|
isInputPending,
|
|
isInteger,
|
|
isKeyOf,
|
|
isNegative,
|
|
isNode,
|
|
isNumber,
|
|
isNumberEqual,
|
|
isNumberObject,
|
|
isObject,
|
|
isObjectLike,
|
|
isObjectWithProperty,
|
|
isObjectWithStringProperty,
|
|
isPatternFill,
|
|
isPlainObject,
|
|
isPointLabelDatum,
|
|
isProperties,
|
|
isRegExp,
|
|
isScaleValid,
|
|
isSegmentTruncated,
|
|
isString,
|
|
isStringFillArray,
|
|
isStringObject,
|
|
isSymbol,
|
|
isTextTruncated,
|
|
isTruncated,
|
|
isUnitTimeCategoryScaling,
|
|
isValidDate,
|
|
isValidNumberFormat,
|
|
iterate,
|
|
joinFormatted,
|
|
jsonApply,
|
|
jsonDiff,
|
|
jsonPropertyCompare,
|
|
jsonWalk,
|
|
kebabCase,
|
|
labelBoxOptionsDef,
|
|
legendPositionValidator,
|
|
lessThan,
|
|
lessThanOrEqual,
|
|
levenshteinDistance,
|
|
lineDashOptionsDef,
|
|
lineDistanceSquared,
|
|
lineHighlightOptionsDef,
|
|
lineSegmentOptions,
|
|
lineSegmentation,
|
|
linear,
|
|
linearGaugeSeriesOptionsDef,
|
|
linearGaugeSeriesThemeableOptionsDef,
|
|
linearGaugeTargetOptionsDef,
|
|
linearPoints,
|
|
listDecoratedProperties,
|
|
lowestGranularityForInterval,
|
|
lowestGranularityUnitForTicks,
|
|
lowestGranularityUnitForValue,
|
|
makeAccessibleClickListener,
|
|
mapValues,
|
|
markerOptionsDefs,
|
|
markerStyleOptionsDefs,
|
|
measureTextSegments,
|
|
memo,
|
|
merge,
|
|
mergeArrayDefaults,
|
|
mergeDefaults,
|
|
modulus,
|
|
multiSeriesHighlightOptionsDef,
|
|
nearestSquared,
|
|
nearestSquaredInContainer,
|
|
nextPowerOf2,
|
|
niceTicksDomain,
|
|
normalisedExtentWithMetadata,
|
|
normalisedTimeExtentWithMetadata,
|
|
normalizeAngle180,
|
|
normalizeAngle360,
|
|
normalizeAngle360FromDegrees,
|
|
normalizeAngle360Inclusive,
|
|
number,
|
|
numberFormatValidator,
|
|
numberMin,
|
|
numberRange,
|
|
object,
|
|
objectsEqual,
|
|
objectsEqualWith,
|
|
optionsDefs,
|
|
or,
|
|
padding,
|
|
paddingOptions,
|
|
parseNumberFormat,
|
|
partialAssign,
|
|
pause,
|
|
pick,
|
|
placeLabels,
|
|
positiveNumber,
|
|
positiveNumberNonZero,
|
|
previousPowerOf2,
|
|
radialGaugeSeriesOptionsDef,
|
|
radialGaugeSeriesThemeableOptionsDef,
|
|
radialGaugeTargetOptionsDef,
|
|
range,
|
|
rangeValidator,
|
|
ratio,
|
|
readIntegratedWrappedValue,
|
|
record,
|
|
required,
|
|
rescaleSpan,
|
|
rescaleVisibleRange,
|
|
resetIds,
|
|
rotatePoint,
|
|
roundTo,
|
|
safeCall,
|
|
seriesLabelOptionsDefs,
|
|
seriesTooltipRangeValidator,
|
|
setAttribute,
|
|
setAttributes,
|
|
setDocument,
|
|
setElementBBox,
|
|
setElementStyle,
|
|
setElementStyles,
|
|
setPath,
|
|
setWindow,
|
|
shadowOptionsDefs,
|
|
shallowClone,
|
|
shapeHighlightOptionsDef,
|
|
shapeSegmentOptions,
|
|
shapeSegmentation,
|
|
shapeValidator,
|
|
simpleMemorize,
|
|
simpleMemorize2,
|
|
smoothPoints,
|
|
solveBezier,
|
|
sortAndUniqueDates,
|
|
sortBasedOnArray,
|
|
spanRange,
|
|
splitBezier2D,
|
|
stepPoints,
|
|
stopPageScrolling,
|
|
strictObjectKeys,
|
|
strictUnion,
|
|
string,
|
|
stringLength,
|
|
stringifyValue,
|
|
strokeOptionsDef,
|
|
textOrSegments,
|
|
themeOperator,
|
|
throttle,
|
|
tickFormat,
|
|
tickStep,
|
|
toArray,
|
|
toDegrees,
|
|
toFontString,
|
|
toIterable,
|
|
toPlainText,
|
|
toRadians,
|
|
toTextString,
|
|
toolbarButtonOptionsDefs,
|
|
tooltipOptionsDefs,
|
|
tooltipOptionsDefsWithArea,
|
|
transformIntegratedCategoryValue,
|
|
truncateLine,
|
|
typeUnion,
|
|
undocumented,
|
|
unguardTextEdges,
|
|
union,
|
|
unionSymbol,
|
|
unique,
|
|
validate,
|
|
withTimeout,
|
|
without,
|
|
wrapLines,
|
|
wrapText,
|
|
wrapTextOrSegments,
|
|
wrapTextSegments
|
|
};
|