49701 lines
1.7 MiB
Executable File
49701 lines
1.7 MiB
Executable File
var __defProp = Object.defineProperty;
|
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
var __decorateClass = (decorators, target, key, kind) => {
|
|
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
|
|
for (var i = decorators.length - 1, decorator; i >= 0; i--)
|
|
if (decorator = decorators[i])
|
|
result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
if (kind && result)
|
|
__defProp(target, key, result);
|
|
return result;
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/main.ts
|
|
import { ModuleRegistry as ModuleRegistry3, enterpriseRegistry as enterpriseRegistry2 } from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/features/background/background.ts
|
|
import { _ModuleSupport as _ModuleSupport2 } from "ag-charts-community";
|
|
import { ActionOnSet, ChartUpdateType, Property as Property2 } from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/features/image/image.ts
|
|
import { _ModuleSupport } from "ag-charts-community";
|
|
import {
|
|
BaseProperties,
|
|
ObserveChanges,
|
|
Property,
|
|
ProxyProperty,
|
|
calculatePlacement,
|
|
createElement
|
|
} from "ag-charts-core";
|
|
var Image = class extends BaseProperties {
|
|
constructor() {
|
|
super();
|
|
this.opacity = 1;
|
|
this.loadedSynchronously = true;
|
|
this.containerWidth = 0;
|
|
this.containerHeight = 0;
|
|
this.onLoad = void 0;
|
|
this.onImageLoad = () => {
|
|
if (this.loadedSynchronously) {
|
|
return;
|
|
}
|
|
this.node.visible = false;
|
|
this.performLayout(this.containerWidth, this.containerHeight);
|
|
this.onLoad?.();
|
|
};
|
|
this.imageElement = createElement("img");
|
|
this.imageElement.onload = this.onImageLoad;
|
|
this.node = new _ModuleSupport.Image(this.imageElement);
|
|
}
|
|
get complete() {
|
|
return this.imageElement.width > 0 && this.imageElement.height > 0;
|
|
}
|
|
performLayout(containerWidth, containerHeight) {
|
|
this.containerWidth = containerWidth;
|
|
this.containerHeight = containerHeight;
|
|
const container = { width: containerWidth, height: containerHeight };
|
|
const placement = calculatePlacement(this.imageElement.width, this.imageElement.height, container, this);
|
|
this.node.setProperties(
|
|
this.complete ? {
|
|
visible: true,
|
|
opacity: this.opacity,
|
|
...placement
|
|
} : { visible: false }
|
|
);
|
|
return placement;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property
|
|
], Image.prototype, "top", 2);
|
|
__decorateClass([
|
|
Property
|
|
], Image.prototype, "right", 2);
|
|
__decorateClass([
|
|
Property
|
|
], Image.prototype, "bottom", 2);
|
|
__decorateClass([
|
|
Property
|
|
], Image.prototype, "left", 2);
|
|
__decorateClass([
|
|
Property
|
|
], Image.prototype, "width", 2);
|
|
__decorateClass([
|
|
Property
|
|
], Image.prototype, "height", 2);
|
|
__decorateClass([
|
|
Property
|
|
], Image.prototype, "opacity", 2);
|
|
__decorateClass([
|
|
ProxyProperty("imageElement.src"),
|
|
ObserveChanges((target) => target.loadedSynchronously = target.complete)
|
|
], Image.prototype, "url", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/features/background/background.ts
|
|
var Background = class extends _ModuleSupport2.Background {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.image = new Image();
|
|
}
|
|
onLayoutComplete(event) {
|
|
super.onLayoutComplete(event);
|
|
if (this.image) {
|
|
const { width, height } = event.chart;
|
|
this.image.performLayout(width, height);
|
|
}
|
|
}
|
|
onImageLoad() {
|
|
this.ctx.updateService.update(ChartUpdateType.SCENE_RENDER);
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property2,
|
|
ActionOnSet({
|
|
newValue(image) {
|
|
this.node.appendChild(image.node);
|
|
image.onLoad = () => this.onImageLoad();
|
|
},
|
|
oldValue(image) {
|
|
image.node.remove();
|
|
image.onLoad = void 0;
|
|
}
|
|
})
|
|
], Background.prototype, "image", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/features/foreground/foreground.ts
|
|
import { _ModuleSupport as _ModuleSupport3 } from "ag-charts-community";
|
|
import {
|
|
ActionOnSet as ActionOnSet2,
|
|
ChartUpdateType as ChartUpdateType2,
|
|
Property as Property3,
|
|
ProxyPropertyOnWrite,
|
|
ZIndexMap
|
|
} from "ag-charts-core";
|
|
var Foreground = class extends _ModuleSupport3.Background {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.image = new Image();
|
|
this.fill = "transparent";
|
|
this.fillOpacity = void 0;
|
|
}
|
|
createNode() {
|
|
return new _ModuleSupport3.Group({ name: "foreground", zIndex: ZIndexMap.FOREGROUND });
|
|
}
|
|
onLayoutComplete(event) {
|
|
super.onLayoutComplete(event);
|
|
const { width, height } = event.chart;
|
|
const placement = this.image.performLayout(width, height);
|
|
if (this.text) {
|
|
this.updateTextNode(placement);
|
|
}
|
|
}
|
|
onImageLoad() {
|
|
this.ctx.updateService.update(ChartUpdateType2.SCENE_RENDER);
|
|
}
|
|
updateTextNode(placement) {
|
|
const { textNode } = this;
|
|
textNode.fontWeight = "bold";
|
|
textNode.fontFamily = "Impact, sans-serif";
|
|
textNode.fontSize = 19;
|
|
textNode.opacity = 0.7;
|
|
textNode.fill = "#9b9b9b";
|
|
textNode.textBaseline = "top";
|
|
const { width } = textNode.getBBox();
|
|
const textPadding = 10;
|
|
textNode.x = placement.x + placement.width / 2 - width / 2;
|
|
textNode.y = placement.y + placement.height + textPadding;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property3,
|
|
ActionOnSet2({
|
|
newValue(image) {
|
|
this.node.appendChild(image.node);
|
|
image.onLoad = () => this.onImageLoad();
|
|
},
|
|
oldValue(image) {
|
|
image.node.remove();
|
|
image.onLoad = void 0;
|
|
}
|
|
})
|
|
], Foreground.prototype, "image", 2);
|
|
__decorateClass([
|
|
Property3,
|
|
ProxyPropertyOnWrite("rectNode", "fill")
|
|
], Foreground.prototype, "fill", 2);
|
|
__decorateClass([
|
|
Property3,
|
|
ProxyPropertyOnWrite("rectNode", "fillOpacity")
|
|
], Foreground.prototype, "fillOpacity", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/license/md5.ts
|
|
var MD5 = class {
|
|
constructor() {
|
|
this.ieCompatibility = false;
|
|
}
|
|
init() {
|
|
this.ieCompatibility = this.md5("hello") != "5d41402abc4b2a76b9719d911017c592";
|
|
}
|
|
md5cycle(x, k) {
|
|
let a = x[0], b = x[1], c = x[2], d = x[3];
|
|
a = this.ff(a, b, c, d, k[0], 7, -680876936);
|
|
d = this.ff(d, a, b, c, k[1], 12, -389564586);
|
|
c = this.ff(c, d, a, b, k[2], 17, 606105819);
|
|
b = this.ff(b, c, d, a, k[3], 22, -1044525330);
|
|
a = this.ff(a, b, c, d, k[4], 7, -176418897);
|
|
d = this.ff(d, a, b, c, k[5], 12, 1200080426);
|
|
c = this.ff(c, d, a, b, k[6], 17, -1473231341);
|
|
b = this.ff(b, c, d, a, k[7], 22, -45705983);
|
|
a = this.ff(a, b, c, d, k[8], 7, 1770035416);
|
|
d = this.ff(d, a, b, c, k[9], 12, -1958414417);
|
|
c = this.ff(c, d, a, b, k[10], 17, -42063);
|
|
b = this.ff(b, c, d, a, k[11], 22, -1990404162);
|
|
a = this.ff(a, b, c, d, k[12], 7, 1804603682);
|
|
d = this.ff(d, a, b, c, k[13], 12, -40341101);
|
|
c = this.ff(c, d, a, b, k[14], 17, -1502002290);
|
|
b = this.ff(b, c, d, a, k[15], 22, 1236535329);
|
|
a = this.gg(a, b, c, d, k[1], 5, -165796510);
|
|
d = this.gg(d, a, b, c, k[6], 9, -1069501632);
|
|
c = this.gg(c, d, a, b, k[11], 14, 643717713);
|
|
b = this.gg(b, c, d, a, k[0], 20, -373897302);
|
|
a = this.gg(a, b, c, d, k[5], 5, -701558691);
|
|
d = this.gg(d, a, b, c, k[10], 9, 38016083);
|
|
c = this.gg(c, d, a, b, k[15], 14, -660478335);
|
|
b = this.gg(b, c, d, a, k[4], 20, -405537848);
|
|
a = this.gg(a, b, c, d, k[9], 5, 568446438);
|
|
d = this.gg(d, a, b, c, k[14], 9, -1019803690);
|
|
c = this.gg(c, d, a, b, k[3], 14, -187363961);
|
|
b = this.gg(b, c, d, a, k[8], 20, 1163531501);
|
|
a = this.gg(a, b, c, d, k[13], 5, -1444681467);
|
|
d = this.gg(d, a, b, c, k[2], 9, -51403784);
|
|
c = this.gg(c, d, a, b, k[7], 14, 1735328473);
|
|
b = this.gg(b, c, d, a, k[12], 20, -1926607734);
|
|
a = this.hh(a, b, c, d, k[5], 4, -378558);
|
|
d = this.hh(d, a, b, c, k[8], 11, -2022574463);
|
|
c = this.hh(c, d, a, b, k[11], 16, 1839030562);
|
|
b = this.hh(b, c, d, a, k[14], 23, -35309556);
|
|
a = this.hh(a, b, c, d, k[1], 4, -1530992060);
|
|
d = this.hh(d, a, b, c, k[4], 11, 1272893353);
|
|
c = this.hh(c, d, a, b, k[7], 16, -155497632);
|
|
b = this.hh(b, c, d, a, k[10], 23, -1094730640);
|
|
a = this.hh(a, b, c, d, k[13], 4, 681279174);
|
|
d = this.hh(d, a, b, c, k[0], 11, -358537222);
|
|
c = this.hh(c, d, a, b, k[3], 16, -722521979);
|
|
b = this.hh(b, c, d, a, k[6], 23, 76029189);
|
|
a = this.hh(a, b, c, d, k[9], 4, -640364487);
|
|
d = this.hh(d, a, b, c, k[12], 11, -421815835);
|
|
c = this.hh(c, d, a, b, k[15], 16, 530742520);
|
|
b = this.hh(b, c, d, a, k[2], 23, -995338651);
|
|
a = this.ii(a, b, c, d, k[0], 6, -198630844);
|
|
d = this.ii(d, a, b, c, k[7], 10, 1126891415);
|
|
c = this.ii(c, d, a, b, k[14], 15, -1416354905);
|
|
b = this.ii(b, c, d, a, k[5], 21, -57434055);
|
|
a = this.ii(a, b, c, d, k[12], 6, 1700485571);
|
|
d = this.ii(d, a, b, c, k[3], 10, -1894986606);
|
|
c = this.ii(c, d, a, b, k[10], 15, -1051523);
|
|
b = this.ii(b, c, d, a, k[1], 21, -2054922799);
|
|
a = this.ii(a, b, c, d, k[8], 6, 1873313359);
|
|
d = this.ii(d, a, b, c, k[15], 10, -30611744);
|
|
c = this.ii(c, d, a, b, k[6], 15, -1560198380);
|
|
b = this.ii(b, c, d, a, k[13], 21, 1309151649);
|
|
a = this.ii(a, b, c, d, k[4], 6, -145523070);
|
|
d = this.ii(d, a, b, c, k[11], 10, -1120210379);
|
|
c = this.ii(c, d, a, b, k[2], 15, 718787259);
|
|
b = this.ii(b, c, d, a, k[9], 21, -343485551);
|
|
x[0] = this.add32(a, x[0]);
|
|
x[1] = this.add32(b, x[1]);
|
|
x[2] = this.add32(c, x[2]);
|
|
x[3] = this.add32(d, x[3]);
|
|
}
|
|
cmn(q, a, b, x, s, t) {
|
|
a = this.add32(this.add32(a, q), this.add32(x, t));
|
|
return this.add32(a << s | a >>> 32 - s, b);
|
|
}
|
|
ff(a, b, c, d, x, s, t) {
|
|
return this.cmn(b & c | ~b & d, a, b, x, s, t);
|
|
}
|
|
gg(a, b, c, d, x, s, t) {
|
|
return this.cmn(b & d | c & ~d, a, b, x, s, t);
|
|
}
|
|
hh(a, b, c, d, x, s, t) {
|
|
return this.cmn(b ^ c ^ d, a, b, x, s, t);
|
|
}
|
|
ii(a, b, c, d, x, s, t) {
|
|
return this.cmn(c ^ (b | ~d), a, b, x, s, t);
|
|
}
|
|
md51(s) {
|
|
const n = s.length;
|
|
const state = [1732584193, -271733879, -1732584194, 271733878];
|
|
let i;
|
|
for (i = 64; i <= s.length; i += 64) {
|
|
this.md5cycle(state, this.md5blk(s.substring(i - 64, i)));
|
|
}
|
|
s = s.substring(i - 64);
|
|
const tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
|
|
for (i = 0; i < s.length; i++) {
|
|
tail[i >> 2] |= s.charCodeAt(i) << (i % 4 << 3);
|
|
}
|
|
tail[i >> 2] |= 128 << (i % 4 << 3);
|
|
if (i > 55) {
|
|
this.md5cycle(state, tail);
|
|
for (i = 0; i < 16; i++) {
|
|
tail[i] = 0;
|
|
}
|
|
}
|
|
tail[14] = n * 8;
|
|
this.md5cycle(state, tail);
|
|
return state;
|
|
}
|
|
/* there needs to be support for Unicode here, * unless we pretend that we can redefine the MD-5
|
|
* algorithm for multi-byte characters (perhaps by adding every four 16-bit characters and
|
|
* shortening the sum to 32 bits). Otherwise I suggest performing MD-5 as if every character
|
|
* was two bytes--e.g., 0040 0025 = @%--but then how will an ordinary MD-5 sum be matched?
|
|
* There is no way to standardize text to something like UTF-8 before transformation; speed cost is
|
|
* utterly prohibitive. The JavaScript standard itself needs to look at this: it should start
|
|
* providing access to strings as preformed UTF-8 8-bit unsigned value arrays.
|
|
*/
|
|
md5blk(s) {
|
|
const md5blks = [];
|
|
for (let i = 0; i < 64; i += 4) {
|
|
md5blks[i >> 2] = s.charCodeAt(i) + (s.charCodeAt(i + 1) << 8) + (s.charCodeAt(i + 2) << 16) + (s.charCodeAt(i + 3) << 24);
|
|
}
|
|
return md5blks;
|
|
}
|
|
rhex(n) {
|
|
const hex_chr = "0123456789abcdef".split("");
|
|
let s = "", j = 0;
|
|
for (; j < 4; j++) {
|
|
s += hex_chr[n >> j * 8 + 4 & 15] + hex_chr[n >> j * 8 & 15];
|
|
}
|
|
return s;
|
|
}
|
|
hex(x) {
|
|
for (let i = 0; i < x.length; i++) {
|
|
x[i] = this.rhex(x[i]);
|
|
}
|
|
return x.join("");
|
|
}
|
|
md5(s) {
|
|
return this.hex(this.md51(s));
|
|
}
|
|
add32(a, b) {
|
|
return this.ieCompatibility ? this.add32Compat(a, b) : this.add32Std(a, b);
|
|
}
|
|
/* this function is much faster, so if possible we use it. Some IEs are the only ones I know of that
|
|
need the idiotic second function, generated by an if clause. */
|
|
add32Std(a, b) {
|
|
return a + b & 4294967295;
|
|
}
|
|
add32Compat(x, y) {
|
|
const lsw = (x & 65535) + (y & 65535), msw = (x >> 16) + (y >> 16) + (lsw >> 16);
|
|
return msw << 16 | lsw & 65535;
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/license/licenseManager.ts
|
|
function missingOrEmpty(value) {
|
|
return value == null || value.length === 0;
|
|
}
|
|
var WATERMARK_SVG_DATA_URL = `data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjU4IiBoZWlnaHQ9IjQwIiB2aWV3Qm94PSIwIDAgMjU4IDQwIiBmaWxsPSJub25lIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgo8cGF0aCBkPSJNMjUuNzc5IDI4LjY1N0gxMy4zNTlMMTEuMTczIDM0LjAxMkg1LjY3Mjk3TDE3LjE4MiA3LjA1OTk5SDIxLjk1M0wzMy40NjIgMzQuMDEySDI3Ljk2MkwyNS43NzYgMjguNjU3SDI1Ljc3OVpNMjQuMDY4IDI0LjM5N0wxOS41ODggMTMuNDM0TDE1LjEwNyAyNC4zOTdIMjQuMDY4Wk02Mi4wOTIgMTguODIzSDQ5LjgxN1YyMy4wODZINTYuNzc1QzU2LjU1NSAyNS4yMjIgNTUuNzU1IDI2LjkyNyA1NC4zNzIgMjguMjAyQzUyLjk4OSAyOS40NzYgNTEuMTY2IDMwLjExNSA0OC45MDkgMzAuMTE1QzQ3LjYyMiAzMC4xMTUgNDYuNDUgMjkuODg1IDQ1LjM5MyAyOS40MjNDNDQuMzU4MyAyOC45NzgxIDQzLjQzMjYgMjguMzEzOCA0Mi42OCAyNy40NzZDNDEuOTI3IDI2LjYzOSA0MS4zNDQgMjUuNjMxIDQwLjkzMSAyNC40NTNDNDAuNTE5IDIzLjI3NSA0MC4zMTEgMjEuOTcgNDAuMzExIDIwLjUzN0M0MC4zMTEgMTkuMTA1IDQwLjUxNiAxNy44IDQwLjkzMSAxNi42MjFDNDEuMzQ0IDE1LjQ0MyA0MS45MjcgMTQuNDM2IDQyLjY4IDEzLjU5OEM0My40Mzc2IDEyLjc1NzcgNDQuMzY5NiAxMi4wOTMyIDQ1LjQxMSAxMS42NTFDNDYuNDc4IDExLjE4OSA0Ny42NTYgMTAuOTYgNDguOTQ2IDEwLjk2QzUxLjYxMiAxMC45NiA1My42MzcgMTEuNjAyIDU1LjAyIDEyLjg4NUw1OC4zIDkuNjA0OTlDNTUuODE3IDcuNjY5OTkgNTIuNjc2IDYuNjk5OTkgNDguODcyIDYuNjk5OTlDNDYuNzYgNi42OTk5OSA0NC44NTMgNy4wMzQ5OSA0My4xNTQgNy43MDA5OUM0MS40NTUgOC4zNjc5OSAzOS45OTggOS4zMDM5OSAzOC43ODMgMTAuNTA0QzM3LjU2NyAxMS43MDcgMzYuNjM0IDEzLjE1OCAzNS45NzcgMTQuODU3QzM1LjMxOSAxNi41NTYgMzQuOTk0IDE4LjQ1MSAzNC45OTQgMjAuNTRDMzQuOTk0IDIyLjYzIDM1LjMyOSAyNC40OTQgMzUuOTk1IDI2LjIwNUMzNi42NjIgMjcuOTE2IDM3LjYwNSAyOS4zNzQgMzguODE3IDMwLjU3N0M0MC4wMzIgMzEuNzggNDEuNDg2IDMyLjcxMyA0My4xODggMzMuMzgzQzQ0Ljg4OCAzNC4wNDkgNDYuNzgyIDM0LjM4NCA0OC44NzIgMzQuMzg0QzUwLjk2MSAzNC4zODQgNTIuNzUgMzQuMDQ5IDU0LjM5IDMzLjM4M0M1Ni4wMzEgMzIuNzE2IDU3LjQyNiAzMS43OCA1OC41NzkgMzAuNTc3QzU5LjczMyAyOS4zNzQgNjAuNjE5IDI3LjkxNiA2MS4yMzkgMjYuMjA1QzYxLjg2IDI0LjQ5NCA2Mi4xNyAyMi42MDUgNjIuMTcgMjAuNTRDNjIuMTY5NiAxOS45Njg4IDYyLjE0NDUgMTkuMzk4IDYyLjA5NSAxOC44MjlMNjIuMDkyIDE4LjgyM1pNMTUxLjgxIDE2Ljk4MUMxNTMuNDEgMTQuNjA5IDE1Ny40MTkgMTQuMzU4IDE1OS4wMjIgMTQuMzU4VjE4LjkxQzE1Ni45NTcgMTguOTEgMTU0Ljk4NSAxOC45OTYgMTUzLjc1NyAxOS44OTJDMTUyLjUyOSAyMC43OTIgMTUxLjkxOSAyMS45ODIgMTUxLjkxOSAyMy40NjRWMzMuOTlIMTQ2Ljk2NFYxNC4zNThIMTUxLjczNkwxNTEuODEgMTYuOTgxWk0xNDMuMDExIDE0LjM2MVYzNC4wMzFIMTM4LjI0TDEzOC4xMzEgMzEuMDQ1QzEzNy40NjYgMzIuMDc2IDEzNi41NTEgMzIuOTIxOSAxMzUuNDcxIDMzLjUwNEMxMzQuMzc2IDM0LjA5OSAxMzMuMDY4IDM0LjM5NiAxMzEuNTM2IDM0LjM5NkMxMzAuMiAzNC4zOTYgMTI4Ljk2MyAzNC4xNTIgMTI3LjgyMiAzMy42NjhDMTI2LjcgMzMuMTk2NCAxMjUuNjg5IDMyLjQ5NSAxMjQuODU1IDMxLjYwOUMxMjQuMDE4IDMwLjcyMiAxMjMuMzU0IDI5LjY2MiAxMjIuODcxIDI4LjQyMkMxMjIuMzg0IDI3LjE4NSAxMjIuMTQyIDI1LjgxMSAxMjIuMTQyIDI0LjMwNEMxMjIuMTQyIDIyLjc5OCAxMjIuMzg0IDIxLjM3OCAxMjIuODcxIDIwLjExNkMxMjMuMzU3IDE4Ljg1NCAxMjQuMDE4IDE3Ljc3MiAxMjQuODU1IDE2Ljg3M0MxMjUuNjg4IDE1Ljk3NjQgMTI2LjY5OCAxNS4yNjM2IDEyNy44MjIgMTQuNzhDMTI4Ljk2MyAxNC4yODEgMTMwLjIwMyAxNC4wMzMgMTMxLjUzNiAxNC4wMzNDMTMzLjA0MyAxNC4wMzMgMTM0LjMzIDE0LjMxOCAxMzUuMzk3IDE0Ljg4OEMxMzYuNDYyIDE1LjQ1ODkgMTM3LjM3NSAxNi4yNzggMTM4LjA1NyAxNy4yNzZWMTQuMzYxSDE0My4wMTFaTTEzMi42MzEgMzAuMTMzQzEzNC4yNTYgMzAuMTMzIDEzNS41NjcgMjkuNTk0IDEzNi41NjUgMjguNTEyQzEzNy41NjEgMjcuNDMgMTM4LjA2IDI1Ljk5MSAxMzguMDYgMjQuMTk2QzEzOC4wNiAyMi40MDEgMTM3LjU2MSAyMC45OSAxMzYuNTY1IDE5Ljg5OUMxMzUuNTcgMTguODA3IDEzNC4yNTkgMTguMjU4IDEzMi42MzEgMTguMjU4QzEzMS4wMDMgMTguMjU4IDEyOS43MjkgMTguODA0IDEyOC43MzQgMTkuODk5QzEyNy43MzggMjAuOTkzIDEyNy4yMzkgMjIuNDM4IDEyNy4yMzkgMjQuMjMzQzEyNy4yMzkgMjYuMDI4IDEyNy43MzUgMjcuNDMzIDEyOC43MzQgMjguNTE1QzEyOS43MjkgMjkuNTk0IDEzMS4wMjggMzAuMTM2IDEzMi42MzEgMzAuMTM2VjMwLjEzM1pNOTMuNjk4IDI3Ljg3NkM5My41Nzk1IDI4LjAwMjUgOTMuNDU2NCAyOC4xMjQ2IDkzLjMyOSAyOC4yNDJDOTEuOTQ3IDI5LjUxNiA5MC4xMjMgMzAuMTU1IDg3Ljg2NiAzMC4xNTVDODYuNTggMzAuMTU1IDg1LjQwOCAyOS45MjYgODQuMzUgMjkuNDY0QzgzLjMxNTUgMjkuMDE4OSA4Mi4zODk4IDI4LjM1NDYgODEuNjM3IDI3LjUxN0M4MC44ODQgMjYuNjc5IDgwLjMwMSAyNS42NzIgNzkuODg5IDI0LjQ5NEM3OS40NzYgMjMuMzE1IDc5LjI2OSAyMi4wMSA3OS4yNjkgMjAuNTc4Qzc5LjI2OSAxOS4xNDUgNzkuNDczIDE3Ljg0IDc5Ljg4OSAxNi42NjJDODAuMzAxIDE1LjQ4NCA4MC44ODQgMTQuNDc2IDgxLjYzNyAxMy42MzlDODIuMzk0OSAxMi43OTg3IDgzLjMyNzMgMTIuMTM0MiA4NC4zNjkgMTEuNjkyQzg1LjQzNiAxMS4yMyA4Ni42MTQgMTEgODcuOTAzIDExQzkwLjU3IDExIDkyLjU5NSAxMS42NDIgOTMuOTc3IDEyLjkyNkw5Ny4yNTggOS42NDQ5OUM5NC43NzQgNy43MTA5OSA5MS42MzMgNi43Mzk5OSA4Ny44MjkgNi43Mzk5OUM4NS43MTggNi43Mzk5OSA4My44MTEgNy4wNzQ5OSA4Mi4xMTIgNy43NDE5OUM4MC40MTMgOC40MDc5OSA3OC45NTYgOS4zNDQ5OSA3Ny43NCAxMC41NDVDNzYuNTI1IDExLjc0NyA3NS41OTIgMTMuMTk5IDc0LjkzNCAxNC44OThDNzQuMjc3IDE2LjU5NyA3My45NTEgMTguNDkxIDczLjk1MSAyMC41ODFDNzMuOTUxIDIyLjY3IDc0LjI4NiAyNC41MzQgNzQuOTUzIDI2LjI0NUM3NS42MTkgMjcuOTU3IDc2LjU2MiAyOS40MTQgNzcuNzc0IDMwLjYxN0M3OC45OSAzMS44MiA4MC40NDQgMzIuNzUzIDgyLjE0NiAzMy40MjNDODMuODQ1IDM0LjA5IDg1LjczOSAzNC40MjQgODcuODI5IDM0LjQyNEM4OS45MTkgMzQuNDI0IDkxLjcwOCAzNC4wOSA5My4zNDggMzMuNDIzQzk0LjcxOCAzMi44NjUgOTUuOTE4IDMyLjEyMSA5Ni45NDggMzEuMTkxQzk3LjE0OSAzMS4wMDggOTcuMzQ4IDMwLjgxNSA5Ny41MzcgMzAuNjJMOTMuNzAxIDI3Ljg4NUw5My42OTggMjcuODc2Wk0xMTAuODAyIDE0LjAxNUMxMDkuMTk5IDE0LjAxNSAxMDYuODM2IDE0LjQ3MSAxMDUuNjExIDE2LjE1OEwxMDUuNTM3IDYuMDE1OTlIMTAwLjc2NVYzMy45MzlIMTA1LjcyVjIyLjY0MUMxMDUuNzcxIDIxLjQ2MDcgMTA2LjI4OCAyMC4zNDg4IDEwNy4xNTcgMTkuNTQ4OUMxMDguMDI3IDE4Ljc0OTEgMTA5LjE3OCAxOC4zMjY2IDExMC4zNTggMTguMzc0QzExMy4zOTcgMTguMzc0IDExNC4yNjggMjEuMTU5IDExNC4yNjggMjIuNjQxVjMzLjkzOUgxMTkuMjIzVjIxLjA1OUMxMTkuMjIzIDIxLjA1OSAxMTkuMTQyIDE0LjAxNSAxMTAuODAyIDE0LjAxNVpNMTczLjc2MyAxNC4zNThIMTY5Ljk5OVY4LjcxNDk5SDE2NS4wNDhWMTQuMzU4SDE2MS4yODRWMTguOTE2SDE2NS4wNDhWMzQuMDAzSDE2OS45OTlWMTguOTE2SDE3My43NjNWMTQuMzU4Wk0xOTAuNzg3IDI1LjI2MkMxOTAuMTI5IDI0LjUwMTQgMTg5LjMwNyAyMy44OTk0IDE4OC4zODQgMjMuNTAxQzE4Ny40ODggMjMuMTE3IDE4Ni4zMzEgMjIuNzMyIDE4NC45NDggMjIuMzY0QzE4NC4xNjUgMjIuMTQzOSAxODMuMzkgMjEuODk3OCAxODIuNjIzIDIxLjYyNkMxODIuMTYzIDIxLjQ2MjEgMTgxLjc0MSAyMS4yMDY2IDE4MS4zODMgMjAuODc1QzE4MS4yMzUgMjAuNzQyMSAxODEuMTE4IDIwLjU3ODkgMTgxLjAzOSAyMC4zOTY0QzE4MC45NjEgMjAuMjE0IDE4MC45MjIgMjAuMDE2NiAxODAuOTI3IDE5LjgxOEMxODAuOTI3IDE5LjI3MiAxODEuMTU2IDE4Ljg0NCAxODEuNjI1IDE4LjUxQzE4Mi4xMjEgMTguMTU2IDE4Mi44NjIgMTcuOTc2IDE4My44MjYgMTcuOTc2QzE4NC43OSAxNy45NzYgMTg1LjU4NyAxOC4yMDkgMTg2LjE0OCAxOC42NjhDMTg2LjcwNiAxOS4xMjQgMTg3LjAwNyAxOS43MjUgMTg3LjA3MiAyMC41TDE4Ny4wOTQgMjAuNzgySDE5MS42MzNMMTkxLjYxNyAyMC40NkMxOTEuNTIxIDE4LjQ4NSAxOTAuNzcxIDE2LjkgMTg5LjM4NSAxNS43NUMxODguMDEyIDE0LjYxMiAxODYuMTg1IDE0LjAzMyAxODMuOTYyIDE0LjAzM0MxODIuNDc3IDE0LjAzMyAxODEuMTQxIDE0LjI4NyAxNzkuOTk0IDE0Ljc4NkMxNzguODMxIDE1LjI5MSAxNzcuOTI2IDE1Ljk5NSAxNzcuMjk2IDE2Ljg4MkMxNzYuNjczIDE3Ljc0NTUgMTc2LjMzOCAxOC43ODQgMTc2LjM0MSAxOS44NDlDMTc2LjM0MSAyMS4xNjcgMTc2LjY5OCAyMi4yNDkgMTc3LjM5OSAyMy4wNjRDMTc4LjA2IDIzLjg0MzIgMTc4Ljg5OCAyNC40NTM0IDE3OS44NDIgMjQuODQ0QzE4MC43NDQgMjUuMjE2IDE4MS45MjggMjUuNjA3IDE4My4zNjEgMjZDMTg0LjgwNiAyNi40MSAxODUuODcyIDI2Ljc4NSAxODYuNTMgMjcuMTIzQzE4Ny4xIDI3LjQxNCAxODcuMzc5IDI3Ljg0NSAxODcuMzc5IDI4LjQ0NEMxODcuMzc5IDI5LjA0MiAxODcuMTIyIDI5LjQ2NyAxODYuNTk1IDI5LjgzOUMxODYuMDQzIDMwLjIyNiAxODUuMjM3IDMwLjQyNSAxODQuMjAxIDMwLjQyNUMxODMuMTY2IDMwLjQyNSAxODIuMzk0IDMwLjE3NCAxODEuNzQ5IDI5LjY3NEMxODEuMTEzIDI5LjE4MSAxODAuNzcyIDI4LjU4OSAxODAuNzEgMjcuODY0TDE4MC42ODUgMjcuNTgySDE3Ni4wMTNMMTc2LjAyNSAyNy45MDFDMTc2LjA2NyAyOS4wOTU1IDE3Ni40NzIgMzAuMjQ4NyAxNzcuMTg4IDMxLjIwNkMxNzcuOTA3IDMyLjE4IDE3OC44OTMgMzIuOTU4IDE4MC4xMTggMzMuNTE5QzE4MS4zMzYgMzQuMDc3IDE4Mi43MzIgMzQuMzYyIDE4NC4yNjYgMzQuMzYyQzE4NS44MDEgMzQuMzYyIDE4Ny4xMDkgMzQuMTA4IDE4OC4yMzggMzMuNjA5QzE4OS4zNzYgMzMuMTA0IDE5MC4yNzIgMzIuMzk0IDE5MC45MDEgMzEuNDk0QzE5MS41MzQgMzAuNTkyIDE5MS44NTMgMjkuNTU0IDE5MS44NTMgMjguNDAzQzE5MS44MjggMjcuMTEgMTkxLjQ2NiAyNi4wNTMgMTkwLjc3NyAyNS4yNjJIMTkwLjc4N1oiIGZpbGw9IiM5QjlCOUIiLz4KPHBhdGggZD0iTTI0MS45ODIgMjUuNjU4MlYxNy43MTE3SDIyOC40NDFMMjIwLjQ5NCAyNS42NTgySDI0MS45ODJaIiBmaWxsPSIjOUI5QjlCIi8+CjxwYXRoIGQ9Ik0yNTcuMjM5IDUuOTUwODFIMjQwLjI2NUwyMzIuMjU1IDEzLjg5NzNIMjU3LjIzOVY1Ljk1MDgxWiIgZmlsbD0iIzlCOUI5QiIvPgo8cGF0aCBkPSJNMjEyLjYxMSAzMy42MDQ4TDIxNi42OCAyOS41MzYxSDIzMC40MTJWMzcuNDgyN0gyMTIuNjExVjMzLjYwNDhaIiBmaWxsPSIjOUI5QjlCIi8+CjxwYXRoIGQ9Ik0yMTUuNTk5IDIxLjc4MDNIMjI0LjM3MkwyMzIuMzgyIDEzLjgzMzdIMjE1LjU5OVYyMS43ODAzWiIgZmlsbD0iIzlCOUI5QiIvPgo8cGF0aCBkPSJNMjA2IDMzLjYwNDdIMjEyLjYxMUwyMjAuNDk0IDI1LjY1ODJIMjA2VjMzLjYwNDdaIiBmaWxsPSIjOUI5QjlCIi8+CjxwYXRoIGQ9Ik0yNDAuMjY1IDUuOTUwODFMMjM2LjE5NyAxMC4wMTk0SDIxMC4yNTlWMi4wNzI4OEgyNDAuMjY1VjUuOTUwODFaIiBmaWxsPSIjOUI5QjlCIi8+Cjwvc3ZnPgo=`;
|
|
var LICENSE_TYPES = {
|
|
"01": "GRID",
|
|
"02": "CHARTS",
|
|
"0102": "BOTH"
|
|
};
|
|
var LICENSING_HELP_URL = "https://www.ag-grid.com/charts/licensing/";
|
|
var _LicenseManager = class _LicenseManager {
|
|
constructor(document2) {
|
|
this.watermarkMessage = void 0;
|
|
this.totalMessageLength = 124;
|
|
this.document = document2;
|
|
this.md5 = new MD5();
|
|
this.md5.init();
|
|
}
|
|
validateLicense() {
|
|
const licenseDetails = this.getLicenseDetails(_LicenseManager.licenseKey, _LicenseManager.gridContext);
|
|
const currentLicenseName = `AG ${licenseDetails.currentLicenseType === "BOTH" ? "Grid and " : ""}Charts Enterprise`;
|
|
let suppliedLicenseName = "";
|
|
if (licenseDetails.suppliedLicenseType === "BOTH") {
|
|
suppliedLicenseName = "AG Grid and AG Charts Enterprise";
|
|
} else if (licenseDetails.suppliedLicenseType === "GRID") {
|
|
suppliedLicenseName = "AG Grid Enterprise";
|
|
} else if (licenseDetails.suppliedLicenseType !== void 0) {
|
|
suppliedLicenseName = "AG Charts Enterprise";
|
|
}
|
|
if (licenseDetails.missing) {
|
|
if (!this.isWebsiteUrl() || this.isForceWatermark()) {
|
|
this.outputMissingLicenseKey(currentLicenseName);
|
|
}
|
|
} else if (licenseDetails.expired) {
|
|
const gridReleaseDate = _LicenseManager.getChartsReleaseDate();
|
|
const formattedReleaseDate = _LicenseManager.formatDate(gridReleaseDate);
|
|
this.outputExpiredKey(licenseDetails.expiry, formattedReleaseDate, suppliedLicenseName);
|
|
} else if (!licenseDetails.valid) {
|
|
this.outputInvalidLicenseKey(
|
|
!!licenseDetails.incorrectLicenseType,
|
|
currentLicenseName,
|
|
suppliedLicenseName
|
|
);
|
|
} else if (licenseDetails.isTrial && licenseDetails.trialExpired) {
|
|
this.outputExpiredTrialKey(licenseDetails.expiry, currentLicenseName, suppliedLicenseName);
|
|
}
|
|
}
|
|
static extractExpiry(license) {
|
|
const restrictionHashed = license.substring(license.lastIndexOf("_") + 1, license.length);
|
|
return new Date(Number.parseInt(_LicenseManager.decode(restrictionHashed), 10));
|
|
}
|
|
static extractLicenseComponents(licenseKey) {
|
|
let cleanedLicenseKey = licenseKey.replaceAll(/[\u200B-\u200D\uFEFF]/g, "");
|
|
cleanedLicenseKey = cleanedLicenseKey.replaceAll(/\r?\n|\r/g, "");
|
|
if (licenseKey.length <= 32) {
|
|
return { md5: null, license: licenseKey, version: null, isTrial: null };
|
|
}
|
|
const hashStart = cleanedLicenseKey.length - 32;
|
|
const md5 = cleanedLicenseKey.substring(hashStart);
|
|
const license = cleanedLicenseKey.substring(0, hashStart);
|
|
const [version, isTrial, type] = _LicenseManager.extractBracketedInformation(cleanedLicenseKey);
|
|
return { md5, license, version, isTrial, type };
|
|
}
|
|
getLicenseDetails(licenseKey, gridContext = false) {
|
|
const currentLicenseType = "CHARTS";
|
|
if (missingOrEmpty(licenseKey)) {
|
|
return {
|
|
licenseKey,
|
|
valid: false,
|
|
missing: true,
|
|
currentLicenseType
|
|
};
|
|
}
|
|
const chartsReleaseDate = _LicenseManager.getChartsReleaseDate();
|
|
const { md5, license, version, isTrial, type } = _LicenseManager.extractLicenseComponents(licenseKey);
|
|
let valid = md5 === this.md5.md5(license) && !licenseKey.includes("For_Trialing_ag-Grid_Only");
|
|
let trialExpired = void 0;
|
|
let expired = void 0;
|
|
let expiry = null;
|
|
let incorrectLicenseType = false;
|
|
let suppliedLicenseType = void 0;
|
|
function handleTrial() {
|
|
const now = /* @__PURE__ */ new Date();
|
|
trialExpired = expiry < now;
|
|
expired = void 0;
|
|
}
|
|
if (valid) {
|
|
expiry = _LicenseManager.extractExpiry(license);
|
|
valid = !Number.isNaN(expiry.getTime());
|
|
if (valid) {
|
|
expired = chartsReleaseDate > expiry;
|
|
switch (version) {
|
|
case "legacy":
|
|
case "2": {
|
|
valid = false;
|
|
break;
|
|
}
|
|
case "3": {
|
|
if (missingOrEmpty(type)) {
|
|
valid = false;
|
|
} else {
|
|
suppliedLicenseType = type;
|
|
if (type !== LICENSE_TYPES["02"] && type !== LICENSE_TYPES["0102"]) {
|
|
valid = false;
|
|
incorrectLicenseType = true;
|
|
} else if (isTrial) {
|
|
handleTrial();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (!valid) {
|
|
return {
|
|
licenseKey,
|
|
valid,
|
|
incorrectLicenseType,
|
|
currentLicenseType,
|
|
suppliedLicenseType
|
|
};
|
|
}
|
|
return {
|
|
licenseKey,
|
|
valid,
|
|
expiry: _LicenseManager.formatDate(expiry),
|
|
expired,
|
|
version,
|
|
isTrial,
|
|
trialExpired,
|
|
invalidLicenseTypeForCombo: gridContext ? suppliedLicenseType !== "BOTH" : void 0,
|
|
incorrectLicenseType,
|
|
currentLicenseType,
|
|
suppliedLicenseType
|
|
};
|
|
}
|
|
isDisplayWatermark() {
|
|
return this.isForceWatermark() || !this.isLocalhost() && !this.isE2ETest() && !this.isWebsiteUrl() && !missingOrEmpty(this.watermarkMessage);
|
|
}
|
|
getWatermarkMessage() {
|
|
return this.watermarkMessage ?? "";
|
|
}
|
|
getWatermarkForegroundConfig() {
|
|
const message = this.getWatermarkMessage();
|
|
if (!message) {
|
|
return void 0;
|
|
}
|
|
return this.buildWatermarkConfig(message);
|
|
}
|
|
getWatermarkForegroundConfigForBrowser() {
|
|
if (!this.isDisplayWatermark()) {
|
|
return void 0;
|
|
}
|
|
const message = this.getWatermarkMessage();
|
|
if (!message) {
|
|
return void 0;
|
|
}
|
|
return this.buildWatermarkConfig(message);
|
|
}
|
|
buildWatermarkConfig(text2) {
|
|
return {
|
|
text: text2,
|
|
image: {
|
|
url: WATERMARK_SVG_DATA_URL,
|
|
width: 170,
|
|
height: 25,
|
|
right: 25,
|
|
bottom: 50,
|
|
opacity: 0.7
|
|
}
|
|
};
|
|
}
|
|
getHostname() {
|
|
if (!this.document) {
|
|
return "localhost";
|
|
}
|
|
const win = this.document.defaultView ?? globalThis;
|
|
if (!win) {
|
|
return "localhost";
|
|
}
|
|
try {
|
|
const hostname = win.location?.hostname ?? "";
|
|
return hostname || "localhost";
|
|
} catch {
|
|
return "localhost";
|
|
}
|
|
}
|
|
isForceWatermark() {
|
|
if (!this.document) {
|
|
return false;
|
|
}
|
|
const win = this.document?.defaultView ?? globalThis.window != void 0 ? globalThis : void 0;
|
|
if (!win) {
|
|
return false;
|
|
}
|
|
const pathname = win.location?.pathname;
|
|
return pathname ? pathname.includes("forceWatermark") : false;
|
|
}
|
|
isWebsiteUrl() {
|
|
const hostname = this.getHostname();
|
|
return /^((?:[\w-]+\.)?ag-grid\.com)$/.exec(hostname) !== null;
|
|
}
|
|
isLocalhost() {
|
|
const hostname = this.getHostname();
|
|
return /^(?:127\.0\.0\.1|localhost)$/.exec(hostname) !== null;
|
|
}
|
|
isE2ETest() {
|
|
const hostname = this.getHostname();
|
|
return /^(?:172\.17\.0\.1|host\.docker\.internal)$/.exec(hostname) !== null;
|
|
}
|
|
static formatDate(date2) {
|
|
const monthNames = [
|
|
"January",
|
|
"February",
|
|
"March",
|
|
"April",
|
|
"May",
|
|
"June",
|
|
"July",
|
|
"August",
|
|
"September",
|
|
"October",
|
|
"November",
|
|
"December"
|
|
];
|
|
const day = date2.getDate();
|
|
const monthIndex = date2.getMonth();
|
|
const year = date2.getFullYear();
|
|
return day + " " + monthNames[monthIndex] + " " + year;
|
|
}
|
|
static getChartsReleaseDate() {
|
|
return new Date(Number.parseInt(_LicenseManager.decode(_LicenseManager.RELEASE_INFORMATION), 10));
|
|
}
|
|
static decode(input) {
|
|
const keystr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
|
|
let t = "";
|
|
let n, r, i;
|
|
let s, o, u, a;
|
|
let f = 0;
|
|
const e = input.replaceAll(/[^A-Za-z0-9+/=]/g, "");
|
|
while (f < e.length) {
|
|
s = keystr.indexOf(e.charAt(f++));
|
|
o = keystr.indexOf(e.charAt(f++));
|
|
u = keystr.indexOf(e.charAt(f++));
|
|
a = keystr.indexOf(e.charAt(f++));
|
|
n = s << 2 | o >> 4;
|
|
r = (o & 15) << 4 | u >> 2;
|
|
i = (u & 3) << 6 | a;
|
|
t = t + String.fromCodePoint(n);
|
|
if (u != 64) {
|
|
t = t + String.fromCodePoint(r);
|
|
}
|
|
if (a != 64) {
|
|
t = t + String.fromCodePoint(i);
|
|
}
|
|
}
|
|
t = _LicenseManager.utf8_decode(t);
|
|
return t;
|
|
}
|
|
static utf8_decode(input) {
|
|
input = input.replaceAll("rn", "n");
|
|
let t = "";
|
|
for (let n = 0; n < input.length; n++) {
|
|
const r = input.codePointAt(n);
|
|
if (r < 128) {
|
|
t += String.fromCodePoint(r);
|
|
} else if (r > 127 && r < 2048) {
|
|
t += String.fromCodePoint(r >> 6 | 192);
|
|
t += String.fromCodePoint(r & 63 | 128);
|
|
} else {
|
|
t += String.fromCodePoint(r >> 12 | 224);
|
|
t += String.fromCodePoint(r >> 6 & 63 | 128);
|
|
t += String.fromCodePoint(r & 63 | 128);
|
|
}
|
|
}
|
|
return t;
|
|
}
|
|
static setGridContext(gridContext = false) {
|
|
_LicenseManager.gridContext = gridContext;
|
|
}
|
|
static setLicenseKey(licenseKey) {
|
|
if (this.licenseKey && this.licenseKey !== licenseKey) {
|
|
console.warn(
|
|
`License Key being set multiple times with different values. This can result in an incorrect license key being used.`
|
|
);
|
|
}
|
|
_LicenseManager.licenseKey = licenseKey;
|
|
}
|
|
static extractBracketedInformation(licenseKey) {
|
|
if (!licenseKey.includes("[")) {
|
|
return ["legacy", false, void 0];
|
|
}
|
|
const matches = licenseKey.match(/\[(.*?)\]/g).map((match) => match.replace("[", "").replace("]", ""));
|
|
if (!matches || matches.length === 0) {
|
|
return ["legacy", false, void 0];
|
|
}
|
|
const isTrial = matches.filter((match) => match === "TRIAL").length === 1;
|
|
const rawVersion = matches.find((match) => match.startsWith("v"));
|
|
const version = rawVersion ? rawVersion.replace("v", "") : "legacy";
|
|
const type = LICENSE_TYPES[matches.find((match) => LICENSE_TYPES[match])];
|
|
return [version, isTrial, type];
|
|
}
|
|
centerPadAndOutput(input) {
|
|
const paddingRequired = this.totalMessageLength - input.length;
|
|
console.error(input.padStart(paddingRequired / 2 + input.length, "*").padEnd(this.totalMessageLength, "*"));
|
|
}
|
|
padAndOutput(input, padding2 = "*", terminateWithPadding = "") {
|
|
console.error(
|
|
input.padEnd(this.totalMessageLength - terminateWithPadding.length, padding2) + terminateWithPadding
|
|
);
|
|
}
|
|
outputInvalidLicenseKey(incorrectLicenseType, currentLicenseName, suppliedLicenseName) {
|
|
if (!_LicenseManager.gridContext) {
|
|
if (incorrectLicenseType) {
|
|
this.centerPadAndOutput("");
|
|
this.centerPadAndOutput(` ${currentLicenseName} License `);
|
|
this.centerPadAndOutput(" Incompatible License Key ");
|
|
this.padAndOutput(
|
|
`* Your license key is for ${suppliedLicenseName} only and does not cover you for ${currentLicenseName}.`,
|
|
" ",
|
|
"*"
|
|
);
|
|
this.padAndOutput(`* To troubleshoot your license key visit ${LICENSING_HELP_URL}.`, " ", "*");
|
|
this.centerPadAndOutput("");
|
|
this.centerPadAndOutput("");
|
|
} else {
|
|
this.centerPadAndOutput("");
|
|
this.centerPadAndOutput(` ${currentLicenseName} License `);
|
|
this.centerPadAndOutput(" Invalid License Key ");
|
|
this.padAndOutput(`* Your license key is not valid.`, " ", "*");
|
|
this.padAndOutput(`* To troubleshoot your license key visit ${LICENSING_HELP_URL}.`, " ", "*");
|
|
this.centerPadAndOutput("");
|
|
this.centerPadAndOutput("");
|
|
}
|
|
}
|
|
this.watermarkMessage = "Invalid License";
|
|
}
|
|
outputExpiredTrialKey(formattedExpiryDate, currentLicenseName, suppliedLicenseName) {
|
|
if (!_LicenseManager.gridContext) {
|
|
this.centerPadAndOutput("");
|
|
this.centerPadAndOutput(` ${currentLicenseName} License `);
|
|
this.centerPadAndOutput(" Trial Period Expired. ");
|
|
this.padAndOutput(
|
|
`* Your trial only license for ${suppliedLicenseName} expired on ${formattedExpiryDate}.`,
|
|
" ",
|
|
"*"
|
|
);
|
|
this.padAndOutput("* Please email info@ag-grid.com to purchase a license.", " ", "*");
|
|
this.centerPadAndOutput("");
|
|
this.centerPadAndOutput("");
|
|
}
|
|
this.watermarkMessage = "Trial Period Expired";
|
|
}
|
|
outputMissingLicenseKey(currentLicenseName) {
|
|
if (!_LicenseManager.gridContext) {
|
|
this.centerPadAndOutput("");
|
|
this.centerPadAndOutput(` ${currentLicenseName} License `);
|
|
this.centerPadAndOutput(" License Key Not Found ");
|
|
this.padAndOutput(`* All ${currentLicenseName} features are unlocked for trial.`, " ", "*");
|
|
this.padAndOutput(
|
|
"* If you want to hide the watermark please email info@ag-grid.com for a trial license key.",
|
|
" ",
|
|
"*"
|
|
);
|
|
this.centerPadAndOutput("");
|
|
this.centerPadAndOutput("");
|
|
}
|
|
this.watermarkMessage = "For Trial Use Only";
|
|
}
|
|
outputExpiredKey(formattedExpiryDate, formattedReleaseDate, currentLicenseName) {
|
|
if (!_LicenseManager.gridContext) {
|
|
this.centerPadAndOutput("");
|
|
this.centerPadAndOutput(` ${currentLicenseName} License `);
|
|
this.centerPadAndOutput(" Incompatible Software Version ");
|
|
this.padAndOutput(
|
|
`* Your license key works with versions of ${currentLicenseName} released before ${formattedExpiryDate}.`,
|
|
" ",
|
|
"*"
|
|
);
|
|
this.padAndOutput(`* The version you are trying to use was released on ${formattedReleaseDate}.`, " ", "*");
|
|
this.padAndOutput("* Please contact info@ag-grid.com to renew your license key.", " ", "*");
|
|
this.centerPadAndOutput("");
|
|
this.centerPadAndOutput("");
|
|
}
|
|
this.watermarkMessage = "License Expired";
|
|
}
|
|
};
|
|
_LicenseManager.RELEASE_INFORMATION = "MTc3MDgwNzY1NDM4MQ==";
|
|
_LicenseManager.gridContext = false;
|
|
var LicenseManager = _LicenseManager;
|
|
|
|
// packages/ag-charts-enterprise/src/license/watermark.ts
|
|
import { createElement as createElement2 } from "ag-charts-core";
|
|
function injectWatermark(domManager, text2) {
|
|
const element = domManager.addChild("canvas-overlay", "watermark");
|
|
const textElement = createElement2("span");
|
|
textElement.innerText = text2;
|
|
element.addEventListener("animationend", () => {
|
|
domManager.removeChild("canvas-overlay", "watermark");
|
|
domManager.removeStyles("watermark");
|
|
});
|
|
element.classList.add("ag-watermark");
|
|
element.appendChild(textElement);
|
|
}
|
|
|
|
// packages/ag-charts-enterprise/src/styles.css
|
|
var styles_default = `.ag-watermark{position:absolute;bottom:20px;right:25px;font-weight:700;font-family:Impact,sans-serif;font-size:19px;opacity:.7;animation:1s ease-out 3s ag-watermark-fadeout;color:#9b9b9b;pointer-events:none;&:before{content:"";display:block;height:40px;width:170px;background-image:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjU4IiBoZWlnaHQ9IjQwIiB2aWV3Qm94PSIwIDAgMjU4IDQwIiBmaWxsPSJub25lIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgo8cGF0aCBkPSJNMjUuNzc5IDI4LjY1N0gxMy4zNTlMMTEuMTczIDM0LjAxMkg1LjY3Mjk3TDE3LjE4MiA3LjA1OTk5SDIxLjk1M0wzMy40NjIgMzQuMDEySDI3Ljk2MkwyNS43NzYgMjguNjU3SDI1Ljc3OVpNMjQuMDY4IDI0LjM5N0wxOS41ODggMTMuNDM0TDE1LjEwNyAyNC4zOTdIMjQuMDY4Wk02Mi4wOTIgMTguODIzSDQ5LjgxN1YyMy4wODZINTYuNzc1QzU2LjU1NSAyNS4yMjIgNTUuNzU1IDI2LjkyNyA1NC4zNzIgMjguMjAyQzUyLjk4OSAyOS40NzYgNTEuMTY2IDMwLjExNSA0OC45MDkgMzAuMTE1QzQ3LjYyMiAzMC4xMTUgNDYuNDUgMjkuODg1IDQ1LjM5MyAyOS40MjNDNDQuMzU4MyAyOC45NzgxIDQzLjQzMjYgMjguMzEzOCA0Mi42OCAyNy40NzZDNDEuOTI3IDI2LjYzOSA0MS4zNDQgMjUuNjMxIDQwLjkzMSAyNC40NTNDNDAuNTE5IDIzLjI3NSA0MC4zMTEgMjEuOTcgNDAuMzExIDIwLjUzN0M0MC4zMTEgMTkuMTA1IDQwLjUxNiAxNy44IDQwLjkzMSAxNi42MjFDNDEuMzQ0IDE1LjQ0MyA0MS45MjcgMTQuNDM2IDQyLjY4IDEzLjU5OEM0My40Mzc2IDEyLjc1NzcgNDQuMzY5NiAxMi4wOTMyIDQ1LjQxMSAxMS42NTFDNDYuNDc4IDExLjE4OSA0Ny42NTYgMTAuOTYgNDguOTQ2IDEwLjk2QzUxLjYxMiAxMC45NiA1My42MzcgMTEuNjAyIDU1LjAyIDEyLjg4NUw1OC4zIDkuNjA0OTlDNTUuODE3IDcuNjY5OTkgNTIuNjc2IDYuNjk5OTkgNDguODcyIDYuNjk5OTlDNDYuNzYgNi42OTk5OSA0NC44NTMgNy4wMzQ5OSA0My4xNTQgNy43MDA5OUM0MS40NTUgOC4zNjc5OSAzOS45OTggOS4zMDM5OSAzOC43ODMgMTAuNTA0QzM3LjU2NyAxMS43MDcgMzYuNjM0IDEzLjE1OCAzNS45NzcgMTQuODU3QzM1LjMxOSAxNi41NTYgMzQuOTk0IDE4LjQ1MSAzNC45OTQgMjAuNTRDMzQuOTk0IDIyLjYzIDM1LjMyOSAyNC40OTQgMzUuOTk1IDI2LjIwNUMzNi42NjIgMjcuOTE2IDM3LjYwNSAyOS4zNzQgMzguODE3IDMwLjU3N0M0MC4wMzIgMzEuNzggNDEuNDg2IDMyLjcxMyA0My4xODggMzMuMzgzQzQ0Ljg4OCAzNC4wNDkgNDYuNzgyIDM0LjM4NCA0OC44NzIgMzQuMzg0QzUwLjk2MSAzNC4zODQgNTIuNzUgMzQuMDQ5IDU0LjM5IDMzLjM4M0M1Ni4wMzEgMzIuNzE2IDU3LjQyNiAzMS43OCA1OC41NzkgMzAuNTc3QzU5LjczMyAyOS4zNzQgNjAuNjE5IDI3LjkxNiA2MS4yMzkgMjYuMjA1QzYxLjg2IDI0LjQ5NCA2Mi4xNyAyMi42MDUgNjIuMTcgMjAuNTRDNjIuMTY5NiAxOS45Njg4IDYyLjE0NDUgMTkuMzk4IDYyLjA5NSAxOC44MjlMNjIuMDkyIDE4LjgyM1pNMTUxLjgxIDE2Ljk4MUMxNTMuNDEgMTQuNjA5IDE1Ny40MTkgMTQuMzU4IDE1OS4wMjIgMTQuMzU4VjE4LjkxQzE1Ni45NTcgMTguOTEgMTU0Ljk4NSAxOC45OTYgMTUzLjc1NyAxOS44OTJDMTUyLjUyOSAyMC43OTIgMTUxLjkxOSAyMS45ODIgMTUxLjkxOSAyMy40NjRWMzMuOTlIMTQ2Ljk2NFYxNC4zNThIMTUxLjczNkwxNTEuODEgMTYuOTgxWk0xNDMuMDExIDE0LjM2MVYzNC4wMzFIMTM4LjI0TDEzOC4xMzEgMzEuMDQ1QzEzNy40NjYgMzIuMDc2IDEzNi41NTEgMzIuOTIxOSAxMzUuNDcxIDMzLjUwNEMxMzQuMzc2IDM0LjA5OSAxMzMuMDY4IDM0LjM5NiAxMzEuNTM2IDM0LjM5NkMxMzAuMiAzNC4zOTYgMTI4Ljk2MyAzNC4xNTIgMTI3LjgyMiAzMy42NjhDMTI2LjcgMzMuMTk2NCAxMjUuNjg5IDMyLjQ5NSAxMjQuODU1IDMxLjYwOUMxMjQuMDE4IDMwLjcyMiAxMjMuMzU0IDI5LjY2MiAxMjIuODcxIDI4LjQyMkMxMjIuMzg0IDI3LjE4NSAxMjIuMTQyIDI1LjgxMSAxMjIuMTQyIDI0LjMwNEMxMjIuMTQyIDIyLjc5OCAxMjIuMzg0IDIxLjM3OCAxMjIuODcxIDIwLjExNkMxMjMuMzU3IDE4Ljg1NCAxMjQuMDE4IDE3Ljc3MiAxMjQuODU1IDE2Ljg3M0MxMjUuNjg4IDE1Ljk3NjQgMTI2LjY5OCAxNS4yNjM2IDEyNy44MjIgMTQuNzhDMTI4Ljk2MyAxNC4yODEgMTMwLjIwMyAxNC4wMzMgMTMxLjUzNiAxNC4wMzNDMTMzLjA0MyAxNC4wMzMgMTM0LjMzIDE0LjMxOCAxMzUuMzk3IDE0Ljg4OEMxMzYuNDYyIDE1LjQ1ODkgMTM3LjM3NSAxNi4yNzggMTM4LjA1NyAxNy4yNzZWMTQuMzYxSDE0My4wMTFaTTEzMi42MzEgMzAuMTMzQzEzNC4yNTYgMzAuMTMzIDEzNS41NjcgMjkuNTk0IDEzNi41NjUgMjguNTEyQzEzNy41NjEgMjcuNDMgMTM4LjA2IDI1Ljk5MSAxMzguMDYgMjQuMTk2QzEzOC4wNiAyMi40MDEgMTM3LjU2MSAyMC45OSAxMzYuNTY1IDE5Ljg5OUMxMzUuNTcgMTguODA3IDEzNC4yNTkgMTguMjU4IDEzMi42MzEgMTguMjU4QzEzMS4wMDMgMTguMjU4IDEyOS43MjkgMTguODA0IDEyOC43MzQgMTkuODk5QzEyNy43MzggMjAuOTkzIDEyNy4yMzkgMjIuNDM4IDEyNy4yMzkgMjQuMjMzQzEyNy4yMzkgMjYuMDI4IDEyNy43MzUgMjcuNDMzIDEyOC43MzQgMjguNTE1QzEyOS43MjkgMjkuNTk0IDEzMS4wMjggMzAuMTM2IDEzMi42MzEgMzAuMTM2VjMwLjEzM1pNOTMuNjk4IDI3Ljg3NkM5My41Nzk1IDI4LjAwMjUgOTMuNDU2NCAyOC4xMjQ2IDkzLjMyOSAyOC4yNDJDOTEuOTQ3IDI5LjUxNiA5MC4xMjMgMzAuMTU1IDg3Ljg2NiAzMC4xNTVDODYuNTggMzAuMTU1IDg1LjQwOCAyOS45MjYgODQuMzUgMjkuNDY0QzgzLjMxNTUgMjkuMDE4OSA4Mi4zODk4IDI4LjM1NDYgODEuNjM3IDI3LjUxN0M4MC44ODQgMjYuNjc5IDgwLjMwMSAyNS42NzIgNzkuODg5IDI0LjQ5NEM3OS40NzYgMjMuMzE1IDc5LjI2OSAyMi4wMSA3OS4yNjkgMjAuNTc4Qzc5LjI2OSAxOS4xNDUgNzkuNDczIDE3Ljg0IDc5Ljg4OSAxNi42NjJDODAuMzAxIDE1LjQ4NCA4MC44ODQgMTQuNDc2IDgxLjYzNyAxMy42MzlDODIuMzk0OSAxMi43OTg3IDgzLjMyNzMgMTIuMTM0MiA4NC4zNjkgMTEuNjkyQzg1LjQzNiAxMS4yMyA4Ni42MTQgMTEgODcuOTAzIDExQzkwLjU3IDExIDkyLjU5NSAxMS42NDIgOTMuOTc3IDEyLjkyNkw5Ny4yNTggOS42NDQ5OUM5NC43NzQgNy43MTA5OSA5MS42MzMgNi43Mzk5OSA4Ny44MjkgNi43Mzk5OUM4NS43MTggNi43Mzk5OSA4My44MTEgNy4wNzQ5OSA4Mi4xMTIgNy43NDE5OUM4MC40MTMgOC40MDc5OSA3OC45NTYgOS4zNDQ5OSA3Ny43NCAxMC41NDVDNzYuNTI1IDExLjc0NyA3NS41OTIgMTMuMTk5IDc0LjkzNCAxNC44OThDNzQuMjc3IDE2LjU5NyA3My45NTEgMTguNDkxIDczLjk1MSAyMC41ODFDNzMuOTUxIDIyLjY3IDc0LjI4NiAyNC41MzQgNzQuOTUzIDI2LjI0NUM3NS42MTkgMjcuOTU3IDc2LjU2MiAyOS40MTQgNzcuNzc0IDMwLjYxN0M3OC45OSAzMS44MiA4MC40NDQgMzIuNzUzIDgyLjE0NiAzMy40MjNDODMuODQ1IDM0LjA5IDg1LjczOSAzNC40MjQgODcuODI5IDM0LjQyNEM4OS45MTkgMzQuNDI0IDkxLjcwOCAzNC4wOSA5My4zNDggMzMuNDIzQzk0LjcxOCAzMi44NjUgOTUuOTE4IDMyLjEyMSA5Ni45NDggMzEuMTkxQzk3LjE0OSAzMS4wMDggOTcuMzQ4IDMwLjgxNSA5Ny41MzcgMzAuNjJMOTMuNzAxIDI3Ljg4NUw5My42OTggMjcuODc2Wk0xMTAuODAyIDE0LjAxNUMxMDkuMTk5IDE0LjAxNSAxMDYuODM2IDE0LjQ3MSAxMDUuNjExIDE2LjE1OEwxMDUuNTM3IDYuMDE1OTlIMTAwLjc2NVYzMy45MzlIMTA1LjcyVjIyLjY0MUMxMDUuNzcxIDIxLjQ2MDcgMTA2LjI4OCAyMC4zNDg4IDEwNy4xNTcgMTkuNTQ4OUMxMDguMDI3IDE4Ljc0OTEgMTA5LjE3OCAxOC4zMjY2IDExMC4zNTggMTguMzc0QzExMy4zOTcgMTguMzc0IDExNC4yNjggMjEuMTU5IDExNC4yNjggMjIuNjQxVjMzLjkzOUgxMTkuMjIzVjIxLjA1OUMxMTkuMjIzIDIxLjA1OSAxMTkuMTQyIDE0LjAxNSAxMTAuODAyIDE0LjAxNVpNMTczLjc2MyAxNC4zNThIMTY5Ljk5OVY4LjcxNDk5SDE2NS4wNDhWMTQuMzU4SDE2MS4yODRWMTguOTE2SDE2NS4wNDhWMzQuMDAzSDE2OS45OTlWMTguOTE2SDE3My43NjNWMTQuMzU4Wk0xOTAuNzg3IDI1LjI2MkMxOTAuMTI5IDI0LjUwMTQgMTg5LjMwNyAyMy44OTk0IDE4OC4zODQgMjMuNTAxQzE4Ny40ODggMjMuMTE3IDE4Ni4zMzEgMjIuNzMyIDE4NC45NDggMjIuMzY0QzE4NC4xNjUgMjIuMTQzOSAxODMuMzkgMjEuODk3OCAxODIuNjIzIDIxLjYyNkMxODIuMTYzIDIxLjQ2MjEgMTgxLjc0MSAyMS4yMDY2IDE4MS4zODMgMjAuODc1QzE4MS4yMzUgMjAuNzQyMSAxODEuMTE4IDIwLjU3ODkgMTgxLjAzOSAyMC4zOTY0QzE4MC45NjEgMjAuMjE0IDE4MC45MjIgMjAuMDE2NiAxODAuOTI3IDE5LjgxOEMxODAuOTI3IDE5LjI3MiAxODEuMTU2IDE4Ljg0NCAxODEuNjI1IDE4LjUxQzE4Mi4xMjEgMTguMTU2IDE4Mi44NjIgMTcuOTc2IDE4My44MjYgMTcuOTc2QzE4NC43OSAxNy45NzYgMTg1LjU4NyAxOC4yMDkgMTg2LjE0OCAxOC42NjhDMTg2LjcwNiAxOS4xMjQgMTg3LjAwNyAxOS43MjUgMTg3LjA3MiAyMC41TDE4Ny4wOTQgMjAuNzgySDE5MS42MzNMMTkxLjYxNyAyMC40NkMxOTEuNTIxIDE4LjQ4NSAxOTAuNzcxIDE2LjkgMTg5LjM4NSAxNS43NUMxODguMDEyIDE0LjYxMiAxODYuMTg1IDE0LjAzMyAxODMuOTYyIDE0LjAzM0MxODIuNDc3IDE0LjAzMyAxODEuMTQxIDE0LjI4NyAxNzkuOTk0IDE0Ljc4NkMxNzguODMxIDE1LjI5MSAxNzcuOTI2IDE1Ljk5NSAxNzcuMjk2IDE2Ljg4MkMxNzYuNjczIDE3Ljc0NTUgMTc2LjMzOCAxOC43ODQgMTc2LjM0MSAxOS44NDlDMTc2LjM0MSAyMS4xNjcgMTc2LjY5OCAyMi4yNDkgMTc3LjM5OSAyMy4wNjRDMTc4LjA2IDIzLjg0MzIgMTc4Ljg5OCAyNC40NTM0IDE3OS44NDIgMjQuODQ0QzE4MC43NDQgMjUuMjE2IDE4MS45MjggMjUuNjA3IDE4My4zNjEgMjZDMTg0LjgwNiAyNi40MSAxODUuODcyIDI2Ljc4NSAxODYuNTMgMjcuMTIzQzE4Ny4xIDI3LjQxNCAxODcuMzc5IDI3Ljg0NSAxODcuMzc5IDI4LjQ0NEMxODcuMzc5IDI5LjA0MiAxODcuMTIyIDI5LjQ2NyAxODYuNTk1IDI5LjgzOUMxODYuMDQzIDMwLjIyNiAxODUuMjM3IDMwLjQyNSAxODQuMjAxIDMwLjQyNUMxODMuMTY2IDMwLjQyNSAxODIuMzk0IDMwLjE3NCAxODEuNzQ5IDI5LjY3NEMxODEuMTEzIDI5LjE4MSAxODAuNzcyIDI4LjU4OSAxODAuNzEgMjcuODY0TDE4MC42ODUgMjcuNTgySDE3Ni4wMTNMMTc2LjAyNSAyNy45MDFDMTc2LjA2NyAyOS4wOTU1IDE3Ni40NzIgMzAuMjQ4NyAxNzcuMTg4IDMxLjIwNkMxNzcuOTA3IDMyLjE4IDE3OC44OTMgMzIuOTU4IDE4MC4xMTggMzMuNTE5QzE4MS4zMzYgMzQuMDc3IDE4Mi43MzIgMzQuMzYyIDE4NC4yNjYgMzQuMzYyQzE4NS44MDEgMzQuMzYyIDE4Ny4xMDkgMzQuMTA4IDE4OC4yMzggMzMuNjA5QzE4OS4zNzYgMzMuMTA0IDE5MC4yNzIgMzIuMzk0IDE5MC45MDEgMzEuNDk0QzE5MS41MzQgMzAuNTkyIDE5MS44NTMgMjkuNTU0IDE5MS44NTMgMjguNDAzQzE5MS44MjggMjcuMTEgMTkxLjQ2NiAyNi4wNTMgMTkwLjc3NyAyNS4yNjJIMTkwLjc4N1oiIGZpbGw9IiM5QjlCOUIiLz4KPHBhdGggZD0iTTI0MS45ODIgMjUuNjU4MlYxNy43MTE3SDIyOC40NDFMMjIwLjQ5NCAyNS42NTgySDI0MS45ODJaIiBmaWxsPSIjOUI5QjlCIi8+CjxwYXRoIGQ9Ik0yNTcuMjM5IDUuOTUwODFIMjQwLjI2NUwyMzIuMjU1IDEzLjg5NzNIMjU3LjIzOVY1Ljk1MDgxWiIgZmlsbD0iIzlCOUI5QiIvPgo8cGF0aCBkPSJNMjEyLjYxMSAzMy42MDQ4TDIxNi42OCAyOS41MzYxSDIzMC40MTJWMzcuNDgyN0gyMTIuNjExVjMzLjYwNDhaIiBmaWxsPSIjOUI5QjlCIi8+CjxwYXRoIGQ9Ik0yMTUuNTk5IDIxLjc4MDNIMjI0LjM3MkwyMzIuMzgyIDEzLjgzMzdIMjE1LjU5OVYyMS43ODAzWiIgZmlsbD0iIzlCOUI5QiIvPgo8cGF0aCBkPSJNMjA2IDMzLjYwNDdIMjEyLjYxMUwyMjAuNDk0IDI1LjY1ODJIMjA2VjMzLjYwNDdaIiBmaWxsPSIjOUI5QjlCIi8+CjxwYXRoIGQ9Ik0yNDAuMjY1IDUuOTUwODFMMjM2LjE5NyAxMC4wMTk0SDIxMC4yNTlWMi4wNzI4OEgyNDAuMjY1VjUuOTUwODFaIiBmaWxsPSIjOUI5QjlCIi8+Cjwvc3ZnPgo=);background-repeat:no-repeat;background-size:170px 40px}>span{padding-left:.7rem}}@keyframes ag-watermark-fadeout{0%{opacity:.5}to{opacity:0}}.ag-charts-dialog{display:flex;flex-direction:column;font-size:var(--ag-charts-chrome-font-size-large)}.ag-charts-dialog__tabs{display:flex;flex-direction:column}.ag-charts-dialog__header{border-bottom:1px solid var(--ag-charts-border-color);display:flex}.ag-charts-dialog__tab-list{display:flex;gap:calc(var(--ag-charts-spacing) * 2)}.ag-charts-dialog__drag-handle{align-items:center;color:inherit;cursor:grab;display:flex;padding:1px 6px;text-align:center}.ag-charts-dialog__drag-handle--dragging{cursor:grabbing}.ag-charts-dialog__tab-button{background:none;border:0;border-bottom:2px solid transparent;border-radius:0;color:var(--ag-charts-panel-subtle-text-color);margin-bottom:-1px;padding:var(--input-padding) calc(var(--input-padding) / 2)}.ag-charts-dialog__tab-button:hover{background:none}.ag-charts-dialog__tab-button--active{border-color:var(--ag-charts-accent-color);color:inherit}.ag-charts-dialog__drag-handle+.ag-charts-dialog__tab-button{margin-left:calc(var(--ag-charts-spacing) * -2)}.ag-charts-button.ag-charts-dialog__close-button{background:none;border:0;margin-left:auto;padding:1px 6px}.ag-charts-dialog__close-button:focus-visible{outline:var(--ag-charts-focus-border);box-shadow:var(--ag-charts-focus-border-shadow);z-index:calc(var(--ag-charts-layer-ui-overlay) + 1)}.ag-charts-dialog__tab-panel{display:none;flex-direction:column;gap:calc(var(--ag-charts-spacing) * 4);margin:0 calc(var(--ag-charts-spacing) * 4);padding:calc(var(--ag-charts-spacing) * 4) 0}.ag-charts-dialog__tab-panel--active{display:flex}.ag-charts-dialog__input-group-line{display:flex;gap:16px 18px;flex-wrap:wrap}.ag-charts-dialog__input-group{align-items:center;display:flex;font-size:var(--ag-charts-chrome-font-size)}.ag-charts-dialog__input-group-label{color:var(--ag-charts-panel-subtle-text-color);margin-right:5px}.ag-charts-dialog__input-group-label[for]{cursor:pointer}.ag-charts-dialog__button{border-radius:0;margin-right:-1px}.ag-charts-dialog__button.ag-charts-dialog__button--active{background:var(--ag-charts-button-focus-background-color);border-color:var(--ag-charts-input-focus-border-color);color:var(--ag-charts-input-focus-text-color);z-index:var(--input-layer-active)}.ag-charts-dialog__button:first-child,.ag-charts-dialog__input-group-label+.ag-charts-dialog__button{border-bottom-left-radius:var(--ag-charts-input-border-radius);border-top-left-radius:var(--ag-charts-input-border-radius)}.ag-charts-dialog__button:last-child{border-bottom-right-radius:var(--ag-charts-input-border-radius);border-top-right-radius:var(--ag-charts-input-border-radius)}.ag-charts-dialog__color-picker-button{--color: #000;background:var(--color);border:none;color:transparent;height:26px;width:26px}.ag-charts-dialog__color-picker-button:hover{background:var(--color)}.ag-charts-dialog__color-picker-button--multi-color,.ag-charts-dialog__color-picker-button--multi-color:hover{background:linear-gradient(135deg,red 0%,#ff0 calc(100% * 1 / 6),#0f0 calc(100% * 2 / 6),#0ff 50%,#00f calc(100% * 4 / 6),#f0f calc(100% * 5 / 6),red 100%)}.ag-charts-color-picker{width:190px;padding:8px;cursor:default;--h: 0;--s: 0;--v: 0;--a: 0;--color: #000;--color-a: #000;--thumb-size: 18px;--inner-width: 172px;--track-height: 12px;--palette-height: 136px;--checker: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="4" height="4"><rect x="0" y="0" width="4" height="4" fill="%23fff"/><path d="M0 0H2V4H4V2H0Z" fill="%23b2b2b2"/></svg>');--multi-color: linear-gradient( 135deg, #f00 0% , #ff0 calc(100% * 1 / 6), #0f0 calc(100% * 2 / 6), #0ff 50% , #00f calc(100% * 4 / 6), #f0f calc(100% * 5 / 6), #f00 100% )}.ag-charts-color-picker__content{display:flex;flex-direction:column}.ag-charts-color-picker__palette{position:relative;width:100%;height:var(--palette-height);margin-bottom:8px;background:linear-gradient(to bottom,#0000,#000),linear-gradient(to right,#fff,#fff0) hsl(var(--h),100%,50%);border-radius:calc(var(--ag-charts-border-radius) * 1.5);box-shadow:inset 0 0 0 1px #0003}.ag-charts-color-picker__palette:after{content:"";position:absolute;display:block;top:calc(var(--thumb-size) * -.5 + (1 - var(--v)) * 100%);left:calc(var(--thumb-size) * -.5 + var(--s) * 100%);background:var(--color);width:var(--thumb-size);height:var(--thumb-size);border-radius:calc(var(--ag-charts-border-radius) * 99);box-shadow:var(--box-shadow);--box-shadow: inset 0 0 0 3px white, inset 0 0 1px 3px #0006, 0 0 5px #00000038}.ag-charts-color-picker__palette:focus-visible:after{outline:var(--ag-charts-focus-border);box-shadow:var(--box-shadow),0 0 0 2px #fff8,var(--ag-charts-focus-border-shadow)}.ag-charts-color-picker__color-row{display:flex;gap:8px;align-items:center;margin-bottom:4px;--inset: calc((var(--thumb-size) - var(--track-height)) / 2)}.ag-charts-color-picker__hue-input,.ag-charts-color-picker__alpha-input{-webkit-appearance:none;display:block;position:relative;padding:0;margin:0 calc(var(--inset) * -1);border:0;height:var(--thumb-size);width:auto;background:transparent;--inset: calc((var(--thumb-size) - var(--track-height)) / 2)}.ag-charts-color-picker__hue-input::-moz-range-thumb,.ag-charts-color-picker__alpha-input::-moz-range-thumb{appearance:none;width:var(--thumb-size);height:var(--thumb-size);border-radius:calc(var(--ag-charts-border-radius) * 99);box-shadow:var(--box-shadow);--box-shadow: inset 0 0 0 3px white, inset 0 0 1px 3px #0006, 0 0 5px #00000038}.ag-charts-color-picker__hue-input::-webkit-slider-thumb,.ag-charts-color-picker__alpha-input::-webkit-slider-thumb{-webkit-appearance:none;width:var(--thumb-size);height:var(--thumb-size);border-radius:calc(var(--ag-charts-border-radius) * 99);box-shadow:var(--box-shadow);--box-shadow: inset 0 0 0 3px white, inset 0 0 1px 3px #0006, 0 0 5px #00000038;transform:translateZ(0)}.ag-charts-color-picker__hue-input::-moz-range-thumb{background:hsl(var(--h),100%,50%)}.ag-charts-color-picker__hue-input::-webkit-slider-thumb{background:hsl(var(--h),100%,50%)}.ag-charts-color-picker__alpha-input::-moz-range-thumb{background:transparent}.ag-charts-color-picker__alpha-input::-webkit-slider-thumb{background:transparent}.ag-charts-color-picker__alpha-input--opaque::-moz-range-thumb{background:var(--color)}.ag-charts-color-picker__alpha-input--opaque::-webkit-slider-thumb{background:var(--color)}.ag-charts-color-picker__hue-input:focus-visible::-moz-range-thumb,.ag-charts-color-picker__alpha-input:focus-visible::-moz-range-thumb{outline:var(--ag-charts-focus-border);box-shadow:var(--box-shadow),var(--ag-charts-focus-border-shadow)}.ag-charts-color-picker__hue-input:focus-visible::-webkit-slider-thumb,.ag-charts-color-picker__alpha-input:focus-visible::-webkit-slider-thumb{outline:var(--ag-charts-focus-border);box-shadow:var(--box-shadow),var(--ag-charts-focus-border-shadow)}.ag-charts-color-picker__hue-input::-moz-range-track,.ag-charts-color-picker__alpha-input::-moz-range-track{position:absolute;content:"";display:block;top:calc(50% - var(--track-height) / 2);left:var(--inset);right:var(--inset);height:var(--track-height);border-radius:calc(var(--ag-charts-border-radius) * 99);box-shadow:inset 0 0 0 1px #0003}.ag-charts-color-picker__hue-input:before,.ag-charts-color-picker__alpha-input:before{position:absolute;content:"";display:block;top:calc(50% - var(--track-height) / 2);left:var(--inset);right:var(--inset);height:var(--track-height);border-radius:calc(var(--ag-charts-border-radius) * 99);box-shadow:inset 0 0 0 1px #0003}.ag-charts-color-picker__multi-color-button{width:36px;margin-left:var(--inset);height:var(--track-height);border-radius:calc(var(--ag-charts-border-radius) * 99);border:0;background:var(--multi-color);box-shadow:inset 0 0 0 1px #0003}.ag-charts-color-picker__multi-color-button--hidden{display:none}.ag-charts-color-picker__multi-color-button--active{box-shadow:inset 0 0 0 1px #0003;outline-offset:1px;outline:2px solid #2196f3}.ag-charts-color-picker__hue-input{flex:1 0 0}.ag-charts-color-picker__hue-input::-moz-range-track{background:linear-gradient(to right,red,red calc((100% - var(--track-height)) * 0 / 6 + var(--track-height) / 2),#ff0 calc((100% - var(--track-height)) * 1 / 6 + var(--track-height) / 2),#0f0 calc((100% - var(--track-height)) * 2 / 6 + var(--track-height) / 2),#0ff calc((100% - var(--track-height)) * 3 / 6 + var(--track-height) / 2),#00f calc((100% - var(--track-height)) * 4 / 6 + var(--track-height) / 2),#f0f calc((100% - var(--track-height)) * 5 / 6 + var(--track-height) / 2),red calc((100% - var(--track-height)) * 6 / 6 + var(--track-height) / 2))}.ag-charts-color-picker__hue-input:before{background:linear-gradient(to right,red,red calc((100% - var(--track-height)) * 0 / 6 + var(--track-height) / 2),#ff0 calc((100% - var(--track-height)) * 1 / 6 + var(--track-height) / 2),#0f0 calc((100% - var(--track-height)) * 2 / 6 + var(--track-height) / 2),#0ff calc((100% - var(--track-height)) * 3 / 6 + var(--track-height) / 2),#00f calc((100% - var(--track-height)) * 4 / 6 + var(--track-height) / 2),#f0f calc((100% - var(--track-height)) * 5 / 6 + var(--track-height) / 2),red calc((100% - var(--track-height)) * 6 / 6 + var(--track-height) / 2))}.ag-charts-color-picker__alpha-input{margin-bottom:7px}.ag-charts-color-picker__alpha-input::-moz-range-track{background:linear-gradient(to right,transparent,var(--color)),var(--checker) top left / 4px 4px}.ag-charts-color-picker__alpha-input:before{background:linear-gradient(to right,transparent,var(--color)),var(--checker) top left / 4px 4px}.ag-charts-color-picker__color-field{display:flex;border:var(--ag-charts-border);background:var(--ag-charts-background-color);border-radius:var(--ag-charts-border-radius);overflow:hidden}.ag-charts-color-picker__color-field:has(:focus-visible){border-color:var(--ag-charts-accent-color);box-shadow:var(--ag-charts-focus-border-shadow)}.ag-charts-color-picker__color-label{width:16px;height:16px;margin:7px 0 7px 7px;color:transparent;background:linear-gradient(to right,var(--color-a),var(--color-a)),var(--checker) top left / 4px 4px;border-radius:calc(var(--ag-charts-border-radius) / 2);box-shadow:inset 0 0 0 1px #0003}.ag-charts-color-picker__color-label--multi-color{background:var(--multi-color)}.ag-charts-color-picker__color-input{flex:1;min-width:0;padding:7px 7px 7px 8px;border:0;margin:0;color:inherit;background:transparent;font-variant:tabular-nums}.ag-charts-color-picker__color-input:focus-visible{border:none;outline:none}.ag-charts-annotations__line-stroke-width-menu,.ag-charts-annotations__line-style-type-menu,.ag-charts-annotations__text-size-menu{border-top-left-radius:0;border-top-right-radius:0;.ag-charts-menu__row:first-child{border-radius:0}}.ag-charts-annotations__text-size-menu{--item-padding: 4px 8px;min-width:34px;text-align:center}.ag-charts-annotations__line-stroke-width-menu{--item-padding: 6px;column-gap:6px}.ag-charts-annotations__line-style-type-menu{--item-padding: 6px;column-gap:0}.ag-charts-annotations__stroke-width-button:before{background:var(--ag-charts-foreground-color);content:"";margin-right:var(--toolbar-button-padding);height:min(var(--stroke-width),20px);width:12px}.ag-charts-annotations__stroke-width-button[aria-disabled=true]:before{filter:grayscale(1);opacity:.5}.ag-charts-annotations__color-picker-button{--emblem: var(--color)}.ag-charts-annotations__color-picker-button--multi-color{--emblem: linear-gradient( to right, #f00 0% , #ff0 calc(100% * 1 / 6), #0f0 calc(100% * 2 / 6), #0ff 50% , #00f calc(100% * 4 / 6), #f0f calc(100% * 5 / 6), #f00 100% )}.ag-charts-annotations__color-picker-button:after{content:"";display:block;position:absolute;bottom:3px;left:5px;right:5px;height:4px;border-radius:99px;box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--ag-charts-foreground-color) 10%,transparent);background:var(--emblem)}.ag-charts-annotations__color-picker-button[aria-disabled=true]:after{filter:grayscale(1);opacity:.5}.ag-charts-annotations__toolbar-menu{min-width:200px}.ag-charts-annotations__axis-button--hidden{display:none}.ag-charts-annotations__axis-button{background-color:var(--ag-charts-crosshair-label-background-color);border-radius:calc(var(--ag-charts-border-radius) / 2);border:none;box-sizing:border-box;color:var(--ag-charts-crosshair-label-text-color);cursor:pointer;font-family:var(--ag-charts-button-font-family);font-size:var(--ag-charts-button-font-size);font-weight:var(--ag-charts-button-font-weight);left:0;line-height:16px;overflow:hidden;padding:0;position:absolute;top:0;user-select:none;white-space:nowrap;z-index:var(--ag-charts-layer-annotations)}.ag-charts-annotations__axis-button:hover{opacity:.8;color:var(--ag-charts-background-color)}.ag-charts-dialog--annotation-settings{min-height:233px;width:289px}.ag-charts-dialog--annotation-settings .ag-charts-textarea{height:calc(10px * 2 + var(--textarea-line-height) * 1em * 3 + 2px);overflow-y:auto;resize:vertical}.ag-charts-context-menu{font-family:var(--ag-charts-chrome-font-family);font-size:var(--ag-charts-chrome-font-size);font-weight:var(--ag-charts-chrome-font-weight);z-index:var(--ag-charts-layer-ui-overlay)}.ag-charts-context-menu__cover{position:fixed;left:0;top:0}.ag-charts-context-menu__menu{background:var(--ag-charts-menu-background-color);border-radius:var(--ag-charts-border-radius);border:var(--ag-charts-menu-border);box-shadow:var(--ag-charts-popup-shadow);color:var(--ag-charts-menu-text-color);display:flex;flex-direction:column;padding:.5em 0;transition:transform .1s ease;white-space:nowrap}.ag-charts-context-menu__menu:focus{outline:none}.ag-charts-context-menu__item{align-items:center;background:none;border:none;box-sizing:border-box;color:inherit;cursor:pointer;display:flex;font:inherit;justify-content:space-between;text-align:left;width:100%;-webkit-appearance:none;-moz-appearance:none}.ag-charts-context-menu__icon>img{width:var(--ag-charts-icon-size);height:var(--ag-charts-icon-size)}.ag-charts-context-menu__icon,.ag-charts-context-menu__cell{display:flex;align-items:center;flex-shrink:0}.ag-charts-context-menu__cell{flex-grow:1}.ag-charts-context-menu__cellpadding{padding:.5em 1em}.ag-charts-context-menu__icon{padding-right:0}.ag-charts-context-menu__item[data-focus-override=true],.ag-charts-context-menu__item:focus,.ag-charts-context-menu__item:active{background:var(--ag-charts-focus-color)}.ag-charts-context-menu__item[data-focus-override=false]{background:inherit}.ag-charts-context-menu__item[data-focus-visible-override=true]:focus,.ag-charts-context-menu__item:focus-visible{outline:var(--ag-charts-focus-border);box-shadow:var(--ag-charts-focus-border-shadow);z-index:calc(var(--ag-charts-layer-ui-overlay) + 1)}.ag-charts-context-menu__item[data-focus-visible-override=false]{outline:inherit;box-shadow:inherit;z-index:inherit}.ag-charts-context-menu__item[aria-disabled=true]{border:none;color:color-mix(in srgb,var(--ag-charts-input-text-color) 50%,transparent)}.ag-charts-context-menu__item[aria-disabled=true]:focus{background:inherit;cursor:inherit}.ag-charts-context-menu__divider{padding:5px 0}.ag-charts-context-menu__divider:after{content:"";display:block;border-top:1px solid var(--ag-charts-border-color)}.ag-charts-crosshair-label{position:absolute;left:0;top:0;user-select:none;pointer-events:none;font-family:var(--ag-charts-font-family);font-size:var(--ag-charts-font-size);font-weight:var(--ag-charts-font-weight);overflow:hidden;white-space:nowrap;z-index:var(--ag-charts-layer-crosshair);box-sizing:border-box}.ag-charts-crosshair-label-content{padding:0 8px;border-radius:calc(var(--ag-charts-border-radius) / 2);line-height:calc(var(--ag-charts-font-size) + 8px);background-color:var(--ag-charts-crosshair-label-background-color);color:var(--ag-charts-crosshair-label-text-color)}.ag-charts-crosshair-label--hidden{visibility:hidden!important}.ag-charts-text-input{position:absolute}.ag-charts-text-input__textarea{--placeholder-text-color: var(--ag-charts-input-placeholder-text-color);display:block;height:100%;width:100%;border:0;background:none;line-height:1.38;outline:none;transform:translateY(.09em)}.ag-charts-text-input__textarea[placeholder]:empty:before{content:attr(placeholder);color:var(--placeholder-text-color);font-weight:400}.ag-charts-text-input__textarea[placeholder]:not(:empty):before{content:""}.ag-charts-chart-toolbar__menu{min-width:200px}.ag-charts-range-buttons .ag-charts-toolbar__button{padding:var(--toolbar-button-padding) calc(var(--toolbar-button-padding) * 1.5)}.ag-charts-zoom-buttons{align-items:center;display:flex;height:44px;justify-content:center;overflow:hidden;padding-bottom:10px;pointer-events:none;width:100%;.ag-charts-toolbar{--toolbar-size: 24px;--toolbar-button-padding: 1px;display:flex;font-size:var(--ag-charts-chrome-font-size);height:var(--toolbar-size);justify-content:center;opacity:1;pointer-events:auto;transition:opacity .2s ease-in-out,transform .4s ease-in-out;.ag-charts-toolbar__button--first{border-bottom-left-radius:var(--ag-charts-border-radius);border-top-left-radius:var(--ag-charts-border-radius)}.ag-charts-toolbar__button--last{border-bottom-right-radius:var(--ag-charts-border-radius);border-top-right-radius:var(--ag-charts-border-radius)}.ag-charts-toolbar__label{padding-left:var(--ag-charts-spacing);padding-right:var(--ag-charts-spacing)}.ag-charts-toolbar__icon+.ag-charts-toolbar__label{padding-left:0}.ag-charts-toolbar__button--gap{margin-left:var(--toolbar-gap)}&.ag-charts-zoom-buttons__toolbar--hidden{opacity:0;transition:opacity .4s ease-in-out,transform .4s ease-in-out}}}.ag-charts-shared-toolbar{gap:var(--toolbar-gap);.ag-charts-toolbar__button{border-radius:var(--ag-charts-border-radius);margin:0}.ag-charts-toolbar__button--active+.ag-charts-toolbar__button{border-left-color:var(--ag-charts-border-color)}}
|
|
`;
|
|
|
|
// 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/chart/tooltipOptions.ts
|
|
var AgTooltipAnchorToType = /* @__PURE__ */ ((AgTooltipAnchorToType2) => {
|
|
AgTooltipAnchorToType2["POINTER"] = "pointer";
|
|
AgTooltipAnchorToType2["NODE"] = "node";
|
|
AgTooltipAnchorToType2["CHART"] = "chart";
|
|
return AgTooltipAnchorToType2;
|
|
})(AgTooltipAnchorToType || {});
|
|
var AgTooltipPlacementType = /* @__PURE__ */ ((AgTooltipPlacementType2) => {
|
|
AgTooltipPlacementType2["TOP"] = "top";
|
|
AgTooltipPlacementType2["RIGHT"] = "right";
|
|
AgTooltipPlacementType2["BOTTOM"] = "bottom";
|
|
AgTooltipPlacementType2["LEFT"] = "left";
|
|
AgTooltipPlacementType2["TOP_RIGHT"] = "top-right";
|
|
AgTooltipPlacementType2["BOTTOM_RIGHT"] = "bottom-right";
|
|
AgTooltipPlacementType2["BOTTOM_LEFT"] = "bottom-left";
|
|
AgTooltipPlacementType2["TOP_LEFT"] = "top-left";
|
|
AgTooltipPlacementType2["CENTER"] = "center";
|
|
return AgTooltipPlacementType2;
|
|
})(AgTooltipPlacementType || {});
|
|
|
|
// 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-enterprise/src/main.ts
|
|
export * from "ag-charts-community";
|
|
|
|
// packages/ag-charts-enterprise/src/axes/angle-category/angleCategoryAxisModule.ts
|
|
import { VERSION, _ModuleSupport as _ModuleSupport9 } from "ag-charts-community";
|
|
|
|
// packages/ag-charts-enterprise/src/axes/angle-category/angleCategoryAxis.ts
|
|
import { _ModuleSupport as _ModuleSupport8 } from "ag-charts-community";
|
|
import { Property as Property7, isNumberEqual as isNumberEqual3 } from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/utils/polar.ts
|
|
function walkPairsOutward(items, step, visitPair) {
|
|
const middleIndex = Math.floor(items.length / 2);
|
|
return walkPairsByStep(items, step, middleIndex, step, visitPair) || walkPairsByStep(items, items.length - step, middleIndex, -step, visitPair);
|
|
}
|
|
function walkPairsByStep(items, startIndex, endIndex, step, visitPair) {
|
|
let previous = items[0];
|
|
for (let i = startIndex; step > 0 ? i <= endIndex : i > endIndex; i += step) {
|
|
const current = items[i];
|
|
if (visitPair(previous, current)) {
|
|
return true;
|
|
}
|
|
previous = current;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// packages/ag-charts-enterprise/src/axes/angle-number/angleAxisInterval.ts
|
|
import { _ModuleSupport as _ModuleSupport4 } from "ag-charts-community";
|
|
import { Property as Property4 } from "ag-charts-core";
|
|
var { AxisInterval } = _ModuleSupport4;
|
|
var AngleAxisInterval = class extends AxisInterval {
|
|
};
|
|
__decorateClass([
|
|
Property4
|
|
], AngleAxisInterval.prototype, "minSpacing", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/axes/angle/angleAxis.ts
|
|
import { _ModuleSupport as _ModuleSupport7 } from "ag-charts-community";
|
|
import {
|
|
ChartAxisDirection as ChartAxisDirection3,
|
|
Property as Property6,
|
|
countFractionDigits,
|
|
isNumberEqual as isNumberEqual2,
|
|
normalizeAngle360 as normalizeAngle3602,
|
|
normalizeAngle360Inclusive,
|
|
toRadians,
|
|
wrapTextOrSegments
|
|
} from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/axes/polar-crosslines/angleCrossLine.ts
|
|
import { _ModuleSupport as _ModuleSupport6 } from "ag-charts-community";
|
|
import { ChartAxisDirection as ChartAxisDirection2, isNumberEqual, normalizeAngle360 } from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/axes/polar-crosslines/polarCrossLine.ts
|
|
import { _ModuleSupport as _ModuleSupport5 } from "ag-charts-community";
|
|
import { BaseProperties as BaseProperties2, ChartAxisDirection, Property as Property5, createId } from "ag-charts-core";
|
|
var { Group, LabelStyle } = _ModuleSupport5;
|
|
var PolarCrossLineLabel = class extends LabelStyle {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.padding = 5;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property5
|
|
], PolarCrossLineLabel.prototype, "enabled", 2);
|
|
__decorateClass([
|
|
Property5
|
|
], PolarCrossLineLabel.prototype, "padding", 2);
|
|
__decorateClass([
|
|
Property5
|
|
], PolarCrossLineLabel.prototype, "text", 2);
|
|
__decorateClass([
|
|
Property5
|
|
], PolarCrossLineLabel.prototype, "parallel", 2);
|
|
var PolarCrossLine = class extends BaseProperties2 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.id = createId(this);
|
|
this.defaultColorRange = [];
|
|
this.shape = "polygon";
|
|
this.label = new PolarCrossLineLabel();
|
|
this.scale = void 0;
|
|
this.clippedRange = [-Infinity, Infinity];
|
|
this.gridLength = 0;
|
|
this.sideFlag = -1;
|
|
this.parallelFlipRotation = 0;
|
|
this.regularFlipRotation = 0;
|
|
this.direction = ChartAxisDirection.Angle;
|
|
this.axisInnerRadius = 0;
|
|
this.axisOuterRadius = 0;
|
|
this.lineGroup = new Group({ name: this.id });
|
|
this.rangeGroup = new Group({ name: this.id });
|
|
this.labelGroup = new Group({ name: this.id });
|
|
this._isRange = void 0;
|
|
}
|
|
assignCrossLineGroup(isRange, crossLineRange) {
|
|
if (isRange !== this._isRange) {
|
|
if (isRange) {
|
|
this.rangeGroup.appendChild(crossLineRange);
|
|
} else {
|
|
this.lineGroup.appendChild(crossLineRange);
|
|
}
|
|
}
|
|
this._isRange = isRange;
|
|
}
|
|
setSectorNodeProps(node) {
|
|
node.fill = this.fill;
|
|
node.fillOpacity = this.fillOpacity ?? 1;
|
|
node.stroke = this.stroke;
|
|
node.strokeOpacity = this.strokeOpacity ?? 1;
|
|
node.strokeWidth = this.strokeWidth ?? 1;
|
|
node.lineDash = this.lineDash;
|
|
}
|
|
setLabelNodeProps(node, x, y, baseline, rotation) {
|
|
const { label } = this;
|
|
node.x = x;
|
|
node.y = y;
|
|
node.text = label.text;
|
|
node.textAlign = "center";
|
|
node.textBaseline = baseline;
|
|
node.rotation = rotation;
|
|
node.rotationCenterX = x;
|
|
node.rotationCenterY = y;
|
|
node.fill = label.color;
|
|
node.setFont(label);
|
|
node.setBoxing(label);
|
|
node.visible = true;
|
|
}
|
|
};
|
|
PolarCrossLine.className = "PolarCrossLine";
|
|
__decorateClass([
|
|
Property5
|
|
], PolarCrossLine.prototype, "enabled", 2);
|
|
__decorateClass([
|
|
Property5
|
|
], PolarCrossLine.prototype, "type", 2);
|
|
__decorateClass([
|
|
Property5
|
|
], PolarCrossLine.prototype, "range", 2);
|
|
__decorateClass([
|
|
Property5
|
|
], PolarCrossLine.prototype, "value", 2);
|
|
__decorateClass([
|
|
Property5
|
|
], PolarCrossLine.prototype, "defaultColorRange", 2);
|
|
__decorateClass([
|
|
Property5
|
|
], PolarCrossLine.prototype, "fill", 2);
|
|
__decorateClass([
|
|
Property5
|
|
], PolarCrossLine.prototype, "fillOpacity", 2);
|
|
__decorateClass([
|
|
Property5
|
|
], PolarCrossLine.prototype, "stroke", 2);
|
|
__decorateClass([
|
|
Property5
|
|
], PolarCrossLine.prototype, "strokeWidth", 2);
|
|
__decorateClass([
|
|
Property5
|
|
], PolarCrossLine.prototype, "strokeOpacity", 2);
|
|
__decorateClass([
|
|
Property5
|
|
], PolarCrossLine.prototype, "lineDash", 2);
|
|
__decorateClass([
|
|
Property5
|
|
], PolarCrossLine.prototype, "shape", 2);
|
|
__decorateClass([
|
|
Property5
|
|
], PolarCrossLine.prototype, "label", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/axes/polar-crosslines/angleCrossLine.ts
|
|
var { getCrossLineValue, validateCrossLineValue, Group: Group2, Path, Sector, RotatableText, ContinuousScale } = _ModuleSupport6;
|
|
var AngleCrossLine = class extends PolarCrossLine {
|
|
constructor() {
|
|
super();
|
|
this.direction = ChartAxisDirection2.Angle;
|
|
this.polygonNode = new Path();
|
|
this.sectorNode = new Sector();
|
|
this.lineNode = new Path();
|
|
this.crossLineRange = new Group2();
|
|
this.labelNode = new RotatableText();
|
|
this.ticks = [];
|
|
this.crossLineRange.append(this.polygonNode);
|
|
this.crossLineRange.append(this.sectorNode);
|
|
this.crossLineRange.append(this.lineNode);
|
|
this.labelGroup.append(this.labelNode);
|
|
}
|
|
visibilityCheck() {
|
|
if (!ContinuousScale.is(this.scale)) {
|
|
return true;
|
|
}
|
|
const [d0, d1] = this.scale.domain;
|
|
const value = getCrossLineValue(this);
|
|
if (this.type === "range") {
|
|
const [start, end] = value;
|
|
return start >= d0 && start <= d1 && end >= start && end <= d1;
|
|
} else {
|
|
return value >= d0 && value <= d1;
|
|
}
|
|
}
|
|
update(visible) {
|
|
const { scale } = this;
|
|
if (!scale || !validateCrossLineValue(this, scale) || !this.visibilityCheck()) {
|
|
this.rangeGroup.visible = false;
|
|
this.lineGroup.visible = false;
|
|
this.labelGroup.visible = false;
|
|
return;
|
|
}
|
|
this.rangeGroup.visible = visible;
|
|
this.lineGroup.visible = visible;
|
|
this.labelGroup.visible = visible;
|
|
this.updateLineNode(visible);
|
|
this.updatePolygonNode(visible);
|
|
this.updateSectorNode(visible);
|
|
this.updateLabelNode(visible);
|
|
}
|
|
updateLineNode(visible) {
|
|
const { scale, type, value, lineNode: line } = this;
|
|
if (!visible || type !== "line" || !scale) {
|
|
line.visible = false;
|
|
return;
|
|
}
|
|
const angle = scale.convert(value);
|
|
if (Number.isNaN(angle)) {
|
|
line.visible = false;
|
|
return;
|
|
}
|
|
const { axisInnerRadius, axisOuterRadius } = this;
|
|
line.visible = true;
|
|
line.stroke = this.stroke;
|
|
line.strokeOpacity = this.strokeOpacity ?? 1;
|
|
line.strokeWidth = this.strokeWidth ?? 1;
|
|
line.fill = void 0;
|
|
line.lineDash = this.lineDash;
|
|
const x = axisOuterRadius * Math.cos(angle);
|
|
const y = axisOuterRadius * Math.sin(angle);
|
|
const x0 = axisInnerRadius * Math.cos(angle);
|
|
const y0 = axisInnerRadius * Math.sin(angle);
|
|
line.path.clear(true);
|
|
line.path.moveTo(x0, y0);
|
|
line.path.lineTo(x, y);
|
|
this.assignCrossLineGroup(false, this.crossLineRange);
|
|
}
|
|
updatePolygonNode(visible) {
|
|
const { polygonNode: polygon, range: range2, scale, shape, type, ticks } = this;
|
|
if (!visible || type !== "range" || shape !== "polygon" || !scale || !range2) {
|
|
polygon.visible = false;
|
|
return;
|
|
}
|
|
const { axisInnerRadius, axisOuterRadius } = this;
|
|
const startIndex = ticks.indexOf(range2[0]);
|
|
const endIndex = ticks.indexOf(range2[1]);
|
|
const stops = startIndex <= endIndex ? ticks.slice(startIndex, endIndex + 1) : ticks.slice(startIndex).concat(ticks.slice(0, endIndex + 1));
|
|
const angles = stops.map((value) => scale.convert(value));
|
|
polygon.visible = true;
|
|
this.setSectorNodeProps(polygon);
|
|
const { path } = polygon;
|
|
path.clear(true);
|
|
for (const [index, angle] of angles.entries()) {
|
|
const x = axisOuterRadius * Math.cos(angle);
|
|
const y = axisOuterRadius * Math.sin(angle);
|
|
if (index === 0) {
|
|
path.moveTo(x, y);
|
|
} else {
|
|
path.lineTo(x, y);
|
|
}
|
|
}
|
|
if (axisInnerRadius === 0) {
|
|
path.lineTo(0, 0);
|
|
} else {
|
|
const reversedAngles = angles.slice().reverse();
|
|
for (const angle of reversedAngles) {
|
|
const x = axisInnerRadius * Math.cos(angle);
|
|
const y = axisInnerRadius * Math.sin(angle);
|
|
path.lineTo(x, y);
|
|
}
|
|
}
|
|
polygon.path.closePath();
|
|
this.assignCrossLineGroup(true, this.crossLineRange);
|
|
}
|
|
updateSectorNode(visible) {
|
|
const { sectorNode: sector, range: range2, scale, shape, type } = this;
|
|
if (!visible || type !== "range" || shape !== "circle" || !scale || !range2) {
|
|
sector.visible = false;
|
|
return;
|
|
}
|
|
const { axisInnerRadius, axisOuterRadius } = this;
|
|
const angles = range2.map((value) => scale.convert(value));
|
|
const step = scale.step ?? 0;
|
|
const padding2 = scale instanceof _ModuleSupport6.BandScale ? step / 2 : 0;
|
|
sector.visible = true;
|
|
this.setSectorNodeProps(sector);
|
|
sector.centerX = 0;
|
|
sector.centerY = 0;
|
|
sector.innerRadius = axisInnerRadius;
|
|
sector.outerRadius = axisOuterRadius;
|
|
sector.startAngle = angles[0] - padding2;
|
|
sector.endAngle = angles[1] + padding2;
|
|
this.assignCrossLineGroup(true, this.crossLineRange);
|
|
}
|
|
updateLabelNode(visible) {
|
|
const { label, labelNode: node, range: range2, scale, type, ticks } = this;
|
|
if (!visible || label.enabled === false || !label.text || !scale || type === "range" && !range2) {
|
|
node.visible = false;
|
|
return;
|
|
}
|
|
node.visible = true;
|
|
const { axisInnerRadius, axisOuterRadius } = this;
|
|
let labelX;
|
|
let labelY;
|
|
let rotation;
|
|
let textBaseline;
|
|
if (type === "line") {
|
|
const angle = normalizeAngle360(scale.convert(this.value));
|
|
const angle270 = 1.5 * Math.PI;
|
|
const isRightSide = isNumberEqual(angle, angle270) || angle > angle270 || angle < Math.PI / 2;
|
|
const midX = (axisInnerRadius + axisOuterRadius) / 2 * Math.cos(angle);
|
|
const midY = (axisInnerRadius + axisOuterRadius) / 2 * Math.sin(angle);
|
|
labelX = midX + label.padding * Math.cos(angle + Math.PI / 2);
|
|
labelY = midY + label.padding * Math.sin(angle + Math.PI / 2);
|
|
textBaseline = isRightSide ? "top" : "bottom";
|
|
rotation = isRightSide ? angle : angle - Math.PI;
|
|
} else {
|
|
const [startAngle, endAngle] = range2.map((value) => normalizeAngle360(scale.convert(value)));
|
|
let angle = (startAngle + endAngle) / 2;
|
|
if (startAngle > endAngle) {
|
|
angle -= Math.PI;
|
|
}
|
|
angle = normalizeAngle360(angle);
|
|
const isBottomSide = (isNumberEqual(angle, 0) || angle > 0) && angle < Math.PI;
|
|
let distance;
|
|
if (this.shape === "circle" || ticks.length < 3) {
|
|
distance = axisOuterRadius - label.padding;
|
|
} else {
|
|
distance = axisOuterRadius * Math.cos(Math.PI / ticks.length) - label.padding;
|
|
}
|
|
labelX = distance * Math.cos(angle);
|
|
labelY = distance * Math.sin(angle);
|
|
textBaseline = isBottomSide ? "bottom" : "top";
|
|
rotation = isBottomSide ? angle - Math.PI / 2 : angle + Math.PI / 2;
|
|
}
|
|
this.setLabelNodeProps(node, labelX, labelY, textBaseline, rotation);
|
|
}
|
|
};
|
|
AngleCrossLine.className = "AngleCrossLine";
|
|
|
|
// packages/ag-charts-enterprise/src/axes/angle/angleAxis.ts
|
|
var { Path: Path2, RotatableText: RotatableText2, Transformable, BBox, Selection, Line } = _ModuleSupport7;
|
|
var AngleAxisLabel = class extends _ModuleSupport7.AxisLabel {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.orientation = "fixed";
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property6
|
|
], AngleAxisLabel.prototype, "orientation", 2);
|
|
var AngleAxis = class extends _ModuleSupport7.PolarAxis {
|
|
constructor(moduleCtx, scale) {
|
|
super(moduleCtx, scale);
|
|
this.startAngle = 0;
|
|
this.endAngle = void 0;
|
|
this.tickLineGroupSelection = Selection.select(
|
|
this.tickLineGroup,
|
|
Line,
|
|
false
|
|
);
|
|
this.gridLineGroupSelection = Selection.select(
|
|
this.gridLineGroup,
|
|
Line,
|
|
false
|
|
);
|
|
this.labelData = [];
|
|
this.tickData = [];
|
|
this.radiusLineGroup = this.axisGroup.appendChild(new _ModuleSupport7.TransformableGroup());
|
|
this.radiusLine = this.radiusLineGroup.appendChild(new Path2());
|
|
this.includeInvisibleDomains = true;
|
|
}
|
|
get direction() {
|
|
return ChartAxisDirection3.Angle;
|
|
}
|
|
createLabel() {
|
|
return new AngleAxisLabel();
|
|
}
|
|
calculateRotations() {
|
|
const rotation = toRadians(this.startAngle);
|
|
const parallelFlipRotation = normalizeAngle3602(rotation);
|
|
const regularFlipRotation = normalizeAngle3602(rotation - Math.PI / 2);
|
|
return { rotation, parallelFlipRotation, regularFlipRotation };
|
|
}
|
|
calculateTickLayout(domain) {
|
|
const { nice, scale } = this;
|
|
const ticksParams = {
|
|
nice: [nice, nice],
|
|
interval: void 0,
|
|
tickCount: void 0,
|
|
minTickCount: 0,
|
|
maxTickCount: Infinity
|
|
};
|
|
const niceDomain = nice ? scale.niceDomain(ticksParams, domain) : domain;
|
|
const tickData = this.generateAngleTicks(niceDomain);
|
|
this.tickData = tickData;
|
|
const ticks = tickData.map((t) => t.value);
|
|
const fractionDigits = ticks.reduce(
|
|
(f, t) => Math.max(typeof t === "number" ? countFractionDigits(t) : 0, f),
|
|
0
|
|
);
|
|
return {
|
|
niceDomain,
|
|
tickDomain: niceDomain,
|
|
ticks,
|
|
rawTickCount: void 0,
|
|
fractionDigits,
|
|
timeInterval: void 0,
|
|
bbox: this.getBBox()
|
|
};
|
|
}
|
|
update() {
|
|
super.update();
|
|
this.updateRadiusLine();
|
|
this.updateGridLines();
|
|
this.updateTickLines();
|
|
}
|
|
normalizedAngles() {
|
|
const startAngle = normalizeAngle3602(-Math.PI / 2 + toRadians(this.startAngle));
|
|
const sweep = this.endAngle == null ? 2 * Math.PI : normalizeAngle360Inclusive(toRadians(this.endAngle) - toRadians(this.startAngle));
|
|
const endAngle = startAngle + sweep;
|
|
return [startAngle, endAngle];
|
|
}
|
|
computeRange() {
|
|
this.range = this.normalizedAngles();
|
|
}
|
|
updateSelections() {
|
|
const data = this.tickData;
|
|
this.gridLineGroupSelection.update(this.gridLength && this.gridLine.enabled ? data : []);
|
|
this.tickLineGroupSelection.update(this.tick.enabled ? data : []);
|
|
this.tickLabelGroupSelection.update(this.label.enabled ? data : []);
|
|
this.gridLineGroupSelection.cleanup();
|
|
this.tickLineGroupSelection.cleanup();
|
|
this.tickLabelGroupSelection.cleanup();
|
|
}
|
|
updatePosition() {
|
|
super.updatePosition();
|
|
const { translation, radiusLineGroup } = this;
|
|
const translationX = Math.floor(translation.x);
|
|
const translationY = Math.floor(translation.y);
|
|
radiusLineGroup.translationX = translationX;
|
|
radiusLineGroup.translationY = translationY;
|
|
}
|
|
updateRadiusLine() {
|
|
const node = this.radiusLine;
|
|
const { path } = node;
|
|
path.clear(true);
|
|
const { points, closePath } = this.getAxisLinePoints();
|
|
for (const { x, y, moveTo: moveTo2, arc, radius = 0, startAngle = 0, endAngle = 0 } of points) {
|
|
if (arc) {
|
|
path.arc(x, y, radius, startAngle, endAngle);
|
|
} else if (moveTo2) {
|
|
path.moveTo(x, y);
|
|
} else {
|
|
path.lineTo(x, y);
|
|
}
|
|
}
|
|
if (closePath) {
|
|
path.closePath();
|
|
}
|
|
node.visible = this.line.enabled;
|
|
node.stroke = this.line.stroke;
|
|
node.strokeWidth = this.line.width;
|
|
node.fill = void 0;
|
|
}
|
|
getAxisLinePoints() {
|
|
const { scale, shape, gridLength: radius } = this;
|
|
const [startAngle, endAngle] = this.range;
|
|
const isFullCircle = isNumberEqual2(endAngle - startAngle, 2 * Math.PI);
|
|
const points = [];
|
|
if (shape === "circle") {
|
|
if (isFullCircle) {
|
|
points.push(
|
|
{ x: radius, y: 0, moveTo: true },
|
|
{
|
|
x: 0,
|
|
y: 0,
|
|
radius,
|
|
startAngle: 0,
|
|
endAngle: 2 * Math.PI,
|
|
arc: true,
|
|
moveTo: false
|
|
}
|
|
);
|
|
} else {
|
|
points.push(
|
|
{
|
|
x: radius * Math.cos(startAngle),
|
|
y: radius * Math.sin(startAngle),
|
|
moveTo: true
|
|
},
|
|
{
|
|
x: 0,
|
|
y: 0,
|
|
radius,
|
|
startAngle: normalizeAngle3602(startAngle),
|
|
endAngle: normalizeAngle3602(endAngle),
|
|
arc: true,
|
|
moveTo: false
|
|
}
|
|
);
|
|
}
|
|
} else if (shape === "polygon") {
|
|
const angles = scale.ticks({
|
|
nice: [this.nice, this.nice],
|
|
interval: void 0,
|
|
tickCount: void 0,
|
|
minTickCount: 0,
|
|
maxTickCount: Infinity
|
|
})?.ticks?.map((value) => scale.convert(value));
|
|
if (angles && angles.length > 2) {
|
|
for (const [i, angle] of angles.entries()) {
|
|
const x = radius * Math.cos(angle);
|
|
const y = radius * Math.sin(angle);
|
|
const moveTo2 = i === 0;
|
|
points.push({ x, y, moveTo: moveTo2 });
|
|
}
|
|
}
|
|
}
|
|
return { points, closePath: isFullCircle };
|
|
}
|
|
updateGridLines() {
|
|
const {
|
|
scale,
|
|
gridLength: radius,
|
|
gridLine: { style, width },
|
|
innerRadiusRatio
|
|
} = this;
|
|
if (!(style && radius > 0)) {
|
|
return;
|
|
}
|
|
const innerRadius = radius * innerRadiusRatio;
|
|
const styleCount = style.length;
|
|
this.gridLineGroupSelection.each((line, datum, index) => {
|
|
const { value } = datum;
|
|
const { stroke: stroke3, lineDash } = style[index % styleCount];
|
|
const angle = scale.convert(value);
|
|
line.x1 = innerRadius * Math.cos(angle);
|
|
line.y1 = innerRadius * Math.sin(angle);
|
|
line.x2 = radius * Math.cos(angle);
|
|
line.y2 = radius * Math.sin(angle);
|
|
line.stroke = stroke3;
|
|
line.strokeWidth = width;
|
|
line.lineDash = lineDash;
|
|
line.fill = void 0;
|
|
});
|
|
this.gridLineGroupSelection.cleanup();
|
|
}
|
|
updateLabels() {
|
|
const { label, tickLabelGroupSelection } = this;
|
|
tickLabelGroupSelection.each((node, _, index) => {
|
|
const labelDatum = this.labelData[index];
|
|
if (!labelDatum || labelDatum.hidden) {
|
|
node.visible = false;
|
|
return;
|
|
}
|
|
node.text = labelDatum.text;
|
|
node.setFont(label);
|
|
node.fill = label.color;
|
|
node.x = labelDatum.x;
|
|
node.y = labelDatum.y;
|
|
node.setAlign(labelDatum);
|
|
node.setBoxing(label);
|
|
node.visible = true;
|
|
if (labelDatum.rotation) {
|
|
node.rotation = labelDatum.rotation;
|
|
node.rotationCenterX = labelDatum.x;
|
|
node.rotationCenterY = labelDatum.y;
|
|
} else {
|
|
node.rotation = 0;
|
|
}
|
|
});
|
|
}
|
|
updateTickLines() {
|
|
const { scale, gridLength: radius, tick, tickLineGroupSelection } = this;
|
|
tickLineGroupSelection.each((line, datum) => {
|
|
const { value } = datum;
|
|
const angle = scale.convert(value);
|
|
const cos = Math.cos(angle);
|
|
const sin = Math.sin(angle);
|
|
line.x1 = radius * cos;
|
|
line.y1 = radius * sin;
|
|
line.x2 = (radius + tick.size) * cos;
|
|
line.y2 = (radius + tick.size) * sin;
|
|
line.stroke = tick.stroke;
|
|
line.strokeWidth = tick.width;
|
|
});
|
|
}
|
|
createLabelNodeData(ticks, options, seriesRect) {
|
|
const { label, gridLength: radius, scale, tick } = this;
|
|
if (!label.enabled) {
|
|
return [];
|
|
}
|
|
const tempText = new RotatableText2();
|
|
const seriesLeft = seriesRect.x - this.translation.x;
|
|
const seriesRight = seriesRect.x + seriesRect.width - this.translation.x;
|
|
const { fractionDigits } = this.layout.label;
|
|
const axisTickFormatter = this.tickFormatter(this.scale.domain, this.tickData, false, fractionDigits);
|
|
const labelData = ticks.map((datum, index) => {
|
|
const { value } = datum;
|
|
const distance = radius + label.spacing + tick.size;
|
|
const angle = scale.convert(value);
|
|
const cos = Math.cos(angle);
|
|
const sin = Math.sin(angle);
|
|
const x = distance * cos;
|
|
const y = distance * sin;
|
|
const { textAlign, textBaseline } = this.getLabelAlign(angle);
|
|
const isLastTickOverFirst = index === ticks.length - 1 && value !== ticks[0] && isNumberEqual2(normalizeAngle3602(angle), normalizeAngle3602(scale.convert(ticks[0])));
|
|
const rotation = this.getLabelRotation(angle);
|
|
let text2 = axisTickFormatter(value, index);
|
|
tempText.text = text2;
|
|
tempText.x = x;
|
|
tempText.y = y;
|
|
tempText.setFont(label);
|
|
tempText.textAlign = textAlign;
|
|
tempText.textBaseline = textBaseline;
|
|
tempText.rotation = rotation;
|
|
if (rotation) {
|
|
tempText.rotationCenterX = x;
|
|
tempText.rotationCenterY = y;
|
|
}
|
|
let box = rotation ? Transformable.toCanvas(tempText) : tempText.getBBox();
|
|
if (box && options.hideWhenNecessary && !rotation) {
|
|
const overflowLeft = seriesLeft - box.x;
|
|
const overflowRight = box.x + box.width - seriesRight;
|
|
const pixelError = 1;
|
|
if (overflowLeft > pixelError || overflowRight > pixelError) {
|
|
const availWidth = box.width - Math.max(overflowLeft, overflowRight);
|
|
const wrapOptions = { maxWidth: availWidth, font: label, textWrap: "never" };
|
|
text2 = wrapTextOrSegments(text2, wrapOptions);
|
|
tempText.text = text2;
|
|
box = tempText.getBBox();
|
|
}
|
|
}
|
|
return {
|
|
text: text2,
|
|
x,
|
|
y,
|
|
textAlign,
|
|
textBaseline,
|
|
hidden: text2 === "" || (datum.hidden ?? isLastTickOverFirst),
|
|
rotation,
|
|
box
|
|
};
|
|
});
|
|
if (label.avoidCollisions) {
|
|
this.avoidLabelCollisions(labelData);
|
|
}
|
|
return labelData;
|
|
}
|
|
computeLabelsBBox(options, seriesRect) {
|
|
this.labelData = this.createLabelNodeData(this.tickData, options, seriesRect);
|
|
const textBoxes = this.labelData.map(({ box }) => box).filter((box) => box != null);
|
|
if (!this.label.enabled || textBoxes.length === 0) {
|
|
return null;
|
|
}
|
|
return BBox.merge(textBoxes);
|
|
}
|
|
getLabelOrientation() {
|
|
const { label } = this;
|
|
return label instanceof AngleAxisLabel ? label.orientation : "fixed";
|
|
}
|
|
getLabelRotation(tickAngle) {
|
|
let rotation = toRadians(this.label.rotation ?? 0);
|
|
tickAngle = normalizeAngle3602(tickAngle);
|
|
const orientation = this.getLabelOrientation();
|
|
if (orientation === "parallel") {
|
|
rotation += tickAngle;
|
|
if (tickAngle >= 0 && tickAngle < Math.PI) {
|
|
rotation -= Math.PI / 2;
|
|
} else {
|
|
rotation += Math.PI / 2;
|
|
}
|
|
} else if (orientation === "perpendicular") {
|
|
rotation += tickAngle;
|
|
if (tickAngle >= Math.PI / 2 && tickAngle < 1.5 * Math.PI) {
|
|
rotation += Math.PI;
|
|
}
|
|
}
|
|
return rotation;
|
|
}
|
|
getLabelAlign(tickAngle) {
|
|
const cos = Math.cos(tickAngle);
|
|
const sin = Math.sin(tickAngle);
|
|
let textAlign;
|
|
let textBaseline;
|
|
const orientation = this.getLabelOrientation();
|
|
const isCos0 = isNumberEqual2(cos, 0);
|
|
const isSin0 = isNumberEqual2(sin, 0);
|
|
const isCos1 = isNumberEqual2(cos, 1);
|
|
const isSinMinus1 = isNumberEqual2(sin, -1);
|
|
const isCosPositive = cos > 0 && !isCos0;
|
|
const isSinPositive = sin > 0 && !isSin0;
|
|
if (orientation === "parallel") {
|
|
textAlign = "center";
|
|
textBaseline = isCos1 && isSin0 || isSinPositive ? "top" : "bottom";
|
|
} else if (orientation === "perpendicular") {
|
|
textAlign = isSinMinus1 || isCosPositive ? "left" : "right";
|
|
textBaseline = "middle";
|
|
} else {
|
|
textAlign = "right";
|
|
if (isCos0) {
|
|
textAlign = "center";
|
|
} else if (isCosPositive) {
|
|
textAlign = "left";
|
|
}
|
|
textBaseline = "bottom";
|
|
if (isSin0) {
|
|
textBaseline = "middle";
|
|
} else if (isSinPositive) {
|
|
textBaseline = "top";
|
|
}
|
|
}
|
|
return { textAlign, textBaseline };
|
|
}
|
|
updateCrossLines() {
|
|
const { shape, gridLength: radius, innerRadiusRatio } = this;
|
|
for (const crossLine of this.crossLines) {
|
|
if (crossLine instanceof AngleCrossLine) {
|
|
crossLine.ticks = this.tickData.map((t) => t.value);
|
|
crossLine.shape = shape;
|
|
crossLine.axisOuterRadius = radius;
|
|
crossLine.axisInnerRadius = radius * innerRadiusRatio;
|
|
}
|
|
}
|
|
super.updateCrossLines();
|
|
}
|
|
};
|
|
AngleAxis.CrossLineConstructor = AngleCrossLine;
|
|
__decorateClass([
|
|
Property6
|
|
], AngleAxis.prototype, "startAngle", 2);
|
|
__decorateClass([
|
|
Property6
|
|
], AngleAxis.prototype, "endAngle", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/axes/angle-category/angleCategoryAxis.ts
|
|
var { CategoryScale } = _ModuleSupport8;
|
|
var AngleCategoryAxis = class extends AngleAxis {
|
|
constructor(moduleCtx) {
|
|
super(moduleCtx, new CategoryScale());
|
|
this.groupPaddingInner = 0;
|
|
this.paddingInner = 0;
|
|
this.interval = new AngleAxisInterval();
|
|
}
|
|
hasDefinedDomain() {
|
|
return false;
|
|
}
|
|
generateAngleTicks(domain) {
|
|
const { scale, gridLength: radius } = this;
|
|
const { values, minSpacing } = this.interval;
|
|
const tickParams = {
|
|
nice: [this.nice, this.nice],
|
|
interval: void 0,
|
|
tickCount: void 0,
|
|
minTickCount: 0,
|
|
maxTickCount: Infinity
|
|
};
|
|
const ticks = values ?? scale.ticks(tickParams, domain)?.ticks ?? [];
|
|
if (ticks.length < 2 || minSpacing == null) {
|
|
return ticks.map((value) => {
|
|
return { value, visible: true };
|
|
});
|
|
}
|
|
const startTick = ticks[0];
|
|
const startAngle = scale.convert(startTick);
|
|
const startX = radius * Math.cos(startAngle);
|
|
const startY = radius * Math.sin(startAngle);
|
|
for (let step = 1; step < ticks.length - 1; step++) {
|
|
const nextTick = ticks[step];
|
|
const nextAngle = scale.convert(nextTick);
|
|
if (nextAngle - startAngle > Math.PI) {
|
|
break;
|
|
}
|
|
const nextX = radius * Math.cos(nextAngle);
|
|
const nextY = radius * Math.sin(nextAngle);
|
|
const spacing = Math.hypot(nextX - startX, nextY - startY);
|
|
if (spacing > minSpacing) {
|
|
const visibleTicks = /* @__PURE__ */ new Set([startTick]);
|
|
walkPairsOutward(ticks, step, (_, next) => {
|
|
visibleTicks.add(next);
|
|
});
|
|
return ticks.map((value) => {
|
|
const visible = visibleTicks.has(value);
|
|
return { value, visible };
|
|
});
|
|
}
|
|
}
|
|
return [{ value: startTick, visible: true }];
|
|
}
|
|
avoidLabelCollisions(labelData) {
|
|
const { minSpacing } = this.label;
|
|
if (labelData.length < 3)
|
|
return;
|
|
const labelsCollide = (prev, next) => {
|
|
if (prev.hidden || next.hidden) {
|
|
return false;
|
|
} else if (minSpacing == null) {
|
|
return prev.box.collidesBBox(next.box);
|
|
}
|
|
const prevBox = prev.box.clone().grow(minSpacing / 2);
|
|
const nextBox = next.box.clone().grow(minSpacing / 2);
|
|
return prevBox.collidesBBox(nextBox);
|
|
};
|
|
const firstLabel = labelData[0];
|
|
const lastLabel = labelData.at(-1);
|
|
const visibleLabels = /* @__PURE__ */ new Set([firstLabel]);
|
|
const lastLabelIsOverFirst = isNumberEqual3(firstLabel.x, lastLabel.x) && isNumberEqual3(firstLabel.y, lastLabel.y);
|
|
const maxStep = Math.floor(labelData.length / 2);
|
|
for (let step = 1; step <= maxStep; step++) {
|
|
const labels = lastLabelIsOverFirst ? labelData.slice(0, -1) : labelData;
|
|
const collisionDetected = walkPairsOutward(labels, step, labelsCollide);
|
|
if (!collisionDetected) {
|
|
walkPairsOutward(labels, step, (_, next) => {
|
|
visibleLabels.add(next);
|
|
});
|
|
break;
|
|
}
|
|
}
|
|
for (const datum of labelData) {
|
|
if (!visibleLabels.has(datum)) {
|
|
datum.hidden = true;
|
|
datum.box = void 0;
|
|
}
|
|
}
|
|
}
|
|
tickFormatParams() {
|
|
return { type: "category" };
|
|
}
|
|
datumFormatParams(value, params) {
|
|
const { datum, seriesId, legendItemName, key, source, property, domain, boundSeries } = params;
|
|
return { type: "category", value, datum, seriesId, legendItemName, key, source, property, domain, boundSeries };
|
|
}
|
|
};
|
|
AngleCategoryAxis.className = "AngleCategoryAxis";
|
|
AngleCategoryAxis.type = "angle-category";
|
|
__decorateClass([
|
|
Property7
|
|
], AngleCategoryAxis.prototype, "groupPaddingInner", 2);
|
|
__decorateClass([
|
|
Property7
|
|
], AngleCategoryAxis.prototype, "paddingInner", 2);
|
|
__decorateClass([
|
|
Property7
|
|
], AngleCategoryAxis.prototype, "interval", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/axes/angle-category/angleCategoryAxisModule.ts
|
|
var AngleCategoryAxisModule = {
|
|
type: "axis",
|
|
name: "angle-category",
|
|
chartType: "polar",
|
|
enterprise: true,
|
|
version: VERSION,
|
|
options: _ModuleSupport9.angleCategoryAxisOptionsDefs,
|
|
themeTemplate: {
|
|
label: { spacing: 5 },
|
|
gridLine: { enabled: false },
|
|
shape: { $findFirstSiblingNotOperation: void 0 }
|
|
},
|
|
create: (ctx) => new AngleCategoryAxis(ctx)
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/axes/angle-number/angleNumberAxisModule.ts
|
|
import { VERSION as VERSION2, _ModuleSupport as _ModuleSupport12 } from "ag-charts-community";
|
|
|
|
// packages/ag-charts-enterprise/src/axes/angle-number/angleNumberAxis.ts
|
|
import "ag-charts-community";
|
|
import {
|
|
Property as Property8,
|
|
angleBetween,
|
|
findMinMax,
|
|
isNumberEqual as isNumberEqual5,
|
|
normalisedExtentWithMetadata
|
|
} from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/axes/angle-number/linearAngleScale.ts
|
|
import { _ModuleSupport as _ModuleSupport10 } from "ag-charts-community";
|
|
import { isDenseInterval, isNumberEqual as isNumberEqual4, range } from "ag-charts-core";
|
|
var { LinearScale } = _ModuleSupport10;
|
|
var LinearAngleScale = class _LinearAngleScale extends LinearScale {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.arcLength = 0;
|
|
}
|
|
static getNiceStepAndTickCount(ticks, domain) {
|
|
const [start, stop] = domain;
|
|
let step = LinearScale.getTickStep(start, stop, ticks);
|
|
const maxTickCount = Number.isNaN(ticks.maxTickCount) ? Infinity : ticks.maxTickCount;
|
|
const expectedTickCount = Math.abs(stop - start) / step;
|
|
let niceTickCount = Math.pow(2, Math.ceil(Math.log(expectedTickCount) / Math.log(2)));
|
|
if (niceTickCount > maxTickCount) {
|
|
niceTickCount /= 2;
|
|
step *= 2;
|
|
}
|
|
return { count: niceTickCount, step };
|
|
}
|
|
ticks(ticks, domain = this.domain) {
|
|
const { arcLength } = this;
|
|
if (!domain || domain.length < 2 || domain.some((d) => !Number.isFinite(d)) || arcLength <= 0) {
|
|
return { ticks: [], count: 0 };
|
|
}
|
|
const { nice, interval } = ticks;
|
|
const [d0, d1] = domain;
|
|
if (interval) {
|
|
const step2 = Math.abs(interval);
|
|
const availableRange = this.getPixelRange();
|
|
if (!isDenseInterval((d1 - d0) / step2, availableRange)) {
|
|
const result2 = range(d0, d1, step2);
|
|
return { ticks: result2.ticks, count: result2.count };
|
|
}
|
|
}
|
|
let step;
|
|
if (nice && this.hasNiceRange()) {
|
|
const linearNiceDomain = super.niceDomain(ticks, domain);
|
|
step = _LinearAngleScale.getNiceStepAndTickCount(ticks, linearNiceDomain).step;
|
|
} else {
|
|
step = LinearScale.getTickStep(d0, d1, ticks);
|
|
}
|
|
const result = range(d0, d1, step);
|
|
return { ticks: result.ticks, count: result.count };
|
|
}
|
|
hasNiceRange() {
|
|
const sortedRange = this.range.slice().sort((a, b) => a - b);
|
|
const niceRanges = [Math.PI, 2 * Math.PI];
|
|
return niceRanges.some((r) => isNumberEqual4(r, sortedRange[1] - sortedRange[0]));
|
|
}
|
|
niceDomain(ticks, domain = this.domain) {
|
|
const linearNiceDomain = super.niceDomain(ticks, domain);
|
|
if (!this.hasNiceRange())
|
|
return linearNiceDomain;
|
|
const reversed = linearNiceDomain[0] > linearNiceDomain[1];
|
|
const start = reversed ? linearNiceDomain[1] : linearNiceDomain[0];
|
|
const { step, count } = _LinearAngleScale.getNiceStepAndTickCount(ticks, linearNiceDomain);
|
|
const s = 1 / step;
|
|
const stop = step >= 1 ? Math.ceil(start / step + count) * step : Math.ceil((start + count * step) * s) / s;
|
|
return reversed ? [stop, start] : [start, stop];
|
|
}
|
|
getPixelRange() {
|
|
return this.arcLength;
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/axes/angle-number/angleNumberAxis.ts
|
|
var AngleNumberAxis = class extends AngleAxis {
|
|
constructor(moduleCtx) {
|
|
super(moduleCtx, new LinearAngleScale());
|
|
this.shape = "circle";
|
|
this.interval = new AngleAxisInterval();
|
|
}
|
|
hasDefinedDomain() {
|
|
const { min, max } = this;
|
|
return min != null && max != null && min < max;
|
|
}
|
|
normaliseDataDomain(d) {
|
|
const { min, max, preferredMin, preferredMax } = this;
|
|
const { extent: extent4, clipped } = normalisedExtentWithMetadata(
|
|
d.domain,
|
|
min,
|
|
max,
|
|
preferredMin,
|
|
preferredMax,
|
|
void 0,
|
|
d.sortMetadata?.sortOrder
|
|
);
|
|
return { domain: extent4, clipped };
|
|
}
|
|
getDomainExtentsNice() {
|
|
return [this.min == null && this.nice, this.max == null && this.nice];
|
|
}
|
|
updateScale() {
|
|
super.updateScale();
|
|
this.scale.arcLength = this.getRangeArcLength();
|
|
}
|
|
getRangeArcLength() {
|
|
const { range: requestedRange } = this;
|
|
const min = Math.min(...requestedRange);
|
|
const max = Math.max(...requestedRange);
|
|
const rotation = angleBetween(min, max) || 2 * Math.PI;
|
|
const radius = this.gridLength;
|
|
return rotation * radius;
|
|
}
|
|
generateAngleTicks(domain) {
|
|
const { scale, range: requestedRange, nice } = this;
|
|
const { values, step, minSpacing, maxSpacing } = this.interval;
|
|
let rawTicks;
|
|
if (values == null) {
|
|
const { arcLength } = scale;
|
|
const minTickCount = maxSpacing ? Math.floor(arcLength / maxSpacing) : 1;
|
|
const maxTickCount = minSpacing ? Math.floor(arcLength / minSpacing) : Infinity;
|
|
const preferredTickCount = Math.floor(4 / Math.PI * Math.abs(requestedRange[0] - requestedRange[1]));
|
|
const tickCount = Math.max(minTickCount, Math.min(maxTickCount, preferredTickCount));
|
|
const tickParams = {
|
|
nice: [nice, nice],
|
|
interval: step,
|
|
tickCount,
|
|
minTickCount,
|
|
maxTickCount
|
|
};
|
|
rawTicks = scale.ticks(tickParams, domain)?.ticks ?? [];
|
|
} else {
|
|
const [d0, d1] = findMinMax(domain.map(Number));
|
|
rawTicks = values.filter((value) => value >= d0 && value <= d1).sort((a, b) => a - b);
|
|
}
|
|
return rawTicks.map((value) => ({ value, visible: true }));
|
|
}
|
|
avoidLabelCollisions(labelData) {
|
|
const { minSpacing } = this.label;
|
|
const labelsCollide = (prev, next) => {
|
|
if (prev.hidden || next.hidden) {
|
|
return false;
|
|
} else if (minSpacing == null) {
|
|
return prev.box.collidesBBox(next.box);
|
|
}
|
|
const prevBox = prev.box.clone().grow(minSpacing / 2);
|
|
const nextBox = next.box.clone().grow(minSpacing / 2);
|
|
return prevBox.collidesBBox(nextBox);
|
|
};
|
|
const firstLabel = labelData[0];
|
|
const lastLabel = labelData.at(-1);
|
|
if (firstLabel !== lastLabel && isNumberEqual5(firstLabel.x, lastLabel.x) && isNumberEqual5(firstLabel.y, lastLabel.y)) {
|
|
lastLabel.hidden = true;
|
|
}
|
|
for (let step = 1; step < labelData.length; step *= 2) {
|
|
let collisionDetected = false;
|
|
for (let i = step; i < labelData.length; i += step) {
|
|
const next = labelData[i];
|
|
const prev = labelData[i - step];
|
|
if (labelsCollide(prev, next)) {
|
|
collisionDetected = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!collisionDetected) {
|
|
for (const [i, datum] of labelData.entries()) {
|
|
if (i % step > 0) {
|
|
datum.hidden = true;
|
|
datum.box = void 0;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
for (const [i, datum] of labelData.entries()) {
|
|
if (i > 0) {
|
|
datum.hidden = true;
|
|
datum.box = void 0;
|
|
}
|
|
}
|
|
}
|
|
tickFormatParams(_domain, _ticks, fractionDigits) {
|
|
return { type: "number", visibleDomain: void 0, fractionDigits };
|
|
}
|
|
datumFormatParams(value, params, fractionDigits) {
|
|
const { datum, seriesId, legendItemName, key, source, property, domain, boundSeries } = params;
|
|
return {
|
|
type: "number",
|
|
value,
|
|
datum,
|
|
seriesId,
|
|
legendItemName,
|
|
key,
|
|
source,
|
|
property,
|
|
domain,
|
|
boundSeries,
|
|
fractionDigits,
|
|
visibleDomain: void 0
|
|
};
|
|
}
|
|
};
|
|
AngleNumberAxis.className = "AngleNumberAxis";
|
|
AngleNumberAxis.type = "angle-number";
|
|
__decorateClass([
|
|
Property8
|
|
], AngleNumberAxis.prototype, "min", 2);
|
|
__decorateClass([
|
|
Property8
|
|
], AngleNumberAxis.prototype, "max", 2);
|
|
__decorateClass([
|
|
Property8
|
|
], AngleNumberAxis.prototype, "preferredMin", 2);
|
|
__decorateClass([
|
|
Property8
|
|
], AngleNumberAxis.prototype, "preferredMax", 2);
|
|
__decorateClass([
|
|
Property8
|
|
], AngleNumberAxis.prototype, "interval", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/axes/angle-number/angleNumberAxisModule.ts
|
|
var AngleNumberAxisModule = {
|
|
type: "axis",
|
|
name: "angle-number",
|
|
chartType: "polar",
|
|
enterprise: true,
|
|
version: VERSION2,
|
|
options: _ModuleSupport12.angleNumberAxisOptionsDefs,
|
|
themeTemplate: {
|
|
label: { spacing: 5 },
|
|
gridLine: { enabled: false }
|
|
},
|
|
create: (ctx) => new AngleNumberAxis(ctx)
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/axes/ordinal/ordinalTimeAxisModule.ts
|
|
import { VERSION as VERSION3, _ModuleSupport as _ModuleSupport14 } from "ag-charts-community";
|
|
|
|
// packages/ag-charts-enterprise/src/axes/ordinal/ordinalTimeAxis.ts
|
|
import {
|
|
_ModuleSupport as _ModuleSupport13
|
|
} from "ag-charts-community";
|
|
import {
|
|
Property as Property9,
|
|
dateTruncationForDomain,
|
|
intervalEpoch,
|
|
intervalMilliseconds,
|
|
intervalStep,
|
|
intervalUnit,
|
|
lowestGranularityUnitForTicks,
|
|
lowestGranularityUnitForValue
|
|
} from "ag-charts-core";
|
|
var {
|
|
OrdinalTimeScale,
|
|
ApproximateOrdinalTimeScale,
|
|
APPROXIMATE_THRESHOLD,
|
|
TimeAxisParentLevel,
|
|
minimumTimeAxisDatumGranularity
|
|
} = _ModuleSupport13;
|
|
var OrdinalTimeAxis = class extends _ModuleSupport13.DiscreteTimeAxis {
|
|
constructor(moduleCtx) {
|
|
const accurateScale = new OrdinalTimeScale();
|
|
super(moduleCtx, accurateScale);
|
|
this.parentLevel = new TimeAxisParentLevel();
|
|
this.accurateScale = accurateScale;
|
|
this.approximateScale = new ApproximateOrdinalTimeScale();
|
|
this.approximateScale.setSourceScale(accurateScale);
|
|
Object.defineProperty(this, "scale", {
|
|
get: () => this.getActiveScale(),
|
|
configurable: true
|
|
});
|
|
}
|
|
get primaryLabel() {
|
|
return this.parentLevel.enabled ? this.parentLevel.label : void 0;
|
|
}
|
|
get primaryTick() {
|
|
return this.parentLevel.enabled ? this.parentLevel.tick : void 0;
|
|
}
|
|
/**
|
|
* Returns the active scale based on visible range and data uniformity.
|
|
* Use approximate scale when data is uniform and visible datum count is large.
|
|
*/
|
|
getActiveScale() {
|
|
const visibleBandCount = this.accurateScale.bandCount(this.visibleRange);
|
|
const isUniform = this.accurateScale.getUniformityCache(this.visibleRange)?.isUniform ?? false;
|
|
if (isUniform && visibleBandCount >= APPROXIMATE_THRESHOLD) {
|
|
return this.approximateScale;
|
|
}
|
|
return this.accurateScale;
|
|
}
|
|
processData() {
|
|
super.processData();
|
|
const { boundSeries, direction } = this;
|
|
this.minimumTimeGranularity = minimumTimeAxisDatumGranularity(boundSeries, direction, void 0, void 0);
|
|
}
|
|
tickFormatParams(domain, ticks, _fractionDigits, timeInterval) {
|
|
timeInterval ?? (timeInterval = lowestGranularityUnitForTicks(ticks));
|
|
const truncateDate = dateTruncationForDomain(domain);
|
|
const unit = intervalUnit(timeInterval);
|
|
const step = intervalStep(timeInterval);
|
|
const epoch = intervalEpoch(timeInterval);
|
|
return { type: "date", unit, step, epoch, truncateDate };
|
|
}
|
|
datumFormatParams(value, params, _fractionDigits, timeInterval, style) {
|
|
if (typeof value === "number")
|
|
value = new Date(value);
|
|
if (timeInterval == null) {
|
|
const { minimumTimeGranularity } = this;
|
|
const datumGranularity = lowestGranularityUnitForValue(value);
|
|
if (minimumTimeGranularity != null && intervalMilliseconds(minimumTimeGranularity) < intervalMilliseconds(datumGranularity)) {
|
|
timeInterval = minimumTimeGranularity;
|
|
} else {
|
|
timeInterval = datumGranularity;
|
|
}
|
|
}
|
|
const { datum, seriesId, legendItemName, key, source, property, domain, boundSeries } = params;
|
|
const unit = intervalUnit(timeInterval);
|
|
const step = intervalStep(timeInterval);
|
|
const epoch = intervalEpoch(timeInterval);
|
|
return {
|
|
type: "date",
|
|
value,
|
|
datum,
|
|
seriesId,
|
|
legendItemName,
|
|
key,
|
|
source,
|
|
property,
|
|
domain,
|
|
boundSeries,
|
|
unit,
|
|
step,
|
|
epoch,
|
|
style
|
|
};
|
|
}
|
|
};
|
|
OrdinalTimeAxis.className = "OrdinalTimeAxis";
|
|
OrdinalTimeAxis.type = "ordinal-time";
|
|
__decorateClass([
|
|
Property9
|
|
], OrdinalTimeAxis.prototype, "parentLevel", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/axes/ordinal/ordinalTimeAxisModule.ts
|
|
var OrdinalTimeAxisModule = {
|
|
type: "axis",
|
|
name: "ordinal-time",
|
|
chartType: "cartesian",
|
|
enterprise: true,
|
|
version: VERSION3,
|
|
options: _ModuleSupport14.ordinalTimeAxisOptionsDefs,
|
|
themeTemplate: {
|
|
groupPaddingInner: 0,
|
|
label: { autoRotate: false, minSpacing: 40 },
|
|
gridLine: { enabled: false },
|
|
interval: { placement: "between" }
|
|
},
|
|
create: (ctx) => new OrdinalTimeAxis(ctx)
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/axes/radius-category/radiusCategoryAxisModule.ts
|
|
import { VERSION as VERSION4, _ModuleSupport as _ModuleSupport18 } from "ag-charts-community";
|
|
|
|
// packages/ag-charts-enterprise/src/axes/radius-category/radiusCategoryAxis.ts
|
|
import { _ModuleSupport as _ModuleSupport17 } from "ag-charts-community";
|
|
import { Property as Property12, ProxyPropertyOnWrite as ProxyPropertyOnWrite2 } from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/axes/radius/radiusAxis.ts
|
|
import { _ModuleSupport as _ModuleSupport16 } from "ag-charts-community";
|
|
import {
|
|
ChartAxisDirection as ChartAxisDirection5,
|
|
Property as Property11,
|
|
ZIndexMap as ZIndexMap2,
|
|
isNumberEqual as isNumberEqual7,
|
|
normalizeAngle360 as normalizeAngle3603,
|
|
toRadians as toRadians2
|
|
} from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/axes/polar-crosslines/radiusCrossLine.ts
|
|
import { _ModuleSupport as _ModuleSupport15 } from "ag-charts-community";
|
|
import { ChartAxisDirection as ChartAxisDirection4, Property as Property10, clamp, isNumberEqual as isNumberEqual6, normalizeAngle360FromDegrees } from "ag-charts-core";
|
|
var { validateCrossLineValue: validateCrossLineValue2, Group: Group3, Path: Path3, Sector: Sector2, RotatableText: RotatableText3 } = _ModuleSupport15;
|
|
var RadiusCrossLineLabel = class extends PolarCrossLineLabel {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.positionAngle = void 0;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property10
|
|
], RadiusCrossLineLabel.prototype, "positionAngle", 2);
|
|
var RadiusCrossLine = class extends PolarCrossLine {
|
|
constructor() {
|
|
super();
|
|
this.direction = ChartAxisDirection4.Radius;
|
|
this.label = new RadiusCrossLineLabel();
|
|
this.polygonNode = new Path3();
|
|
this.sectorNode = new Sector2();
|
|
this.crossLineRange = new Group3();
|
|
this.labelNode = new RotatableText3();
|
|
this.outerRadius = 0;
|
|
this.innerRadius = 0;
|
|
this.crossLineRange.append(this.polygonNode);
|
|
this.crossLineRange.append(this.sectorNode);
|
|
this.labelGroup.append(this.labelNode);
|
|
}
|
|
update(visible) {
|
|
const { scale } = this;
|
|
if (!scale || !validateCrossLineValue2(this, scale)) {
|
|
this.rangeGroup.visible = false;
|
|
this.lineGroup.visible = false;
|
|
this.labelGroup.visible = false;
|
|
return;
|
|
}
|
|
this.updateRadii();
|
|
const { innerRadius, outerRadius } = this;
|
|
visible && (visible = innerRadius >= this.axisInnerRadius && outerRadius <= this.axisOuterRadius);
|
|
this.rangeGroup.visible = visible;
|
|
this.lineGroup.visible = visible;
|
|
this.labelGroup.visible = visible;
|
|
this.updatePolygonNode(visible);
|
|
this.updateSectorNode(visible);
|
|
this.updateLabelNode(visible);
|
|
this.assignCrossLineGroup(this.type === "range", this.crossLineRange);
|
|
}
|
|
updateRadii() {
|
|
const { range: range2, scale, type, axisInnerRadius, axisOuterRadius } = this;
|
|
if (!scale)
|
|
return { innerRadius: 0, outerRadius: 0 };
|
|
const getRadius = (value) => axisOuterRadius + axisInnerRadius - value;
|
|
let outerRadius, innerRadius;
|
|
if (type === "line") {
|
|
outerRadius = getRadius(scale.convert(this.value));
|
|
innerRadius = outerRadius;
|
|
} else {
|
|
const bandwidth = Math.abs(scale?.bandwidth ?? 0);
|
|
const convertedRange = range2.map((r) => scale.convert(r));
|
|
outerRadius = getRadius(Math.max(...convertedRange));
|
|
innerRadius = getRadius(Math.min(...convertedRange)) + bandwidth;
|
|
}
|
|
this.outerRadius = outerRadius;
|
|
this.innerRadius = innerRadius;
|
|
}
|
|
drawPolygon(radius, angles, polygon) {
|
|
for (const [index, angle] of angles.entries()) {
|
|
const x = radius * Math.cos(angle);
|
|
const y = radius * Math.sin(angle);
|
|
if (index === 0) {
|
|
polygon.path.moveTo(x, y);
|
|
} else {
|
|
polygon.path.lineTo(x, y);
|
|
}
|
|
}
|
|
polygon.path.closePath();
|
|
}
|
|
updatePolygonNode(visible) {
|
|
const { gridAngles, polygonNode: polygon, scale, shape, type, innerRadius, outerRadius } = this;
|
|
if (!visible || shape !== "polygon" || !scale || !gridAngles) {
|
|
polygon.visible = false;
|
|
return;
|
|
}
|
|
polygon.visible = true;
|
|
const padding2 = this.getPadding();
|
|
polygon.path.clear(true);
|
|
this.drawPolygon(outerRadius - padding2, gridAngles, polygon);
|
|
const reversedAngles = gridAngles.slice().reverse();
|
|
const innerPolygonRadius = type === "line" ? outerRadius - padding2 : innerRadius + padding2;
|
|
this.drawPolygon(innerPolygonRadius, reversedAngles, polygon);
|
|
this.setSectorNodeProps(polygon);
|
|
}
|
|
updateSectorNode(visible) {
|
|
const { axisInnerRadius, axisOuterRadius, scale, sectorNode: sector, shape, innerRadius, outerRadius } = this;
|
|
if (!visible || shape !== "circle" || !scale) {
|
|
sector.visible = false;
|
|
return;
|
|
}
|
|
sector.visible = true;
|
|
sector.startAngle = 0;
|
|
sector.endAngle = 2 * Math.PI;
|
|
const padding2 = this.getPadding();
|
|
const r0 = clamp(axisInnerRadius, innerRadius + padding2, axisOuterRadius);
|
|
const r1 = clamp(axisInnerRadius, outerRadius - padding2, axisOuterRadius);
|
|
sector.innerRadius = Math.min(r0, r1);
|
|
sector.outerRadius = Math.max(r0, r1);
|
|
this.setSectorNodeProps(sector);
|
|
}
|
|
updateLabelNode(visible) {
|
|
const { innerRadius, label, labelNode: node, scale, shape, type } = this;
|
|
if (!visible || label.enabled === false || !label.text || !scale) {
|
|
node.visible = false;
|
|
return;
|
|
}
|
|
const angle = normalizeAngle360FromDegrees((label.positionAngle ?? 0) - 90);
|
|
const isBottomSide = (isNumberEqual6(angle, 0) || angle > 0) && angle < Math.PI;
|
|
const rotation = isBottomSide ? angle - Math.PI / 2 : angle + Math.PI / 2;
|
|
let distance;
|
|
const angles = this.gridAngles ?? [];
|
|
if (type === "line") {
|
|
distance = innerRadius + label.padding;
|
|
} else if (shape === "circle" || angles.length < 3) {
|
|
distance = innerRadius - label.padding;
|
|
} else {
|
|
distance = innerRadius * Math.cos(Math.PI / angles.length) - label.padding;
|
|
}
|
|
const labelX = distance * Math.cos(angle);
|
|
const labelY = distance * Math.sin(angle);
|
|
let textBaseline;
|
|
if (type === "line") {
|
|
textBaseline = isBottomSide ? "top" : "bottom";
|
|
} else {
|
|
textBaseline = isBottomSide ? "bottom" : "top";
|
|
}
|
|
this.setLabelNodeProps(node, labelX, labelY, textBaseline, rotation);
|
|
}
|
|
getPadding() {
|
|
const { scale } = this;
|
|
if (!scale)
|
|
return 0;
|
|
const bandwidth = Math.abs(scale.bandwidth ?? 0);
|
|
const step = Math.abs(scale.step ?? 0);
|
|
return scale instanceof _ModuleSupport15.BandScale ? (step - bandwidth) / 2 : 0;
|
|
}
|
|
};
|
|
RadiusCrossLine.className = "RadiusCrossLine";
|
|
|
|
// packages/ag-charts-enterprise/src/axes/radius/radiusAxis.ts
|
|
var { Caption, Group: Group4, TransformableGroup, Path: Path4, Line: Line2, Selection: Selection2, generateTicks, AxisGroupZIndexMap } = _ModuleSupport16;
|
|
var RadiusAxisLabel = class extends _ModuleSupport16.AxisLabel {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.autoRotateAngle = 335;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property11
|
|
], RadiusAxisLabel.prototype, "autoRotate", 2);
|
|
__decorateClass([
|
|
Property11
|
|
], RadiusAxisLabel.prototype, "autoRotateAngle", 2);
|
|
var RadiusAxis = class extends _ModuleSupport16.PolarAxis {
|
|
constructor(moduleCtx, scale) {
|
|
super(moduleCtx, scale);
|
|
this.positionAngle = 0;
|
|
this.gridLineGroupSelection = Selection2.select(
|
|
this.gridLineGroup,
|
|
Line2,
|
|
false
|
|
);
|
|
this.generatedTicks = void 0;
|
|
this.headingLabelGroup = this.axisGroup.appendChild(
|
|
new TransformableGroup({ name: `${this.id}-Axis-heading` })
|
|
);
|
|
this.lineNodeGroup = this.axisGroup.appendChild(
|
|
new TransformableGroup({ name: `${this.id}-Axis-line` })
|
|
);
|
|
this.lineNode = this.lineNodeGroup.appendChild(
|
|
new Line2({
|
|
name: `${this.id}-Axis-line`,
|
|
zIndex: AxisGroupZIndexMap.AxisLine
|
|
})
|
|
);
|
|
this.gridPathGroup = this.gridGroup.appendChild(
|
|
new Group4({
|
|
name: `${this.id}-gridPaths`,
|
|
zIndex: ZIndexMap2.AXIS_GRID
|
|
})
|
|
);
|
|
this.gridPathSelection = Selection2.select(this.gridPathGroup, Path4);
|
|
this.headingLabelGroup.appendChild(this.title.caption.node);
|
|
this.cleanup.register(this.title.caption.registerInteraction(this.moduleCtx, "afterend"));
|
|
}
|
|
get direction() {
|
|
return ChartAxisDirection5.Radius;
|
|
}
|
|
getAxisTransform() {
|
|
const maxRadius = this.scale.range[0];
|
|
const { translation, positionAngle, innerRadiusRatio } = this;
|
|
const innerRadius = maxRadius * innerRadiusRatio;
|
|
const rotation = toRadians2(positionAngle);
|
|
return {
|
|
translationX: translation.x,
|
|
translationY: translation.y - maxRadius - innerRadius,
|
|
rotation,
|
|
rotationCenterX: 0,
|
|
rotationCenterY: maxRadius + innerRadius
|
|
};
|
|
}
|
|
update() {
|
|
super.update();
|
|
this.updateTitle();
|
|
this.updateGridLines();
|
|
const { enabled, stroke: stroke3, width } = this.line;
|
|
this.lineNode.setProperties({
|
|
stroke: stroke3,
|
|
strokeWidth: enabled ? width : 0,
|
|
x1: 0,
|
|
y1: this.range[0],
|
|
x2: 0,
|
|
y2: this.range[1]
|
|
});
|
|
}
|
|
updatePosition() {
|
|
super.updatePosition();
|
|
const axisTransform = this.getAxisTransform();
|
|
this.tickLineGroup.setProperties(axisTransform);
|
|
this.tickLabelGroup.setProperties(axisTransform);
|
|
this.lineNodeGroup.setProperties(axisTransform);
|
|
this.headingLabelGroup.setProperties(axisTransform);
|
|
}
|
|
calculateRotations() {
|
|
const rotation = 0;
|
|
const parallelFlipRotation = 0;
|
|
const regularFlipRotation = -Math.PI / 2;
|
|
return { rotation, parallelFlipRotation, regularFlipRotation };
|
|
}
|
|
calculateTickLayout(domain, niceMode, _visibleRange) {
|
|
const visibleRange = [0, 1];
|
|
const sideFlag = this.label.getSideFlag();
|
|
const labelX = sideFlag * (this.getTickSize() + this.label.spacing + this.seriesAreaPadding);
|
|
const { range: range2, reverse, defaultTickMinSpacing } = this;
|
|
const tickGenerationResult = generateTicks({
|
|
scale: this.scale,
|
|
label: this.label,
|
|
interval: this.interval,
|
|
tickFormatter: (...args) => this.tickFormatter(...args),
|
|
domain,
|
|
range: range2,
|
|
reverse,
|
|
niceMode,
|
|
visibleRange,
|
|
defaultTickMinSpacing,
|
|
labelOffset: labelX,
|
|
sideFlag,
|
|
axisRotation: 0,
|
|
sizeLimit: void 0,
|
|
primaryTickCount: void 0
|
|
});
|
|
const { tickData } = tickGenerationResult;
|
|
const { ticks, rawTicks, rawTickCount, tickDomain, fractionDigits, niceDomain = domain } = tickData;
|
|
const labels = ticks.map((d) => this.getTickLabelProps(d, tickGenerationResult));
|
|
this.generatedTicks = { ticks, labels };
|
|
return { ticks: rawTicks, tickDomain, niceDomain, rawTickCount, fractionDigits, timeInterval: void 0 };
|
|
}
|
|
updateSelections() {
|
|
const { generatedTicks } = this;
|
|
if (!generatedTicks)
|
|
return;
|
|
const { ticks, labels } = generatedTicks;
|
|
this.gridLineGroupSelection.update(this.gridLength ? ticks : []);
|
|
this.tickLabelGroupSelection.update(labels);
|
|
this.gridPathSelection.update(this.gridLine.enabled ? this.prepareGridPathTickData(ticks) : []);
|
|
this.gridLineGroupSelection.cleanup();
|
|
this.tickLabelGroupSelection.cleanup();
|
|
this.gridPathSelection.cleanup();
|
|
}
|
|
// TODO - abstract out
|
|
updateLabels() {
|
|
if (!this.label.enabled)
|
|
return;
|
|
const axisLabelPositionFn = _ModuleSupport16.resetAxisLabelSelectionFn();
|
|
this.tickLabelGroupSelection.each((node, datum) => {
|
|
node.fill = datum.color;
|
|
node.text = datum.text;
|
|
node.textBaseline = datum.textBaseline;
|
|
node.textAlign = datum.textAlign ?? "center";
|
|
node.setFont(datum);
|
|
node.setBoxing(datum);
|
|
node.setProperties(axisLabelPositionFn(node, datum));
|
|
});
|
|
}
|
|
updateGridLines() {
|
|
const {
|
|
gridLine: { style, width },
|
|
shape,
|
|
generatedTicks
|
|
} = this;
|
|
if (!style || !generatedTicks) {
|
|
return;
|
|
}
|
|
const styleCount = style.length;
|
|
const setStyle = (node, index) => {
|
|
const { stroke: stroke3, lineDash } = style[index % styleCount];
|
|
node.stroke = stroke3;
|
|
node.strokeWidth = width;
|
|
node.lineDash = lineDash;
|
|
node.fill = void 0;
|
|
};
|
|
const [startAngle, endAngle] = this.gridRange ?? [0, 2 * Math.PI];
|
|
const isFullCircle = isNumberEqual7(endAngle - startAngle, 2 * Math.PI);
|
|
const drawCircleShape = (node, value) => {
|
|
const { path } = node;
|
|
path.clear(true);
|
|
const radius = this.getTickRadius(value);
|
|
if (isFullCircle) {
|
|
path.moveTo(radius, 0);
|
|
path.arc(0, 0, radius, 0, 2 * Math.PI);
|
|
} else {
|
|
path.moveTo(radius * Math.cos(startAngle), radius * Math.sin(startAngle));
|
|
path.arc(0, 0, radius, normalizeAngle3603(startAngle), normalizeAngle3603(endAngle));
|
|
}
|
|
if (isFullCircle) {
|
|
path.closePath();
|
|
}
|
|
};
|
|
const drawPolygonShape = (node, value) => {
|
|
const { path } = node;
|
|
const angles = this.gridAngles;
|
|
path.clear(true);
|
|
if (!angles || angles.length < 3) {
|
|
return;
|
|
}
|
|
const radius = this.getTickRadius(value);
|
|
for (const [idx, angle] of angles.entries()) {
|
|
const x = radius * Math.cos(angle);
|
|
const y = radius * Math.sin(angle);
|
|
if (idx === 0) {
|
|
path.moveTo(x, y);
|
|
} else {
|
|
path.lineTo(x, y);
|
|
}
|
|
for (const [innerIdx, innerAngle] of angles.entries()) {
|
|
const x2 = radius * Math.cos(innerAngle);
|
|
const y2 = radius * Math.sin(innerAngle);
|
|
if (innerIdx === 0) {
|
|
path.moveTo(x2, y2);
|
|
} else {
|
|
path.lineTo(x2, y2);
|
|
}
|
|
}
|
|
path.closePath();
|
|
}
|
|
path.closePath();
|
|
};
|
|
const drawFn = shape === "circle" ? drawCircleShape : drawPolygonShape;
|
|
this.gridPathSelection.each((node, value, index) => {
|
|
setStyle(node, index);
|
|
drawFn(node, value);
|
|
});
|
|
}
|
|
updateTitle() {
|
|
const identityFormatter = (params) => params.defaultValue;
|
|
const { title, range: requestedRange } = this;
|
|
const { formatter = identityFormatter } = this.title;
|
|
title.caption.enabled = title.enabled;
|
|
title.caption.fontFamily = title.fontFamily;
|
|
title.caption.fontSize = title.fontSize;
|
|
title.caption.fontStyle = title.fontStyle;
|
|
title.caption.fontWeight = title.fontWeight;
|
|
title.caption.color = title.color;
|
|
title.caption.wrapping = title.wrapping;
|
|
let titleVisible = false;
|
|
const titleNode = title.caption.node;
|
|
if (title.enabled) {
|
|
titleVisible = true;
|
|
titleNode.rotation = Math.PI / 2;
|
|
titleNode.x = Math.floor((requestedRange[0] + requestedRange[1]) / 2);
|
|
titleNode.y = -Caption.SMALL_PADDING;
|
|
titleNode.textAlign = "center";
|
|
titleNode.textBaseline = "bottom";
|
|
titleNode.text = this.cachedCallWithContext(formatter, this.getTitleFormatterParams(this.scale.domain));
|
|
}
|
|
titleNode.visible = titleVisible;
|
|
}
|
|
updateCrossLines() {
|
|
for (const crossLine of this.crossLines) {
|
|
if (crossLine instanceof RadiusCrossLine) {
|
|
const { shape, gridAngles, range: range2, innerRadiusRatio } = this;
|
|
const radius = range2[0];
|
|
crossLine.shape = shape;
|
|
crossLine.gridAngles = gridAngles;
|
|
crossLine.axisOuterRadius = radius;
|
|
crossLine.axisInnerRadius = radius * innerRadiusRatio;
|
|
}
|
|
}
|
|
super.updateCrossLines();
|
|
}
|
|
createLabel() {
|
|
return new RadiusAxisLabel();
|
|
}
|
|
// TODO - abstract out (shared with cartesian axis)
|
|
getTickLabelProps(datum, tickGenerationResult) {
|
|
const { label } = this;
|
|
const { rotation, textBaseline, textAlign } = tickGenerationResult;
|
|
const range2 = this.scale.range;
|
|
const text2 = datum.tickLabel ?? "";
|
|
const sideFlag = label.getSideFlag();
|
|
const labelX = sideFlag * (this.getTickSize() + label.spacing + this.seriesAreaPadding);
|
|
const visible = text2 !== "" && text2 != null;
|
|
const combinedRotation = rotation;
|
|
return {
|
|
...this.getLabelStyles({ value: datum.tick, formattedValue: datum.tickLabel }),
|
|
tickId: datum.tickId,
|
|
rotation: combinedRotation,
|
|
text: text2,
|
|
textAlign,
|
|
textBaseline,
|
|
visible,
|
|
x: labelX,
|
|
y: datum.translation,
|
|
rotationCenterX: labelX,
|
|
rotationCenterY: datum.translation,
|
|
range: range2
|
|
};
|
|
}
|
|
};
|
|
RadiusAxis.CrossLineConstructor = RadiusCrossLine;
|
|
__decorateClass([
|
|
Property11
|
|
], RadiusAxis.prototype, "positionAngle", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/axes/radius-category/radiusCategoryAxis.ts
|
|
var { CategoryScale: CategoryScale2 } = _ModuleSupport17;
|
|
var RadiusCategoryAxis = class extends RadiusAxis {
|
|
constructor(moduleCtx) {
|
|
super(moduleCtx, new CategoryScale2());
|
|
this.shape = "circle";
|
|
this.groupPaddingInner = 0;
|
|
this.paddingInner = 0;
|
|
this.paddingOuter = 0;
|
|
}
|
|
hasDefinedDomain() {
|
|
return false;
|
|
}
|
|
normaliseDataDomain(d) {
|
|
return { domain: d.domain, clipped: false };
|
|
}
|
|
prepareGridPathTickData(data) {
|
|
return data.slice().reverse();
|
|
}
|
|
getTickRadius(tickDatum) {
|
|
const { scale, innerRadiusRatio } = this;
|
|
const maxRadius = scale.range[0];
|
|
const minRadius = maxRadius * innerRadiusRatio;
|
|
if (CategoryScale2.is(scale)) {
|
|
const ticks = scale.domain;
|
|
const index = ticks.length - 1 - ticks.indexOf(tickDatum.tick);
|
|
return index === 0 ? minRadius : scale.inset + scale.step * (index - 0.5) + scale.bandwidth / 2;
|
|
} else {
|
|
const tickRange = (maxRadius - minRadius) / scale.domain.length;
|
|
return maxRadius - tickDatum.translation + minRadius - tickRange / 2;
|
|
}
|
|
}
|
|
tickFormatParams() {
|
|
return { type: "category" };
|
|
}
|
|
datumFormatParams(value, params) {
|
|
const { datum, seriesId, legendItemName, key, source, property, domain, boundSeries } = params;
|
|
return { type: "category", value, datum, seriesId, legendItemName, key, source, property, domain, boundSeries };
|
|
}
|
|
};
|
|
RadiusCategoryAxis.className = "RadiusCategoryAxis";
|
|
RadiusCategoryAxis.type = "radius-category";
|
|
__decorateClass([
|
|
Property12
|
|
], RadiusCategoryAxis.prototype, "groupPaddingInner", 2);
|
|
__decorateClass([
|
|
ProxyPropertyOnWrite2("scale", "paddingInner"),
|
|
Property12
|
|
], RadiusCategoryAxis.prototype, "paddingInner", 2);
|
|
__decorateClass([
|
|
ProxyPropertyOnWrite2("scale", "paddingOuter"),
|
|
Property12
|
|
], RadiusCategoryAxis.prototype, "paddingOuter", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/axes/radius-category/radiusCategoryAxisModule.ts
|
|
var RadiusCategoryAxisModule = {
|
|
type: "axis",
|
|
name: "radius-category",
|
|
chartType: "polar",
|
|
enterprise: true,
|
|
version: VERSION4,
|
|
options: _ModuleSupport18.radiusCategoryAxisOptionsDefs,
|
|
themeTemplate: {
|
|
positionAngle: 0,
|
|
line: { enabled: false },
|
|
label: { minSpacing: 5 }
|
|
},
|
|
create: (ctx) => new RadiusCategoryAxis(ctx)
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/axes/radius-number/radiusNumberAxisModule.ts
|
|
import { VERSION as VERSION5, _ModuleSupport as _ModuleSupport20 } from "ag-charts-community";
|
|
|
|
// packages/ag-charts-enterprise/src/axes/radius-number/radiusNumberAxis.ts
|
|
import { _ModuleSupport as _ModuleSupport19 } from "ag-charts-community";
|
|
import { Property as Property13, normalisedExtentWithMetadata as normalisedExtentWithMetadata2 } from "ag-charts-core";
|
|
var { LinearScale: LinearScale2 } = _ModuleSupport19;
|
|
var RadiusNumberAxis = class extends RadiusAxis {
|
|
constructor(moduleCtx) {
|
|
super(moduleCtx, new LinearScale2());
|
|
this.shape = "polygon";
|
|
}
|
|
hasDefinedDomain() {
|
|
const { min, max } = this;
|
|
return min != null && max != null && min < max;
|
|
}
|
|
prepareGridPathTickData(data) {
|
|
const { scale } = this;
|
|
const domainTop = scale.domain[1];
|
|
return data.filter(({ tick }) => tick !== domainTop).sort((a, b) => b.tick - a.tick);
|
|
}
|
|
getTickRadius(tickDatum) {
|
|
const { scale } = this;
|
|
const maxRadius = scale.range[0];
|
|
const minRadius = maxRadius * this.innerRadiusRatio;
|
|
return maxRadius - tickDatum.translation + minRadius;
|
|
}
|
|
normaliseDataDomain(d) {
|
|
const { min, max, preferredMin, preferredMax } = this;
|
|
const { extent: extent4, clipped } = normalisedExtentWithMetadata2(
|
|
d.domain,
|
|
min,
|
|
max,
|
|
preferredMin,
|
|
preferredMax,
|
|
void 0,
|
|
d.sortMetadata?.sortOrder
|
|
);
|
|
return { domain: extent4, clipped };
|
|
}
|
|
getDomainExtentsNice() {
|
|
return [this.min == null && this.nice, this.max == null && this.nice];
|
|
}
|
|
tickFormatParams(_domain, _ticks, fractionDigits) {
|
|
return { type: "number", visibleDomain: void 0, fractionDigits };
|
|
}
|
|
datumFormatParams(value, params, fractionDigits) {
|
|
const { datum, seriesId, legendItemName, key, source, property, domain, boundSeries } = params;
|
|
return {
|
|
type: "number",
|
|
value,
|
|
datum,
|
|
seriesId,
|
|
legendItemName,
|
|
key,
|
|
source,
|
|
property,
|
|
domain,
|
|
boundSeries,
|
|
fractionDigits,
|
|
visibleDomain: void 0
|
|
};
|
|
}
|
|
};
|
|
RadiusNumberAxis.className = "RadiusNumberAxis";
|
|
RadiusNumberAxis.type = "radius-number";
|
|
__decorateClass([
|
|
Property13
|
|
], RadiusNumberAxis.prototype, "min", 2);
|
|
__decorateClass([
|
|
Property13
|
|
], RadiusNumberAxis.prototype, "max", 2);
|
|
__decorateClass([
|
|
Property13
|
|
], RadiusNumberAxis.prototype, "preferredMin", 2);
|
|
__decorateClass([
|
|
Property13
|
|
], RadiusNumberAxis.prototype, "preferredMax", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/axes/radius-number/radiusNumberAxisModule.ts
|
|
var RadiusNumberAxisModule = {
|
|
type: "axis",
|
|
name: "radius-number",
|
|
chartType: "polar",
|
|
enterprise: true,
|
|
version: VERSION5,
|
|
options: _ModuleSupport20.radiusNumberAxisOptionsDefs,
|
|
themeTemplate: {
|
|
positionAngle: 0,
|
|
line: { enabled: false },
|
|
shape: { $findFirstSiblingNotOperation: void 0 },
|
|
label: { minSpacing: 5 }
|
|
},
|
|
create: (ctx) => new RadiusNumberAxis(ctx)
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/animation/animationModule.ts
|
|
import { VERSION as VERSION6 } from "ag-charts-community";
|
|
import { boolean, positiveNumber, undocumented } from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/features/animation/animation.ts
|
|
import "ag-charts-community";
|
|
import { AbstractModuleInstance, ObserveChanges as ObserveChanges2, Property as Property14 } from "ag-charts-core";
|
|
var Animation = class extends AbstractModuleInstance {
|
|
constructor(ctx) {
|
|
super();
|
|
this.ctx = ctx;
|
|
this.enabled = true;
|
|
ctx.animationManager.skip(false);
|
|
this.cleanup.register(() => ctx.animationManager.skip(true));
|
|
}
|
|
};
|
|
__decorateClass([
|
|
ObserveChanges2((target, newValue) => {
|
|
target.ctx.animationManager.skip(!newValue);
|
|
}),
|
|
Property14
|
|
], Animation.prototype, "enabled", 2);
|
|
__decorateClass([
|
|
ObserveChanges2((target, newValue) => {
|
|
if (newValue != null) {
|
|
target.ctx.animationManager.defaultDuration = newValue;
|
|
}
|
|
}),
|
|
Property14
|
|
], Animation.prototype, "duration", 2);
|
|
__decorateClass([
|
|
ObserveChanges2((target, newValue) => {
|
|
target.ctx.animationManager.maxAnimatableItems = newValue ?? Infinity;
|
|
}),
|
|
Property14
|
|
], Animation.prototype, "maxAnimatableItems", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/features/animation/animationModule.ts
|
|
var AnimationModule = {
|
|
type: "plugin",
|
|
name: "animation",
|
|
enterprise: true,
|
|
version: VERSION6,
|
|
options: {
|
|
enabled: boolean,
|
|
duration: positiveNumber
|
|
},
|
|
themeTemplate: {
|
|
enabled: true
|
|
},
|
|
create: (ctx) => new Animation(ctx)
|
|
};
|
|
AnimationModule.options.maxAnimatableItems = undocumented(positiveNumber);
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/annotationsModule.ts
|
|
import { VERSION as VERSION7, _ModuleSupport as _ModuleSupport65 } from "ag-charts-community";
|
|
import "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/features/shared-toolbar/sharedToolbar.ts
|
|
import { _ModuleSupport as _ModuleSupport22 } from "ag-charts-community";
|
|
import { AbstractModuleInstance as AbstractModuleInstance2 } from "ag-charts-core";
|
|
var _SharedToolbar = class _SharedToolbar extends AbstractModuleInstance2 {
|
|
constructor(ctx) {
|
|
super();
|
|
this.ctx = ctx;
|
|
this.activeSections = /* @__PURE__ */ new Set();
|
|
this.sectionButtons = {
|
|
annotations: [],
|
|
chartToolbar: []
|
|
};
|
|
this.container = this.ctx.domManager.addChild("canvas-overlay", "shared-toolbar");
|
|
this.container.role = "presentation";
|
|
}
|
|
getSharedToolbar(section) {
|
|
if (!this.sharedToolbar) {
|
|
this.createSharedToolbar();
|
|
}
|
|
if (section === "chartToolbar" && this.sharedToolbar) {
|
|
this.sharedToolbar.setAriaLabelId("ariaLabelFinancialCharts");
|
|
}
|
|
return this.toolbarWithSection(section);
|
|
}
|
|
createSharedToolbar() {
|
|
this.sharedToolbar = new _ModuleSupport22.Toolbar(this.ctx, "ariaLabelAnnotationsToolbar", "vertical");
|
|
this.sharedToolbar.addClass("ag-charts-shared-toolbar");
|
|
this.container.append(this.sharedToolbar.getElement());
|
|
this.cleanup.register(() => {
|
|
if (!this.sharedToolbar)
|
|
return;
|
|
this.sharedToolbar.getElement().remove();
|
|
this.sharedToolbar.destroy();
|
|
this.sharedToolbar = void 0;
|
|
});
|
|
}
|
|
toolbarWithSection(section) {
|
|
const sharedToolbar = this.sharedToolbar;
|
|
const withSection = {
|
|
layout: (layoutBox, padding2) => {
|
|
if (this.firstLayoutSection != null && this.firstLayoutSection !== section && this.activeSections.has(this.firstLayoutSection)) {
|
|
return;
|
|
}
|
|
this.firstLayoutSection = section;
|
|
const width = sharedToolbar.getBounds().width;
|
|
sharedToolbar.setBounds({
|
|
x: layoutBox.x,
|
|
y: layoutBox.y,
|
|
width
|
|
});
|
|
layoutBox.shrink({ left: width + sharedToolbar.horizontalSpacing + (padding2 ?? 0) });
|
|
},
|
|
addToolbarListener: (eventType, handler) => {
|
|
return sharedToolbar.addToolbarListener(eventType, (sharedEvent) => {
|
|
const sectionIndex = this.getSectionIndex(section, sharedEvent.button.index);
|
|
if (sectionIndex < 0)
|
|
return;
|
|
const event = {
|
|
...sharedEvent,
|
|
button: this.sectionButtons[section][sectionIndex]
|
|
};
|
|
handler(event);
|
|
});
|
|
},
|
|
updateButtons: (buttons) => {
|
|
this.sectionButtons[section] = buttons;
|
|
const sharedButtons = _SharedToolbar.SECTION_ORDER.flatMap((order) => this.sectionButtons[order]);
|
|
sharedToolbar.updateButtons(sharedButtons);
|
|
},
|
|
updateButtonByIndex: (index, button) => {
|
|
sharedToolbar.updateButtonByIndex(this.getIndex(section, index), button);
|
|
},
|
|
toggleActiveButtonByIndex: (index) => {
|
|
sharedToolbar.toggleActiveButtonByIndex(this.getIndex(section, index));
|
|
},
|
|
toggleButtonEnabledByIndex: (index, enabled) => {
|
|
sharedToolbar.toggleButtonEnabledByIndex(this.getIndex(section, index), enabled);
|
|
},
|
|
setHidden: (hidden) => {
|
|
if (hidden) {
|
|
this.activeSections.delete(section);
|
|
} else {
|
|
this.activeSections.add(section);
|
|
}
|
|
let sum = 0;
|
|
for (const order of _SharedToolbar.SECTION_ORDER) {
|
|
if (order !== section) {
|
|
sum += this.sectionButtons[order].length;
|
|
continue;
|
|
}
|
|
for (const index of this.sectionButtons[section].keys()) {
|
|
sharedToolbar.setButtonHiddenByIndex(sum + index, hidden);
|
|
}
|
|
}
|
|
},
|
|
destroy: () => {
|
|
withSection.setHidden(true);
|
|
if (this.activeSections.size === 0) {
|
|
this.destroy();
|
|
}
|
|
},
|
|
clearActiveButton: sharedToolbar.clearActiveButton.bind(sharedToolbar),
|
|
addListener: sharedToolbar.addListener.bind(sharedToolbar),
|
|
removeListener: sharedToolbar.removeListener.bind(sharedToolbar)
|
|
};
|
|
withSection.setHidden(false);
|
|
return withSection;
|
|
}
|
|
getIndex(section, index) {
|
|
let sum = 0;
|
|
for (const order of _SharedToolbar.SECTION_ORDER) {
|
|
if (order === section)
|
|
return sum + index;
|
|
sum += this.sectionButtons[order].length;
|
|
}
|
|
return -1;
|
|
}
|
|
getSectionIndex(section, index) {
|
|
let sum = 0;
|
|
for (const order of _SharedToolbar.SECTION_ORDER) {
|
|
if (order === section) {
|
|
if (index >= sum + this.sectionButtons[section].length)
|
|
return -1;
|
|
return index - sum;
|
|
}
|
|
sum += this.sectionButtons[order].length;
|
|
}
|
|
return -1;
|
|
}
|
|
};
|
|
_SharedToolbar.SECTION_ORDER = ["chartToolbar", "annotations"];
|
|
var SharedToolbar = _SharedToolbar;
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/annotations.ts
|
|
import {
|
|
_ModuleSupport as _ModuleSupport64
|
|
} from "ag-charts-community";
|
|
import {
|
|
AbstractModuleInstance as AbstractModuleInstance4,
|
|
ChartAxisDirection as ChartAxisDirection9,
|
|
ChartUpdateType as ChartUpdateType3,
|
|
ObserveChanges as ObserveChanges3,
|
|
PropertiesArray as PropertiesArray3,
|
|
Property as Property37,
|
|
Vec2 as Vec219,
|
|
isValidDate
|
|
} from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/features/text-input/textInput.ts
|
|
import { _ModuleSupport as _ModuleSupport23 } from "ag-charts-community";
|
|
import { CleanupRegistry, attachListener, ceilTo, focusCursorAtEnd, setAttributes } from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/features/text-input/textInputTemplate.html
|
|
var textInputTemplate_default = '<div contenteditable="plaintext-only" class="ag-charts-text-input__textarea" tabindex="0"></div>';
|
|
|
|
// packages/ag-charts-enterprise/src/features/text-input/textInput.ts
|
|
var moduleId = "text-input";
|
|
var canvasOverlay = "canvas-overlay";
|
|
var TextInput = class {
|
|
constructor(ctx) {
|
|
this.ctx = ctx;
|
|
this.cleanup = new CleanupRegistry();
|
|
this.layout = {
|
|
getTextInputCoords: () => ({ x: 0, y: 0 }),
|
|
getTextPosition: () => "center",
|
|
alignment: "center",
|
|
textAlign: "center"
|
|
};
|
|
this.visible = false;
|
|
this.element = ctx.domManager.addChild(canvasOverlay, moduleId);
|
|
this.element.classList.add("ag-charts-text-input");
|
|
this.cleanup.register(() => ctx.domManager.removeChild(canvasOverlay, moduleId));
|
|
}
|
|
setKeyDownHandler(handler) {
|
|
this.cleanup.register(attachListener(this.element, "keydown", handler));
|
|
}
|
|
show(opts) {
|
|
this.element.innerHTML = textInputTemplate_default;
|
|
const textArea = this.element.firstElementChild;
|
|
setAttributes(textArea, {
|
|
role: "textbox",
|
|
// AG-15233
|
|
"data-preventdefault": false
|
|
// AG-13715
|
|
});
|
|
if (!textArea.isContentEditable) {
|
|
textArea.contentEditable = "true";
|
|
}
|
|
textArea.setAttribute(
|
|
"placeholder",
|
|
this.ctx.localeManager.t(opts.placeholderText ?? "inputTextareaPlaceholder")
|
|
);
|
|
if (opts.styles?.placeholderColor) {
|
|
textArea.style.setProperty("--placeholder-text-color", opts.styles?.placeholderColor);
|
|
}
|
|
textArea.innerText = opts.text ?? "";
|
|
textArea.style.color = opts.styles?.color ?? "inherit";
|
|
textArea.style.fontFamily = opts.styles?.fontFamily ?? "inherit";
|
|
textArea.style.fontSize = opts.styles?.fontSize ? `${opts.styles.fontSize}px` : "inherit";
|
|
textArea.style.fontStyle = opts.styles?.fontStyle ?? "inherit";
|
|
textArea.style.fontWeight = typeof opts.styles?.fontWeight === "number" ? `${opts.styles.fontWeight}` : opts.styles?.fontWeight ?? "inherit";
|
|
focusCursorAtEnd(textArea);
|
|
textArea.addEventListener("input", () => {
|
|
this.updatePosition();
|
|
opts.onChange?.(this.getValue(), this.getBBox());
|
|
});
|
|
textArea.addEventListener("click", (event) => {
|
|
event.stopPropagation();
|
|
});
|
|
if (opts.layout) {
|
|
this.layout = opts.layout;
|
|
this.updatePosition();
|
|
}
|
|
opts.onChange?.(this.getValue(), this.getBBox());
|
|
this.visible = true;
|
|
}
|
|
hide() {
|
|
this.element.innerHTML = "";
|
|
this.layout = {
|
|
getTextInputCoords: () => ({ x: 0, y: 0 }),
|
|
getTextPosition: () => "center",
|
|
alignment: "center",
|
|
textAlign: "center"
|
|
};
|
|
this.visible = false;
|
|
}
|
|
isVisible() {
|
|
return this.visible;
|
|
}
|
|
updateColor(color7) {
|
|
if (!this.element.firstElementChild)
|
|
return;
|
|
this.element.firstElementChild.style.color = color7;
|
|
}
|
|
updateFontSize(fontSize) {
|
|
if (!this.element.firstElementChild)
|
|
return;
|
|
this.element.firstElementChild.style.fontSize = `${fontSize}px`;
|
|
this.updatePosition();
|
|
return this.getBBox();
|
|
}
|
|
getValue() {
|
|
if (!this.element.firstElementChild)
|
|
return;
|
|
return this.element.firstElementChild.innerText.trim();
|
|
}
|
|
updatePosition() {
|
|
const { element } = this;
|
|
const textArea = element.firstElementChild;
|
|
if (!textArea)
|
|
return;
|
|
const sceneRect = this.ctx.domManager.getBoundingClientRect();
|
|
const { width, getTextInputCoords, getTextPosition, alignment, textAlign } = this.layout;
|
|
element.style.setProperty("width", width ? `${width}px` : "unset");
|
|
const textRect = textArea.getBoundingClientRect();
|
|
const point = getTextInputCoords(textRect.height);
|
|
let horizontalPosition = point.x;
|
|
if (alignment === "center") {
|
|
horizontalPosition -= (width ?? textRect.width) / 2;
|
|
} else if (alignment === "right") {
|
|
horizontalPosition -= width ?? textRect.width;
|
|
}
|
|
const position = getTextPosition();
|
|
let verticalPosition = point.y;
|
|
if (position === "center") {
|
|
verticalPosition -= textRect.height / 2;
|
|
} else if (position === "bottom") {
|
|
verticalPosition -= textRect.height;
|
|
}
|
|
element.style.setProperty("top", `${verticalPosition}px`);
|
|
element.style.setProperty("left", `${horizontalPosition}px`);
|
|
element.style.setProperty("max-width", `${sceneRect.width - horizontalPosition}px`);
|
|
element.style.setProperty("text-align", alignment);
|
|
textArea.style.setProperty("text-align", textAlign);
|
|
}
|
|
getBBox() {
|
|
const { left, top, width, height } = this.element.getBoundingClientRect();
|
|
return new _ModuleSupport23.BBox(left, top, ceilTo(width, 2), height);
|
|
}
|
|
destroy() {
|
|
this.cleanup.flush();
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/annotationAxesButtons.ts
|
|
import { BaseProperties as BaseProperties3, Property as Property15 } from "ag-charts-core";
|
|
var AxesButtons = class extends BaseProperties3 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.enabled = false;
|
|
this.axes = "y";
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property15
|
|
], AxesButtons.prototype, "enabled", 2);
|
|
__decorateClass([
|
|
Property15
|
|
], AxesButtons.prototype, "axes", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/annotationDefaults.ts
|
|
import "ag-charts-community";
|
|
import { deepClone } from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/annotationTypes.ts
|
|
var AnnotationType = /* @__PURE__ */ ((AnnotationType2) => {
|
|
AnnotationType2["Line"] = "line";
|
|
AnnotationType2["HorizontalLine"] = "horizontal-line";
|
|
AnnotationType2["VerticalLine"] = "vertical-line";
|
|
AnnotationType2["DisjointChannel"] = "disjoint-channel";
|
|
AnnotationType2["ParallelChannel"] = "parallel-channel";
|
|
AnnotationType2["FibonacciRetracement"] = "fibonacci-retracement";
|
|
AnnotationType2["FibonacciRetracementTrendBased"] = "fibonacci-retracement-trend-based";
|
|
AnnotationType2["Callout"] = "callout";
|
|
AnnotationType2["Comment"] = "comment";
|
|
AnnotationType2["Note"] = "note";
|
|
AnnotationType2["Text"] = "text";
|
|
AnnotationType2["Arrow"] = "arrow";
|
|
AnnotationType2["ArrowUp"] = "arrow-up";
|
|
AnnotationType2["ArrowDown"] = "arrow-down";
|
|
AnnotationType2["DateRange"] = "date-range";
|
|
AnnotationType2["PriceRange"] = "price-range";
|
|
AnnotationType2["DatePriceRange"] = "date-price-range";
|
|
AnnotationType2["QuickDatePriceRange"] = "quick-date-price-range";
|
|
return AnnotationType2;
|
|
})(AnnotationType || {});
|
|
var ANNOTATION_TYPES = Object.values(AnnotationType);
|
|
function stringToAnnotationType(value) {
|
|
for (const t of ANNOTATION_TYPES) {
|
|
if (t === value)
|
|
return t;
|
|
}
|
|
}
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/utils/has.ts
|
|
import { isObject as isObject12 } from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/callout/calloutProperties.ts
|
|
import { Color, Property as Property18, isObject } from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/annotationProperties.ts
|
|
import "ag-charts-community";
|
|
import { BaseProperties as BaseProperties4, FONT_SIZE, Property as Property16, generateUUID } from "ag-charts-core";
|
|
var PointProperties = class extends BaseProperties4 {
|
|
};
|
|
__decorateClass([
|
|
Property16
|
|
], PointProperties.prototype, "x", 2);
|
|
__decorateClass([
|
|
Property16
|
|
], PointProperties.prototype, "y", 2);
|
|
var ChannelAnnotationMiddleProperties = class extends Stroke(LineStyle(Visible(BaseProperties4))) {
|
|
};
|
|
var AxisLabelProperties = class extends Stroke(LineStyle(Fill(Label(Font(BaseProperties4))))) {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.cornerRadius = 2;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property16
|
|
], AxisLabelProperties.prototype, "enabled", 2);
|
|
__decorateClass([
|
|
Property16
|
|
], AxisLabelProperties.prototype, "cornerRadius", 2);
|
|
var BackgroundProperties = class extends Fill(BaseProperties4) {
|
|
};
|
|
var HandleProperties = class extends Stroke(LineStyle(Fill(BaseProperties4))) {
|
|
};
|
|
var LineTextProperties = class extends Font(BaseProperties4) {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.label = "";
|
|
this.position = "top";
|
|
this.alignment = "left";
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property16
|
|
], LineTextProperties.prototype, "label", 2);
|
|
__decorateClass([
|
|
Property16
|
|
], LineTextProperties.prototype, "position", 2);
|
|
__decorateClass([
|
|
Property16
|
|
], LineTextProperties.prototype, "alignment", 2);
|
|
var LabelTextProperties = class extends Font(BaseProperties4) {
|
|
};
|
|
var ChannelTextProperties = class extends Font(BaseProperties4) {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.label = "";
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property16
|
|
], ChannelTextProperties.prototype, "label", 2);
|
|
__decorateClass([
|
|
Property16
|
|
], ChannelTextProperties.prototype, "position", 2);
|
|
__decorateClass([
|
|
Property16
|
|
], ChannelTextProperties.prototype, "alignment", 2);
|
|
function Annotation(Parent) {
|
|
class AnnotationInternal extends Writeable(Visible(Parent)) {
|
|
constructor() {
|
|
super(...arguments);
|
|
// A uuid is required, over the usual incrementing index, as annotations can be restored from external databases
|
|
this.id = generateUUID();
|
|
}
|
|
}
|
|
return AnnotationInternal;
|
|
}
|
|
function Line3(Parent) {
|
|
class LineInternal extends Parent {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.start = new PointProperties();
|
|
this.end = new PointProperties();
|
|
}
|
|
}
|
|
__decorateClass([
|
|
Property16
|
|
], LineInternal.prototype, "start", 2);
|
|
__decorateClass([
|
|
Property16
|
|
], LineInternal.prototype, "end", 2);
|
|
return LineInternal;
|
|
}
|
|
function Point(Parent) {
|
|
class PointInternal extends Parent {
|
|
}
|
|
__decorateClass([
|
|
Property16
|
|
], PointInternal.prototype, "x", 2);
|
|
__decorateClass([
|
|
Property16
|
|
], PointInternal.prototype, "y", 2);
|
|
return PointInternal;
|
|
}
|
|
function Value(Parent) {
|
|
class ValueInternal extends Parent {
|
|
}
|
|
__decorateClass([
|
|
Property16
|
|
], ValueInternal.prototype, "value", 2);
|
|
return ValueInternal;
|
|
}
|
|
function Background2(Parent) {
|
|
class BackgroundInternal extends Parent {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.background = new BackgroundProperties();
|
|
}
|
|
}
|
|
__decorateClass([
|
|
Property16
|
|
], BackgroundInternal.prototype, "background", 2);
|
|
return BackgroundInternal;
|
|
}
|
|
function Handle(Parent) {
|
|
class HandleInternal extends Parent {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.handle = new HandleProperties();
|
|
}
|
|
}
|
|
__decorateClass([
|
|
Property16
|
|
], HandleInternal.prototype, "handle", 2);
|
|
return HandleInternal;
|
|
}
|
|
function AxisLabel(Parent) {
|
|
class AxisLabelInternal extends Parent {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.axisLabel = new AxisLabelProperties();
|
|
}
|
|
}
|
|
__decorateClass([
|
|
Property16
|
|
], AxisLabelInternal.prototype, "axisLabel", 2);
|
|
return AxisLabelInternal;
|
|
}
|
|
function Label(Parent) {
|
|
class LabelInternal extends Parent {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.padding = void 0;
|
|
this.textAlign = "center";
|
|
this.formatter = void 0;
|
|
}
|
|
// TODO: making this generic causes issues with mixins sequence
|
|
}
|
|
__decorateClass([
|
|
Property16
|
|
], LabelInternal.prototype, "padding", 2);
|
|
__decorateClass([
|
|
Property16
|
|
], LabelInternal.prototype, "textAlign", 2);
|
|
__decorateClass([
|
|
Property16
|
|
], LabelInternal.prototype, "formatter", 2);
|
|
return LabelInternal;
|
|
}
|
|
function Cappable(Parent) {
|
|
class CappableInternal extends Parent {
|
|
}
|
|
return CappableInternal;
|
|
}
|
|
function Extendable(Parent) {
|
|
class ExtendableInternal extends Parent {
|
|
}
|
|
__decorateClass([
|
|
Property16
|
|
], ExtendableInternal.prototype, "extendStart", 2);
|
|
__decorateClass([
|
|
Property16
|
|
], ExtendableInternal.prototype, "extendEnd", 2);
|
|
return ExtendableInternal;
|
|
}
|
|
function Writeable(Parent) {
|
|
class WriteableInternal extends Parent {
|
|
isWriteable() {
|
|
return !this.locked && !this.readOnly;
|
|
}
|
|
isHoverable() {
|
|
return !this.readOnly;
|
|
}
|
|
}
|
|
__decorateClass([
|
|
Property16
|
|
], WriteableInternal.prototype, "locked", 2);
|
|
__decorateClass([
|
|
Property16
|
|
], WriteableInternal.prototype, "readOnly", 2);
|
|
return WriteableInternal;
|
|
}
|
|
function Localisable(Parent) {
|
|
class LocalisableInternal extends Parent {
|
|
setLocaleManager(localeManager) {
|
|
this.localeManager ?? (this.localeManager = localeManager);
|
|
}
|
|
}
|
|
return LocalisableInternal;
|
|
}
|
|
function Visible(Parent) {
|
|
class VisibleInternal extends Parent {
|
|
}
|
|
__decorateClass([
|
|
Property16
|
|
], VisibleInternal.prototype, "visible", 2);
|
|
return VisibleInternal;
|
|
}
|
|
function Fill(Parent) {
|
|
class FillInternal extends Parent {
|
|
}
|
|
__decorateClass([
|
|
Property16
|
|
], FillInternal.prototype, "fill", 2);
|
|
__decorateClass([
|
|
Property16
|
|
], FillInternal.prototype, "fillOpacity", 2);
|
|
return FillInternal;
|
|
}
|
|
function Stroke(Parent) {
|
|
class StrokeInternal extends Parent {
|
|
}
|
|
__decorateClass([
|
|
Property16
|
|
], StrokeInternal.prototype, "stroke", 2);
|
|
__decorateClass([
|
|
Property16
|
|
], StrokeInternal.prototype, "strokeOpacity", 2);
|
|
__decorateClass([
|
|
Property16
|
|
], StrokeInternal.prototype, "strokeWidth", 2);
|
|
return StrokeInternal;
|
|
}
|
|
function LineStyle(Parent) {
|
|
class LineDashInternal extends Parent {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.lineCap = void 0;
|
|
this.computedLineDash = void 0;
|
|
}
|
|
}
|
|
__decorateClass([
|
|
Property16
|
|
], LineDashInternal.prototype, "lineDash", 2);
|
|
__decorateClass([
|
|
Property16
|
|
], LineDashInternal.prototype, "lineDashOffset", 2);
|
|
__decorateClass([
|
|
Property16
|
|
], LineDashInternal.prototype, "lineStyle", 2);
|
|
return LineDashInternal;
|
|
}
|
|
function Font(Parent) {
|
|
class FontInternal extends Parent {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.fontSize = FONT_SIZE.SMALL;
|
|
this.fontFamily = "Verdana, sans-serif";
|
|
}
|
|
}
|
|
__decorateClass([
|
|
Property16
|
|
], FontInternal.prototype, "fontStyle", 2);
|
|
__decorateClass([
|
|
Property16
|
|
], FontInternal.prototype, "fontWeight", 2);
|
|
__decorateClass([
|
|
Property16
|
|
], FontInternal.prototype, "fontSize", 2);
|
|
__decorateClass([
|
|
Property16
|
|
], FontInternal.prototype, "fontFamily", 2);
|
|
__decorateClass([
|
|
Property16
|
|
], FontInternal.prototype, "color", 2);
|
|
return FontInternal;
|
|
}
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/properties/textualStartEndProperties.ts
|
|
import { Property as Property17 } from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/utils/scale.ts
|
|
import { isDate, isNumber, isString } from "ag-charts-core";
|
|
function getGrouping(d) {
|
|
if (isNumber(d) || isString(d) || isDate(d)) {
|
|
return { value: d, groupPercentage: 0 };
|
|
}
|
|
return d ?? { value: void 0, groupPercentage: 0 };
|
|
}
|
|
function getGroupingValue(d) {
|
|
return getGrouping(d)?.value;
|
|
}
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/utils/values.ts
|
|
function convertLine(datum, context) {
|
|
if (datum.start == null || datum.end == null)
|
|
return;
|
|
const start = convertPoint(datum.start, context);
|
|
const end = convertPoint(datum.end, context);
|
|
if (start == null || end == null)
|
|
return;
|
|
return { x1: start.x, y1: start.y, x2: end.x, y2: end.y };
|
|
}
|
|
function convertPoint(point, context) {
|
|
const x = convert(point.x, context.xAxis);
|
|
const y = convert(point.y, context.yAxis);
|
|
return { x, y };
|
|
}
|
|
function convert(p, context) {
|
|
if (p == null)
|
|
return 0;
|
|
const { value, groupPercentage } = getGrouping(p);
|
|
const { scale, snapToGroup } = context;
|
|
const width = scale.bandwidth === 0 ? scale.step ?? 0 : scale.bandwidth ?? 0;
|
|
const offset = snapToGroup ? width / 2 : width * groupPercentage;
|
|
return scale.convert(value) + offset;
|
|
}
|
|
function invertCoords(coords, context) {
|
|
const x = invert(coords.x, context.xAxis);
|
|
const y = invert(coords.y, context.yAxis);
|
|
return { x, y };
|
|
}
|
|
function invert(n, context) {
|
|
const { scale } = context;
|
|
if (context.continuous && scale.step == null) {
|
|
return context.scaleInvert(n);
|
|
}
|
|
const value = context.scaleInvertNearest(n);
|
|
const width = scale.bandwidth === 0 ? scale.step : scale.bandwidth ?? 0;
|
|
const bandStart = scale.convert(value);
|
|
const bandEnd = bandStart + width;
|
|
const groupPercentage = bandStart === bandEnd ? 0 : (n - bandStart) / (bandEnd - bandStart);
|
|
return { value, groupPercentage };
|
|
}
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/properties/startEndProperties.ts
|
|
import { BaseProperties as BaseProperties5 } from "ag-charts-core";
|
|
var StartEndProperties = class extends Annotation(Line3(Handle(BaseProperties5))) {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.snapToAngle = 45;
|
|
}
|
|
getDefaultColor(_colorPickerType) {
|
|
return void 0;
|
|
}
|
|
getDefaultOpacity(_colorPickerType) {
|
|
return void 0;
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/properties/textualStartEndProperties.ts
|
|
var TextualStartEndProperties = class extends Localisable(Label(Font(StartEndProperties))) {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.text = "";
|
|
this.position = "top";
|
|
this.alignment = "left";
|
|
this.placement = "inside";
|
|
this.placeholderText = "inputTextareaPlaceholder";
|
|
}
|
|
getDefaultColor(_colorPickerType) {
|
|
return this.color;
|
|
}
|
|
getDefaultOpacity(_colorPickerType) {
|
|
return void 0;
|
|
}
|
|
getPlaceholderColor() {
|
|
return void 0;
|
|
}
|
|
getPadding() {
|
|
const { padding: padding2 = 0 } = this;
|
|
return {
|
|
top: padding2,
|
|
right: padding2,
|
|
bottom: padding2,
|
|
left: padding2
|
|
};
|
|
}
|
|
getText() {
|
|
const isPlaceholder = this.text.length == 0;
|
|
let text2 = this.text;
|
|
if (isPlaceholder) {
|
|
text2 = this.placeholderText ?? "";
|
|
if (this.localeManager)
|
|
text2 = this.localeManager.t(text2);
|
|
}
|
|
return {
|
|
text: text2,
|
|
isPlaceholder
|
|
};
|
|
}
|
|
getTextInputCoords(context, _height) {
|
|
return convertPoint(this.end, context);
|
|
}
|
|
getTextPosition() {
|
|
return this.position;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property17
|
|
], TextualStartEndProperties.prototype, "text", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/callout/calloutProperties.ts
|
|
var DEFAULT_CALLOUT_PADDING = {
|
|
top: 6,
|
|
right: 12,
|
|
bottom: 9,
|
|
left: 12
|
|
};
|
|
var CalloutProperties = class extends Fill(Stroke(TextualStartEndProperties)) {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.type = "callout" /* Callout */;
|
|
this.position = "bottom";
|
|
this.alignment = "left";
|
|
}
|
|
static is(value) {
|
|
return isObject(value) && value.type === "callout" /* Callout */;
|
|
}
|
|
getDefaultColor(colorPickerType) {
|
|
switch (colorPickerType) {
|
|
case `fill-color`:
|
|
return this.fill;
|
|
case `line-color`:
|
|
return this.stroke;
|
|
case `text-color`:
|
|
default:
|
|
return this.color;
|
|
}
|
|
}
|
|
getDefaultOpacity(colorPickerType) {
|
|
switch (colorPickerType) {
|
|
case `fill-color`:
|
|
return this.fillOpacity;
|
|
case `line-color`:
|
|
return this.strokeOpacity;
|
|
case `text-color`:
|
|
default:
|
|
return void 0;
|
|
}
|
|
}
|
|
getPlaceholderColor() {
|
|
const { r, g, b } = Color.fromString(this.color ?? "#888888");
|
|
return new Color(r, g, b, 0.66).toString();
|
|
}
|
|
getPadding() {
|
|
const { padding: padding2 } = this;
|
|
if (padding2 == null) {
|
|
return { ...DEFAULT_CALLOUT_PADDING };
|
|
}
|
|
return {
|
|
top: padding2,
|
|
right: padding2,
|
|
bottom: padding2,
|
|
left: padding2
|
|
};
|
|
}
|
|
getTextInputCoords(context, height) {
|
|
const coords = super.getTextInputCoords(context, height);
|
|
const padding2 = this.getPadding();
|
|
const paddingLeft = padding2.left ?? 0;
|
|
const paddingBottom = padding2.bottom ?? 0;
|
|
return {
|
|
x: coords.x + paddingLeft,
|
|
y: coords.y - paddingBottom
|
|
};
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property18
|
|
], CalloutProperties.prototype, "type", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/comment/commentProperties.ts
|
|
import { Color as Color2, Property as Property20, isObject as isObject2 } from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/properties/textualPointProperties.ts
|
|
import { BaseProperties as BaseProperties6, Property as Property19 } from "ag-charts-core";
|
|
var TextualPointProperties = class extends Annotation(Point(Handle(Label(Font(BaseProperties6))))) {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.text = "";
|
|
this.position = "top";
|
|
this.alignment = "left";
|
|
this.placement = "inside";
|
|
this.placeholderText = "inputTextareaPlaceholder";
|
|
}
|
|
getDefaultColor(_colorPickerType) {
|
|
return this.color;
|
|
}
|
|
getDefaultOpacity(_colorPickerType) {
|
|
return void 0;
|
|
}
|
|
getPlaceholderColor() {
|
|
return void 0;
|
|
}
|
|
getPadding() {
|
|
const { padding: padding2 = 0 } = this;
|
|
return {
|
|
top: padding2,
|
|
right: padding2,
|
|
bottom: padding2,
|
|
left: padding2
|
|
};
|
|
}
|
|
getText() {
|
|
const isPlaceholder = this.text.length == 0;
|
|
const text2 = isPlaceholder ? this.placeholderText ?? "" : this.text;
|
|
return {
|
|
text: text2,
|
|
isPlaceholder
|
|
};
|
|
}
|
|
getTextInputCoords(context, _height) {
|
|
return convertPoint(this, context);
|
|
}
|
|
getTextPosition() {
|
|
return this.position;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property19
|
|
], TextualPointProperties.prototype, "text", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/comment/commentProperties.ts
|
|
var DEFAULT_COMMENT_PADDING = {
|
|
top: 8,
|
|
right: 14,
|
|
bottom: 8,
|
|
left: 14
|
|
};
|
|
var CommentProperties = class extends Fill(Stroke(TextualPointProperties)) {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.type = "comment" /* Comment */;
|
|
this.position = "bottom";
|
|
this.alignment = "left";
|
|
}
|
|
static is(value) {
|
|
return isObject2(value) && value.type === "comment" /* Comment */;
|
|
}
|
|
getDefaultColor(colorPickerType) {
|
|
switch (colorPickerType) {
|
|
case `fill-color`:
|
|
return this.fill;
|
|
case `line-color`:
|
|
return this.stroke;
|
|
case `text-color`:
|
|
default:
|
|
return this.color;
|
|
}
|
|
}
|
|
getDefaultOpacity(colorPickerType) {
|
|
switch (colorPickerType) {
|
|
case `fill-color`:
|
|
return this.fillOpacity;
|
|
case `line-color`:
|
|
return this.strokeOpacity;
|
|
case `text-color`:
|
|
default:
|
|
return void 0;
|
|
}
|
|
}
|
|
getPlaceholderColor() {
|
|
const { r, g, b } = Color2.fromString(this.color ?? "#888888");
|
|
return new Color2(r, g, b, 0.66).toString();
|
|
}
|
|
getPadding() {
|
|
const { padding: padding2, fontSize } = this;
|
|
if (padding2 == null) {
|
|
return {
|
|
top: Math.max(fontSize * 0.4, DEFAULT_COMMENT_PADDING.top),
|
|
bottom: Math.max(fontSize * 0.4, DEFAULT_COMMENT_PADDING.bottom),
|
|
left: Math.max(fontSize * 0.8, DEFAULT_COMMENT_PADDING.left),
|
|
right: Math.max(fontSize * 0.8, DEFAULT_COMMENT_PADDING.right)
|
|
};
|
|
}
|
|
return {
|
|
top: padding2,
|
|
right: padding2,
|
|
bottom: padding2,
|
|
left: padding2
|
|
};
|
|
}
|
|
getTextInputCoords(context, height) {
|
|
const coords = super.getTextInputCoords(context, height);
|
|
const padding2 = this.getPadding();
|
|
return {
|
|
x: coords.x + padding2.left,
|
|
y: coords.y - padding2.bottom
|
|
};
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property20
|
|
], CommentProperties.prototype, "type", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/measurer/measurerProperties.ts
|
|
import "ag-charts-community";
|
|
import { BaseProperties as BaseProperties7, Property as Property21, isObject as isObject3 } from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/utils/line.ts
|
|
import { Vec2 } from "ag-charts-core";
|
|
function getLineStyle(lineDash, lineStyle) {
|
|
return lineDash ? "dashed" : lineStyle ?? "solid";
|
|
}
|
|
function getComputedLineDash(strokeWidth, styleType) {
|
|
switch (styleType) {
|
|
case "solid":
|
|
return [];
|
|
case "dashed":
|
|
return [strokeWidth * 4, strokeWidth * 2];
|
|
case "dotted":
|
|
return [0, strokeWidth * 2];
|
|
}
|
|
}
|
|
function getLineDash(lineDash, computedLineDash, lineStyle, strokeWidth) {
|
|
const styleType = getLineStyle(lineDash, lineStyle);
|
|
return computedLineDash ?? lineDash ?? getComputedLineDash(strokeWidth ?? 1, styleType);
|
|
}
|
|
function getLineCap(lineCap, lineDash, lineStyle) {
|
|
const styleType = getLineStyle(lineDash, lineStyle);
|
|
return lineCap ?? styleType === "dotted" ? "round" : void 0;
|
|
}
|
|
function boundsIntersections(coords, bounds) {
|
|
const [p1, p2] = Vec2.from(coords);
|
|
const reflection = bounds.height;
|
|
const gradient = Vec2.gradient(p2, p1, reflection);
|
|
const intercept = Vec2.intercept(p2, gradient, reflection);
|
|
const fallback = [
|
|
{ x: p1.x, y: reflection ?? 0 },
|
|
{ x: p1.x, y: reflection == null ? bounds.height : reflection - bounds.height }
|
|
];
|
|
if (gradient === Infinity) {
|
|
return fallback;
|
|
}
|
|
let points = [
|
|
Vec2.intersectAtY(gradient, intercept, 0, reflection),
|
|
Vec2.intersectAtY(gradient, intercept, bounds.height, reflection),
|
|
Vec2.intersectAtX(gradient, intercept, 0, reflection),
|
|
Vec2.intersectAtX(gradient, intercept, bounds.width, reflection)
|
|
];
|
|
points = points.filter((p) => p.x >= bounds.x && p.x <= bounds.width && p.y >= bounds.y && p.y <= bounds.height).sort((a, b) => {
|
|
if (a.x === b.x)
|
|
return 0;
|
|
return a.x < b.x ? -1 : 1;
|
|
});
|
|
if (points.length !== 2) {
|
|
return fallback;
|
|
}
|
|
return points;
|
|
}
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/measurer/measurerProperties.ts
|
|
var MeasurerStatisticsDivider = class extends Stroke(BaseProperties7) {
|
|
};
|
|
var MeasurerStatistics = class extends Font(Fill(Stroke(BaseProperties7))) {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.divider = new MeasurerStatisticsDivider();
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property21
|
|
], MeasurerStatistics.prototype, "divider", 2);
|
|
var MeasurerDirectionProperties = class extends Fill(Stroke(Handle(BaseProperties7))) {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.statistics = new MeasurerStatistics();
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property21
|
|
], MeasurerDirectionProperties.prototype, "statistics", 2);
|
|
var MeasurerTypeProperties = class extends Localisable(Background2(Stroke(LineStyle(StartEndProperties)))) {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.direction = "both";
|
|
this.hasDateRange = false;
|
|
this.hasPriceRange = false;
|
|
this.statistics = new MeasurerStatistics();
|
|
this.getVolume = () => void 0;
|
|
this.text = new LineTextProperties();
|
|
}
|
|
getDefaultColor(colorPickerType) {
|
|
switch (colorPickerType) {
|
|
case `fill-color`:
|
|
return this.background.fill;
|
|
case `line-color`:
|
|
return this.stroke;
|
|
case `text-color`:
|
|
return this.text.color;
|
|
}
|
|
}
|
|
getDefaultOpacity(colorPickerType) {
|
|
switch (colorPickerType) {
|
|
case `fill-color`:
|
|
return this.background.fillOpacity;
|
|
case `line-color`:
|
|
return this.strokeOpacity;
|
|
}
|
|
}
|
|
getLineDash() {
|
|
return getLineDash(this.lineDash, this.computedLineDash, this.lineStyle, this.strokeWidth);
|
|
}
|
|
getLineCap() {
|
|
return getLineCap(this.lineCap, this.lineDash, this.lineStyle);
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property21
|
|
], MeasurerTypeProperties.prototype, "statistics", 2);
|
|
__decorateClass([
|
|
Property21
|
|
], MeasurerTypeProperties.prototype, "text", 2);
|
|
function DateRange(Parent) {
|
|
class DateRangeInternal extends Parent {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.hasDateRange = true;
|
|
}
|
|
}
|
|
return DateRangeInternal;
|
|
}
|
|
function PriceRange(Parent) {
|
|
class PriceRangeInternal extends Parent {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.hasPriceRange = true;
|
|
}
|
|
}
|
|
return PriceRangeInternal;
|
|
}
|
|
var DateRangeProperties = class extends DateRange(MeasurerTypeProperties) {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.type = "date-range" /* DateRange */;
|
|
this.direction = "horizontal";
|
|
}
|
|
static is(value) {
|
|
return isObject3(value) && value.type === "date-range" /* DateRange */;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property21
|
|
], DateRangeProperties.prototype, "type", 2);
|
|
__decorateClass([
|
|
Property21
|
|
], DateRangeProperties.prototype, "extendAbove", 2);
|
|
__decorateClass([
|
|
Property21
|
|
], DateRangeProperties.prototype, "extendBelow", 2);
|
|
var PriceRangeProperties = class extends PriceRange(MeasurerTypeProperties) {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.type = "price-range" /* PriceRange */;
|
|
this.direction = "vertical";
|
|
}
|
|
static is(value) {
|
|
return isObject3(value) && value.type === "price-range" /* PriceRange */;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property21
|
|
], PriceRangeProperties.prototype, "type", 2);
|
|
__decorateClass([
|
|
Property21
|
|
], PriceRangeProperties.prototype, "extendLeft", 2);
|
|
__decorateClass([
|
|
Property21
|
|
], PriceRangeProperties.prototype, "extendRight", 2);
|
|
var DatePriceRangeProperties = class extends DateRange(PriceRange(MeasurerTypeProperties)) {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.type = "date-price-range" /* DatePriceRange */;
|
|
this.direction = "both";
|
|
}
|
|
static is(value) {
|
|
return isObject3(value) && value.type === "date-price-range" /* DatePriceRange */;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property21
|
|
], DatePriceRangeProperties.prototype, "type", 2);
|
|
var QuickDatePriceRangeProperties = class extends DateRange(PriceRange(MeasurerTypeProperties)) {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.type = "quick-date-price-range" /* QuickDatePriceRange */;
|
|
this.up = new MeasurerDirectionProperties();
|
|
this.down = new MeasurerDirectionProperties();
|
|
this.direction = "both";
|
|
}
|
|
static is(value) {
|
|
return isObject3(value) && value.type === "quick-date-price-range" /* QuickDatePriceRange */;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property21
|
|
], QuickDatePriceRangeProperties.prototype, "type", 2);
|
|
__decorateClass([
|
|
Property21
|
|
], QuickDatePriceRangeProperties.prototype, "up", 2);
|
|
__decorateClass([
|
|
Property21
|
|
], QuickDatePriceRangeProperties.prototype, "down", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/note/noteProperties.ts
|
|
import { BaseProperties as BaseProperties8, Property as Property22, clamp as clamp2, isObject as isObject4 } from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/text/util.ts
|
|
import { _ModuleSupport as _ModuleSupport26 } from "ag-charts-community";
|
|
import { cachedTextMeasurer, calcLineHeight, wrapText } from "ag-charts-core";
|
|
var { BBox: BBox2 } = _ModuleSupport26;
|
|
var ANNOTATION_TEXT_LINE_HEIGHT = 1.38;
|
|
function maybeWrapText(options, text2, maxWidth) {
|
|
return maxWidth ? wrapText(text2, { maxWidth, font: options, textWrap: "always", avoidOrphans: false }) : text2;
|
|
}
|
|
function measureAnnotationText(options, text2) {
|
|
const { lineMetrics, width } = cachedTextMeasurer(options).measureLines(text2);
|
|
const height = lineMetrics.length * calcLineHeight(options.fontSize, ANNOTATION_TEXT_LINE_HEIGHT);
|
|
return { width, height };
|
|
}
|
|
function getBBox(options, text2, coords, bbox) {
|
|
let width = bbox?.width ?? 0;
|
|
let height = bbox?.height ?? 0;
|
|
if (!bbox) {
|
|
const wrappedText = options.width == null ? text2 : maybeWrapText(options, text2, options.width);
|
|
({ width, height } = measureAnnotationText(options, wrappedText));
|
|
}
|
|
return new BBox2(coords.x, coords.y, width, height);
|
|
}
|
|
function updateTextNode(node, text2, isPlaceholder, config, { x, y }, textBaseline) {
|
|
const { visible = true, fontFamily, fontSize = 14, fontStyle, fontWeight, textAlign } = config;
|
|
const lineHeight = calcLineHeight(fontSize, ANNOTATION_TEXT_LINE_HEIGHT);
|
|
textBaseline ?? (textBaseline = config.position == "center" ? "middle" : config.position);
|
|
const fill = isPlaceholder ? config.getPlaceholderColor() : config.color;
|
|
node.setProperties({
|
|
x,
|
|
y,
|
|
visible,
|
|
text: text2,
|
|
fill,
|
|
fontFamily,
|
|
fontSize,
|
|
fontStyle,
|
|
fontWeight,
|
|
textAlign,
|
|
lineHeight,
|
|
textBaseline
|
|
});
|
|
}
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/note/noteProperties.ts
|
|
var DEFAULT_NOTE_PADDING = 10;
|
|
var HANDLE_SIZE = 11;
|
|
var ICON_HEIGHT = 20;
|
|
var ICON_WIDTH = 22;
|
|
var ICON_SPACING = 10;
|
|
var LABEL_OFFSET = ICON_HEIGHT + ICON_SPACING;
|
|
var TOOLBAR_OFFSET = 34;
|
|
var NoteBackgroundProperties = class extends Fill(Stroke(BaseProperties8)) {
|
|
};
|
|
var NoteProperties = class extends Fill(Stroke(TextualPointProperties)) {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.type = "note" /* Note */;
|
|
this.background = new NoteBackgroundProperties();
|
|
this.position = "bottom";
|
|
this.alignment = "center";
|
|
this.width = 200;
|
|
}
|
|
static is(value) {
|
|
return isObject4(value) && value.type === "note" /* Note */;
|
|
}
|
|
getDefaultColor(colorPickerType) {
|
|
switch (colorPickerType) {
|
|
case `line-color`:
|
|
return this.fill;
|
|
case `text-color`:
|
|
return this.color;
|
|
}
|
|
}
|
|
getDefaultOpacity(colorPickerType) {
|
|
switch (colorPickerType) {
|
|
case `line-color`:
|
|
return this.fillOpacity;
|
|
case `text-color`:
|
|
return void 0;
|
|
}
|
|
}
|
|
getPadding() {
|
|
const padding2 = this.padding ?? DEFAULT_NOTE_PADDING;
|
|
return {
|
|
top: padding2,
|
|
right: padding2,
|
|
bottom: padding2,
|
|
left: padding2
|
|
};
|
|
}
|
|
getTextInputCoords(context, height) {
|
|
const { width, text: text2 } = this;
|
|
const textInputCoords = super.getTextInputCoords(context, height);
|
|
const padding2 = this.getPadding().top;
|
|
const bbox = getBBox(this, text2, textInputCoords);
|
|
bbox.x = clamp2(width / 2, bbox.x, context.seriesRect.width - width / 2);
|
|
const topY = bbox.y - LABEL_OFFSET - padding2 * 2;
|
|
const bottomY = bbox.y + HANDLE_SIZE + padding2 * 2;
|
|
const textHeight = Math.max(bbox.height, height);
|
|
if (topY - textHeight - TOOLBAR_OFFSET < 0) {
|
|
bbox.y = bottomY;
|
|
this.position = "top";
|
|
} else {
|
|
bbox.y = topY + padding2;
|
|
this.position = "bottom";
|
|
}
|
|
return {
|
|
x: bbox.x,
|
|
y: bbox.y
|
|
};
|
|
}
|
|
isHoverable() {
|
|
return true;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property22
|
|
], NoteProperties.prototype, "type", 2);
|
|
__decorateClass([
|
|
Property22
|
|
], NoteProperties.prototype, "background", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/properties/pointProperties.ts
|
|
import { BaseProperties as BaseProperties9 } from "ag-charts-core";
|
|
var PointProperties2 = class extends Annotation(Point(Handle(BaseProperties9))) {
|
|
getDefaultColor(_colorPickerType) {
|
|
return void 0;
|
|
}
|
|
getDefaultOpacity(_colorPickerType) {
|
|
return void 0;
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/properties/shapePointProperties.ts
|
|
var ShapePointProperties = class _ShapePointProperties extends Fill(PointProperties2) {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.size = 32;
|
|
}
|
|
static is(value) {
|
|
return value instanceof _ShapePointProperties;
|
|
}
|
|
getDefaultColor(colorPickerType) {
|
|
return colorPickerType === `fill-color` ? this.fill : void 0;
|
|
}
|
|
getDefaultOpacity(colorPickerType) {
|
|
return colorPickerType === `fill-color` ? this.fillOpacity : void 0;
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/cross-line/crossLineProperties.ts
|
|
import "ag-charts-community";
|
|
import { BaseProperties as BaseProperties10, Property as Property23, isObject as isObject5 } from "ag-charts-core";
|
|
var HorizontalLineProperties = class extends Annotation(Value(Handle(AxisLabel(Stroke(LineStyle(BaseProperties10)))))) {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.direction = "horizontal";
|
|
this.type = "horizontal-line" /* HorizontalLine */;
|
|
this.text = new LineTextProperties();
|
|
}
|
|
static is(value) {
|
|
return isObject5(value) && value.type === "horizontal-line" /* HorizontalLine */;
|
|
}
|
|
getDefaultColor() {
|
|
return this.stroke;
|
|
}
|
|
getDefaultOpacity() {
|
|
return this.strokeOpacity;
|
|
}
|
|
getLineDash() {
|
|
return getLineDash(this.lineDash, this.computedLineDash, this.lineStyle, this.strokeWidth);
|
|
}
|
|
getLineCap() {
|
|
return getLineCap(this.lineCap, this.lineDash, this.lineStyle);
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property23
|
|
], HorizontalLineProperties.prototype, "type", 2);
|
|
__decorateClass([
|
|
Property23
|
|
], HorizontalLineProperties.prototype, "text", 2);
|
|
var VerticalLineProperties = class extends Annotation(Value(Handle(AxisLabel(Stroke(LineStyle(BaseProperties10)))))) {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.direction = "vertical";
|
|
this.type = "vertical-line" /* VerticalLine */;
|
|
this.text = new LineTextProperties();
|
|
}
|
|
static is(value) {
|
|
return isObject5(value) && value.type === "vertical-line" /* VerticalLine */;
|
|
}
|
|
getDefaultColor() {
|
|
return this.stroke;
|
|
}
|
|
getDefaultOpacity() {
|
|
return this.strokeOpacity;
|
|
}
|
|
getLineDash() {
|
|
return getLineDash(this.lineDash, this.computedLineDash, this.lineStyle, this.strokeWidth);
|
|
}
|
|
getLineCap() {
|
|
return getLineCap(this.lineCap, this.lineDash, this.lineStyle);
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property23
|
|
], VerticalLineProperties.prototype, "type", 2);
|
|
__decorateClass([
|
|
Property23
|
|
], VerticalLineProperties.prototype, "text", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/disjoint-channel/disjointChannelProperties.ts
|
|
import "ag-charts-community";
|
|
import { BaseProperties as BaseProperties11, Logger, Property as Property24, isObject as isObject6 } from "ag-charts-core";
|
|
var DisjointChannelProperties = class extends Annotation(
|
|
Background2(Line3(Handle(Extendable(Stroke(LineStyle(BaseProperties11))))))
|
|
) {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.type = "disjoint-channel" /* DisjointChannel */;
|
|
this.text = new ChannelTextProperties();
|
|
this.snapToAngle = 45;
|
|
}
|
|
static is(value) {
|
|
return isObject6(value) && value.type === "disjoint-channel" /* DisjointChannel */;
|
|
}
|
|
get bottom() {
|
|
const bottom = {
|
|
start: { x: this.start.x, y: this.start.y },
|
|
end: { x: this.end.x, y: this.end.y }
|
|
};
|
|
if (typeof bottom.start.y === "number" && typeof bottom.end.y === "number") {
|
|
bottom.start.y -= this.startHeight;
|
|
bottom.end.y -= this.endHeight;
|
|
} else {
|
|
Logger.warnOnce(`Annotation [${this.type}] can only be used with a numeric y-axis.`);
|
|
}
|
|
return bottom;
|
|
}
|
|
getDefaultColor(colorPickerType) {
|
|
switch (colorPickerType) {
|
|
case `fill-color`:
|
|
return this.background.fill;
|
|
case `line-color`:
|
|
return this.stroke;
|
|
case "text-color":
|
|
return this.text.color;
|
|
}
|
|
}
|
|
getDefaultOpacity(colorPickerType) {
|
|
switch (colorPickerType) {
|
|
case `fill-color`:
|
|
return this.background.fillOpacity;
|
|
case `line-color`:
|
|
return this.strokeOpacity;
|
|
}
|
|
}
|
|
getLineDash() {
|
|
return getLineDash(this.lineDash, this.computedLineDash, this.lineStyle, this.strokeWidth);
|
|
}
|
|
getLineCap() {
|
|
return getLineCap(this.lineCap, this.lineDash, this.lineStyle);
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property24
|
|
], DisjointChannelProperties.prototype, "type", 2);
|
|
__decorateClass([
|
|
Property24
|
|
], DisjointChannelProperties.prototype, "startHeight", 2);
|
|
__decorateClass([
|
|
Property24
|
|
], DisjointChannelProperties.prototype, "endHeight", 2);
|
|
__decorateClass([
|
|
Property24
|
|
], DisjointChannelProperties.prototype, "text", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/fibonacci-retracement-trend-based/fibonacciRetracementTrendBasedProperties.ts
|
|
import { Property as Property27, isObject as isObject8 } from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/properties/fibonacciProperties.ts
|
|
import { Property as Property26 } from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/line/lineProperties.ts
|
|
import "ag-charts-community";
|
|
import { Property as Property25, isObject as isObject7 } from "ag-charts-core";
|
|
var LineTypeProperties = class extends Localisable(
|
|
Cappable(Extendable(Stroke(LineStyle(StartEndProperties))))
|
|
) {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.text = new LineTextProperties();
|
|
}
|
|
getDefaultColor(colorPickerType) {
|
|
switch (colorPickerType) {
|
|
case "line-color":
|
|
return this.stroke;
|
|
case "text-color":
|
|
return this.text.color;
|
|
}
|
|
}
|
|
getDefaultOpacity() {
|
|
return this.strokeOpacity;
|
|
}
|
|
getLineDash() {
|
|
return getLineDash(this.lineDash, this.computedLineDash, this.lineStyle, this.strokeWidth);
|
|
}
|
|
getLineCap() {
|
|
return getLineCap(this.lineCap, this.lineDash, this.lineStyle);
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property25
|
|
], LineTypeProperties.prototype, "text", 2);
|
|
var ArrowProperties = class extends LineTypeProperties {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.type = "arrow" /* Arrow */;
|
|
this.endCap = "arrow";
|
|
}
|
|
static is(value) {
|
|
return isObject7(value) && value.type === "arrow" /* Arrow */;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property25
|
|
], ArrowProperties.prototype, "type", 2);
|
|
var LineProperties = class extends LineTypeProperties {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.type = "line" /* Line */;
|
|
}
|
|
static is(value) {
|
|
return isObject7(value) && value.type === "line" /* Line */;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property25
|
|
], LineProperties.prototype, "type", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/properties/fibonacciProperties.ts
|
|
var FibonacciProperties = class extends LineTypeProperties {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.label = new LabelTextProperties();
|
|
this.reverse = false;
|
|
this.showFill = true;
|
|
this.isMultiColor = true;
|
|
this.strokes = [];
|
|
this.bands = 10;
|
|
}
|
|
getDefaultColor(colorPickerType) {
|
|
switch (colorPickerType) {
|
|
case "line-color":
|
|
return this.rangeStroke ?? this.stroke;
|
|
case "text-color":
|
|
return this.text.color;
|
|
}
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property26
|
|
], FibonacciProperties.prototype, "label", 2);
|
|
__decorateClass([
|
|
Property26
|
|
], FibonacciProperties.prototype, "reverse", 2);
|
|
__decorateClass([
|
|
Property26
|
|
], FibonacciProperties.prototype, "showFill", 2);
|
|
__decorateClass([
|
|
Property26
|
|
], FibonacciProperties.prototype, "isMultiColor", 2);
|
|
__decorateClass([
|
|
Property26
|
|
], FibonacciProperties.prototype, "strokes", 2);
|
|
__decorateClass([
|
|
Property26
|
|
], FibonacciProperties.prototype, "rangeStroke", 2);
|
|
__decorateClass([
|
|
Property26
|
|
], FibonacciProperties.prototype, "bands", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/fibonacci-retracement-trend-based/fibonacciRetracementTrendBasedProperties.ts
|
|
var FibonacciRetracementTrendBasedProperties = class extends FibonacciProperties {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.type = "fibonacci-retracement-trend-based" /* FibonacciRetracementTrendBased */;
|
|
this.endRetracement = new PointProperties();
|
|
}
|
|
static is(value) {
|
|
return isObject8(value) && value.type === "fibonacci-retracement-trend-based" /* FibonacciRetracementTrendBased */;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property27
|
|
], FibonacciRetracementTrendBasedProperties.prototype, "type", 2);
|
|
__decorateClass([
|
|
Property27
|
|
], FibonacciRetracementTrendBasedProperties.prototype, "endRetracement", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/fibonacci-retracement/fibonacciRetracementProperties.ts
|
|
import { Property as Property28, isObject as isObject9 } from "ag-charts-core";
|
|
var FibonacciRetracementProperties = class extends FibonacciProperties {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.type = "fibonacci-retracement" /* FibonacciRetracement */;
|
|
}
|
|
static is(value) {
|
|
return isObject9(value) && value.type === "fibonacci-retracement" /* FibonacciRetracement */;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property28
|
|
], FibonacciRetracementProperties.prototype, "type", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/parallel-channel/parallelChannelProperties.ts
|
|
import "ag-charts-community";
|
|
import { BaseProperties as BaseProperties12, Logger as Logger2, Property as Property29, isObject as isObject10 } from "ag-charts-core";
|
|
var ParallelChannelProperties = class extends Annotation(
|
|
Background2(Line3(Handle(Extendable(Stroke(LineStyle(BaseProperties12))))))
|
|
) {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.type = "parallel-channel" /* ParallelChannel */;
|
|
this.middle = new ChannelAnnotationMiddleProperties();
|
|
this.text = new ChannelTextProperties();
|
|
this.snapToAngle = 45;
|
|
}
|
|
static is(value) {
|
|
return isObject10(value) && value.type === "parallel-channel" /* ParallelChannel */;
|
|
}
|
|
get bottom() {
|
|
const bottom = {
|
|
start: { x: this.start.x, y: this.start.y },
|
|
end: { x: this.end.x, y: this.end.y }
|
|
};
|
|
if (typeof bottom.start.y === "number" && typeof bottom.end.y === "number") {
|
|
bottom.start.y -= this.height;
|
|
bottom.end.y -= this.height;
|
|
} else {
|
|
Logger2.warnOnce(`Annotation [${this.type}] can only be used with a numeric y-axis.`);
|
|
}
|
|
return bottom;
|
|
}
|
|
getDefaultColor(colorPickerType) {
|
|
switch (colorPickerType) {
|
|
case `fill-color`:
|
|
return this.background.fill;
|
|
case `line-color`:
|
|
return this.stroke;
|
|
case "text-color":
|
|
return this.text.color;
|
|
}
|
|
}
|
|
getDefaultOpacity(colorPickerType) {
|
|
switch (colorPickerType) {
|
|
case `fill-color`:
|
|
return this.background.fillOpacity;
|
|
case `line-color`:
|
|
return this.strokeOpacity;
|
|
}
|
|
}
|
|
getLineDash() {
|
|
return getLineDash(this.lineDash, this.computedLineDash, this.lineStyle, this.strokeWidth);
|
|
}
|
|
getLineCap() {
|
|
return getLineCap(this.lineCap, this.lineDash, this.lineStyle);
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property29
|
|
], ParallelChannelProperties.prototype, "type", 2);
|
|
__decorateClass([
|
|
Property29
|
|
], ParallelChannelProperties.prototype, "height", 2);
|
|
__decorateClass([
|
|
Property29
|
|
], ParallelChannelProperties.prototype, "middle", 2);
|
|
__decorateClass([
|
|
Property29
|
|
], ParallelChannelProperties.prototype, "text", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/text/textProperties.ts
|
|
import { Property as Property30, isObject as isObject11 } from "ag-charts-core";
|
|
var TextProperties = class extends TextualPointProperties {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.type = "text" /* Text */;
|
|
this.position = "bottom";
|
|
}
|
|
static is(value) {
|
|
return isObject11(value) && value.type === "text" /* Text */;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property30
|
|
], TextProperties.prototype, "type", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/utils/types.ts
|
|
function isEphemeralType(datum) {
|
|
return QuickDatePriceRangeProperties.is(datum);
|
|
}
|
|
function isLineType(datum) {
|
|
return LineProperties.is(datum) || HorizontalLineProperties.is(datum) || VerticalLineProperties.is(datum) || ArrowProperties.is(datum) || isFibonacciType(datum);
|
|
}
|
|
function isChannelType(datum) {
|
|
return DisjointChannelProperties.is(datum) || ParallelChannelProperties.is(datum);
|
|
}
|
|
function isFibonacciType(datum) {
|
|
return FibonacciRetracementProperties.is(datum) || FibonacciRetracementTrendBasedProperties.is(datum);
|
|
}
|
|
function isTextType(datum) {
|
|
return CalloutProperties.is(datum) || CommentProperties.is(datum) || NoteProperties.is(datum) || TextProperties.is(datum);
|
|
}
|
|
function isMeasurerType(datum) {
|
|
return DateRangeProperties.is(datum) || PriceRangeProperties.is(datum) || DatePriceRangeProperties.is(datum) || QuickDatePriceRangeProperties.is(datum);
|
|
}
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/utils/has.ts
|
|
function hasFontSize(datum) {
|
|
return isTextType(datum) && !NoteProperties.is(datum);
|
|
}
|
|
function hasLineStyle(datum) {
|
|
return isLineType(datum) || isChannelType(datum) || isMeasurerType(datum) && !QuickDatePriceRangeProperties.is(datum);
|
|
}
|
|
function hasLineColor(datum) {
|
|
return isLineType(datum) || isChannelType(datum) || isMeasurerType(datum) || CalloutProperties.is(datum) || NoteProperties.is(datum);
|
|
}
|
|
function hasIconColor(datum) {
|
|
return NoteProperties.is(datum);
|
|
}
|
|
function hasFillColor(datum) {
|
|
return isChannelType(datum) || isMeasurerType(datum) || CalloutProperties.is(datum) || CommentProperties.is(datum) || ShapePointProperties.is(datum);
|
|
}
|
|
function hasTextColor(datum) {
|
|
return isTextType(datum) && !NoteProperties.is(datum);
|
|
}
|
|
function hasLineText(datum) {
|
|
return (isLineType(datum) || isChannelType(datum) || isMeasurerType(datum)) && !isEphemeralType(datum) && isObject12(datum.text);
|
|
}
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/utils/styles.ts
|
|
function setFontSize(datum, fontSize) {
|
|
if ("fontSize" in datum)
|
|
datum.fontSize = fontSize;
|
|
if (hasLineText(datum))
|
|
datum.text.fontSize = fontSize;
|
|
}
|
|
function setLineStyle(datum, style) {
|
|
const strokeWidth = style?.strokeWidth ?? datum.strokeWidth ?? 1;
|
|
const lineType = style?.type ?? datum.lineStyle;
|
|
const lineStyle = lineType ?? getLineStyle(datum.lineDash, lineType);
|
|
const computedLineDash = getComputedLineDash(strokeWidth, lineStyle);
|
|
datum.strokeWidth = strokeWidth;
|
|
datum.computedLineDash = computedLineDash;
|
|
datum.lineStyle = lineStyle;
|
|
datum.lineCap = lineStyle === "dotted" ? "round" : void 0;
|
|
}
|
|
function setColor(datum, colorPickerType, colorOpacity, color7, opacity, isMultiColor) {
|
|
switch (colorPickerType) {
|
|
case `fill-color`: {
|
|
if ("fill" in datum)
|
|
datum.fill = color7;
|
|
if ("fillOpacity" in datum)
|
|
datum.fillOpacity = opacity;
|
|
if ("background" in datum) {
|
|
datum.background.fill = color7;
|
|
datum.background.fillOpacity = opacity;
|
|
}
|
|
break;
|
|
}
|
|
case `line-color`: {
|
|
if ("axisLabel" in datum) {
|
|
datum.axisLabel.fill = color7;
|
|
datum.axisLabel.fillOpacity = opacity;
|
|
datum.axisLabel.stroke = color7;
|
|
datum.axisLabel.strokeOpacity = opacity;
|
|
}
|
|
if ("fill" in datum && "fillOpacity" in datum && hasIconColor(datum)) {
|
|
datum.fill = color7;
|
|
datum.fillOpacity = opacity;
|
|
} else {
|
|
if ("strokeOpacity" in datum)
|
|
datum.strokeOpacity = opacity;
|
|
if ("isMultiColor" in datum && "rangeStroke" in datum) {
|
|
datum.isMultiColor = isMultiColor;
|
|
datum.rangeStroke = color7;
|
|
} else if ("stroke" in datum) {
|
|
datum.stroke = color7;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case `text-color`: {
|
|
if ("color" in datum)
|
|
datum.color = colorOpacity;
|
|
if (hasLineText(datum))
|
|
datum.text.color = color7;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/annotationDefaults.ts
|
|
var AnnotationDefaults = class {
|
|
constructor() {
|
|
this.mementoOriginatorKey = "annotation-defaults";
|
|
this.colors = new Map(
|
|
Object.values(AnnotationType).map((type) => [
|
|
type,
|
|
/* @__PURE__ */ new Map([
|
|
["line-color", void 0],
|
|
["fill-color", void 0],
|
|
["text-color", void 0]
|
|
])
|
|
])
|
|
);
|
|
this.fontSizes = /* @__PURE__ */ new Map([
|
|
["callout" /* Callout */, void 0],
|
|
["comment" /* Comment */, void 0],
|
|
["text" /* Text */, void 0],
|
|
["arrow" /* Arrow */, void 0],
|
|
["line" /* Line */, void 0],
|
|
["disjoint-channel" /* DisjointChannel */, void 0],
|
|
["parallel-channel" /* ParallelChannel */, void 0],
|
|
["date-range" /* DateRange */, void 0],
|
|
["price-range" /* PriceRange */, void 0],
|
|
["date-price-range" /* DatePriceRange */, void 0]
|
|
]);
|
|
this.lineStyles = /* @__PURE__ */ new Map([
|
|
["line" /* Line */, void 0],
|
|
["horizontal-line" /* HorizontalLine */, void 0],
|
|
["vertical-line" /* VerticalLine */, void 0],
|
|
["disjoint-channel" /* DisjointChannel */, void 0],
|
|
["parallel-channel" /* ParallelChannel */, void 0],
|
|
["arrow" /* Arrow */, void 0],
|
|
["date-range" /* DateRange */, void 0],
|
|
["price-range" /* PriceRange */, void 0],
|
|
["date-price-range" /* DatePriceRange */, void 0]
|
|
]);
|
|
this.lineTextAlignments = /* @__PURE__ */ new Map([
|
|
["line" /* Line */, void 0],
|
|
["horizontal-line" /* HorizontalLine */, void 0],
|
|
["vertical-line" /* VerticalLine */, void 0],
|
|
["disjoint-channel" /* DisjointChannel */, void 0],
|
|
["parallel-channel" /* ParallelChannel */, void 0],
|
|
["arrow" /* Arrow */, void 0],
|
|
["date-range" /* DateRange */, void 0],
|
|
["price-range" /* PriceRange */, void 0],
|
|
["date-price-range" /* DatePriceRange */, void 0]
|
|
]);
|
|
this.lineTextPositions = /* @__PURE__ */ new Map([
|
|
["line" /* Line */, void 0],
|
|
["horizontal-line" /* HorizontalLine */, void 0],
|
|
["vertical-line" /* VerticalLine */, void 0],
|
|
["disjoint-channel" /* DisjointChannel */, void 0],
|
|
["parallel-channel" /* ParallelChannel */, void 0],
|
|
["arrow" /* Arrow */, void 0],
|
|
["date-range" /* DateRange */, void 0],
|
|
["price-range" /* PriceRange */, void 0],
|
|
["date-price-range" /* DatePriceRange */, void 0]
|
|
]);
|
|
this.fibonacciOptions = /* @__PURE__ */ new Map([
|
|
[
|
|
"fibonacci-retracement" /* FibonacciRetracement */,
|
|
{
|
|
bands: void 0,
|
|
reverse: void 0,
|
|
showFill: void 0
|
|
}
|
|
],
|
|
[
|
|
"fibonacci-retracement-trend-based" /* FibonacciRetracementTrendBased */,
|
|
{
|
|
bands: void 0,
|
|
reverse: void 0,
|
|
showFill: void 0
|
|
}
|
|
]
|
|
]);
|
|
}
|
|
createMemento() {
|
|
return {
|
|
colors: deepClone(this.colors),
|
|
fontSizes: deepClone(this.fontSizes),
|
|
lineStyles: deepClone(this.lineStyles),
|
|
lineTextAlignments: deepClone(this.lineTextAlignments),
|
|
lineTextPositions: deepClone(this.lineTextPositions),
|
|
fibonacciOptions: deepClone(this.fibonacciOptions)
|
|
};
|
|
}
|
|
guardMemento(_blob) {
|
|
return true;
|
|
}
|
|
restoreMemento(_version, _mementoVersion, blob) {
|
|
this.colors = deepClone(blob.colors);
|
|
this.fontSizes = deepClone(blob.fontSizes);
|
|
this.lineStyles = deepClone(blob.lineStyles);
|
|
this.lineTextAlignments = deepClone(blob.lineTextAlignments);
|
|
this.lineTextPositions = deepClone(blob.lineTextPositions);
|
|
this.fibonacciOptions = deepClone(blob.fibonacciOptions);
|
|
}
|
|
setDefaultColor(type, colorType, colorOpacity, color7, opacity, isMultiColor) {
|
|
this.colors.get(type)?.set(colorType, [colorOpacity, color7, opacity, isMultiColor]);
|
|
}
|
|
setDefaultFontSize(type, fontSize) {
|
|
this.fontSizes.set(type, fontSize);
|
|
}
|
|
setDefaultLineStyleType(type, lineStyleType) {
|
|
const defaultStyle = this.lineStyles.get(type);
|
|
if (defaultStyle) {
|
|
defaultStyle.type = lineStyleType;
|
|
} else {
|
|
this.lineStyles.set(type, { type: lineStyleType });
|
|
}
|
|
}
|
|
setDefaultLineStyleWidth(type, strokeWidth) {
|
|
const defaultStyle = this.lineStyles.get(type);
|
|
if (defaultStyle) {
|
|
defaultStyle.strokeWidth = strokeWidth;
|
|
} else {
|
|
this.lineStyles.set(type, { strokeWidth });
|
|
}
|
|
}
|
|
setDefaultLineTextAlignment(type, alignment) {
|
|
this.lineTextAlignments.set(type, alignment);
|
|
}
|
|
setDefaultLineTextPosition(type, position) {
|
|
this.lineTextPositions.set(type, position);
|
|
}
|
|
setDefaultFibonacciOptions(type, key, value) {
|
|
if (type != "fibonacci-retracement" /* FibonacciRetracement */ && type != "fibonacci-retracement-trend-based" /* FibonacciRetracementTrendBased */)
|
|
return;
|
|
const options = this.fibonacciOptions.get(type);
|
|
options[key] = value;
|
|
this.fibonacciOptions.set(type, options);
|
|
}
|
|
applyDefaults(datum) {
|
|
for (const [annotationType, colors] of this.colors) {
|
|
if (datum.type !== annotationType)
|
|
continue;
|
|
for (const [colorPickerType, [colorOpacity, color7, opacity, isMultiColor] = []] of colors) {
|
|
if (colorOpacity && color7 && opacity != null && isMultiColor != null) {
|
|
setColor(datum, colorPickerType, colorOpacity, color7, opacity, isMultiColor);
|
|
}
|
|
}
|
|
}
|
|
for (const [annotationType, size] of this.fontSizes) {
|
|
if (datum.type !== annotationType || size == null)
|
|
continue;
|
|
setFontSize(datum, size);
|
|
}
|
|
for (const [annotationType, style] of this.lineStyles) {
|
|
if (datum.type !== annotationType || style == null)
|
|
continue;
|
|
setLineStyle(datum, style);
|
|
}
|
|
for (const [annotationType, position] of this.lineTextPositions) {
|
|
if (datum.type !== annotationType || position == null)
|
|
continue;
|
|
datum.text.position = position;
|
|
}
|
|
for (const [annotationType, alignment] of this.lineTextAlignments) {
|
|
if (datum.type !== annotationType || alignment == null)
|
|
continue;
|
|
datum.text.alignment = alignment;
|
|
}
|
|
for (const [annotationType, options] of this.fibonacciOptions) {
|
|
if (datum.type !== annotationType || options == null)
|
|
continue;
|
|
for (const option of Object.keys(options)) {
|
|
const value = options[option];
|
|
if (value == null) {
|
|
continue;
|
|
}
|
|
datum.set({ [option]: value });
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/annotationOptionsToolbar.ts
|
|
import { _ModuleSupport as _ModuleSupport33 } from "ag-charts-community";
|
|
import {
|
|
BaseProperties as BaseProperties14,
|
|
CleanupRegistry as CleanupRegistry2,
|
|
Color as Color4,
|
|
EventEmitter,
|
|
PropertiesArray,
|
|
Property as Property32
|
|
} from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/components/color-picker/colorPicker.ts
|
|
import { _ModuleSupport as _ModuleSupport31 } from "ag-charts-community";
|
|
import { Color as Color3, attachListener as attachListener2, clamp as clamp3, createElement as createElement3, getWindow } from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/components/color-picker/colorPickerTemplate.html
|
|
var colorPickerTemplate_default = '<div class="ag-charts-color-picker__palette" role="slider" tabindex="0"></div><div class="ag-charts-color-picker__color-row" role="presentation"><button class="ag-charts-color-picker__multi-color-button" tabindex="0" type="button" role="switch"></button> <input class="ag-charts-color-picker__hue-input" tabindex="0" type="range" min="0" max="360" value="0"></div><input class="ag-charts-color-picker__alpha-input" tabindex="0" type="range" min="0" max="1" value="1" step="0.01"> <label class="ag-charts-color-picker__color-field" role="presentation"><span class="ag-charts-color-picker__color-label" aria-hidden="true"></span> <input class="ag-charts-color-picker__color-input" tabindex="0" value="#000"></label>';
|
|
|
|
// packages/ag-charts-enterprise/src/components/color-picker/colorPicker.ts
|
|
var getHsva = (input) => {
|
|
try {
|
|
const color7 = Color3.fromString(input);
|
|
const [h, s, v] = color7.toHSB();
|
|
return [h, s, v, color7.a];
|
|
} catch {
|
|
return;
|
|
}
|
|
};
|
|
var ColorPicker = class extends _ModuleSupport31.AnchoredPopover {
|
|
constructor(ctx, options) {
|
|
super(ctx, "color-picker", options);
|
|
this.hasChanged = false;
|
|
this.hideFns.push(() => {
|
|
this.i18nUpdater = void 0;
|
|
if (this.hasChanged)
|
|
this.onChangeHide?.();
|
|
});
|
|
this.cleanup.register(this.ctx.eventsHub.on("locale:change", () => this.i18nUpdater?.()));
|
|
}
|
|
show(options) {
|
|
this.hasChanged = false;
|
|
this.onChangeHide = options.onChangeHide;
|
|
const { element, initialFocus } = this.createColorPicker(options);
|
|
const popover = this.showWithChildren([element], { initialFocus, ...options });
|
|
popover.classList.add("ag-charts-color-picker");
|
|
popover.setAttribute("role", "dialog");
|
|
}
|
|
createColorPicker(opts) {
|
|
const { localeManager } = this.ctx;
|
|
let isMultiColor = opts.isMultiColor ?? false;
|
|
let [h, s, v, a] = getHsva(opts.color ?? "#f00") ?? [0, 1, 0.5, 1];
|
|
a = opts.opacity ?? a;
|
|
const colorPicker = createElement3("div", "ag-charts-color-picker__content");
|
|
colorPicker.innerHTML = colorPickerTemplate_default;
|
|
colorPicker.ariaLabel = this.ctx.localeManager.t("ariaLabelColorPicker");
|
|
const paletteInput = colorPicker.querySelector(".ag-charts-color-picker__palette");
|
|
const hueInput = colorPicker.querySelector(".ag-charts-color-picker__hue-input");
|
|
const multiColorButton = colorPicker.querySelector(
|
|
".ag-charts-color-picker__multi-color-button"
|
|
);
|
|
const alphaInput = colorPicker.querySelector(".ag-charts-color-picker__alpha-input");
|
|
const colorInput = colorPicker.querySelector(".ag-charts-color-picker__color-input");
|
|
const colorInputLabel = colorPicker.querySelector(".ag-charts-color-picker__color-label");
|
|
const updatePaletteInputAriaValue = (first) => {
|
|
const key = { s: "ariaValueColorPalette", v: "ariaValueColorPaletteFirstV" }[first];
|
|
paletteInput.ariaValueText = localeManager.t(key, { s, v });
|
|
};
|
|
this.i18nUpdater = () => {
|
|
paletteInput.ariaRoleDescription = localeManager.t("ariaRoleDescription2DSlider");
|
|
paletteInput.ariaLabel = localeManager.t("ariaLabelColorPickerPalette");
|
|
hueInput.ariaLabel = localeManager.t("ariaLabelColorPickerHue");
|
|
multiColorButton.ariaLabel = localeManager.t("ariaLabelColorPickerMultiColor");
|
|
alphaInput.ariaLabel = localeManager.t("ariaLabelColorPickerAlpha");
|
|
colorInput.ariaLabel = localeManager.t("ariaLabelColor");
|
|
updatePaletteInputAriaValue("s");
|
|
};
|
|
this.i18nUpdater();
|
|
multiColorButton.classList.toggle(
|
|
"ag-charts-color-picker__multi-color-button--hidden",
|
|
!opts.hasMultiColorOption
|
|
);
|
|
const update = (trackChange = true) => {
|
|
const color7 = Color3.fromHSB(h, s, v, a);
|
|
const colorString = color7.toHexString();
|
|
colorPicker.style.setProperty("--h", `${h}`);
|
|
colorPicker.style.setProperty("--s", `${s}`);
|
|
colorPicker.style.setProperty("--v", `${v}`);
|
|
colorPicker.style.setProperty("--a", `${a}`);
|
|
colorPicker.style.setProperty("--color", colorString.slice(0, 7));
|
|
colorPicker.style.setProperty("--color-a", colorString);
|
|
hueInput.value = `${h}`;
|
|
alphaInput.value = `${a}`;
|
|
alphaInput.classList.toggle("ag-charts-color-picker__alpha-input--opaque", a === 1);
|
|
multiColorButton.classList.toggle("ag-charts-color-picker__multi-color-button--active", isMultiColor);
|
|
colorInputLabel.classList.toggle("ag-charts-color-picker__color-label--multi-color", isMultiColor);
|
|
if (document.activeElement !== colorInput) {
|
|
multiColorButton.ariaChecked = isMultiColor.toString();
|
|
colorInput.value = isMultiColor ? localeManager.t("ariaLabelColorPickerMultiColor") : colorString.toUpperCase();
|
|
}
|
|
if (trackChange || opts.color == null) {
|
|
const plainColor = Color3.fromHSB(h, s, v, 1).toHexString();
|
|
opts.onChange?.(colorString, plainColor, a, isMultiColor);
|
|
}
|
|
if (trackChange)
|
|
this.hasChanged = true;
|
|
};
|
|
update(false);
|
|
const preventDefault = (event) => event.preventDefault();
|
|
const stopPropagation = (event) => event.stopPropagation();
|
|
const beginPaletteInteraction = (e) => {
|
|
e.preventDefault();
|
|
const currentTarget = e.currentTarget;
|
|
currentTarget.focus();
|
|
const rect = currentTarget.getBoundingClientRect();
|
|
const pointerMove = ({ clientX, clientY }) => {
|
|
isMultiColor = false;
|
|
s = Math.min(Math.max((clientX - rect.left) / rect.width, 0), 1);
|
|
v = 1 - Math.min(Math.max((clientY - rect.top) / rect.height, 0), 1);
|
|
update();
|
|
updatePaletteInputAriaValue("s");
|
|
};
|
|
pointerMove(e);
|
|
const pointerUp = attachListener2(getWindow(), "pointermove", pointerMove);
|
|
getWindow().addEventListener("pointerup", pointerUp, { once: true });
|
|
};
|
|
colorPicker.addEventListener("mousedown", stopPropagation);
|
|
colorPicker.addEventListener("touchstart", stopPropagation);
|
|
colorPicker.addEventListener("touchmove", stopPropagation);
|
|
colorPicker.addEventListener("keydown", (e) => {
|
|
e.stopPropagation();
|
|
switch (e.key) {
|
|
case "Enter":
|
|
case "Escape":
|
|
this.hide();
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
e.preventDefault();
|
|
});
|
|
paletteInput.addEventListener("pointerdown", beginPaletteInteraction);
|
|
paletteInput.addEventListener("touchstart", preventDefault, { passive: false });
|
|
paletteInput.addEventListener("touchmove", preventDefault, { passive: false });
|
|
paletteInput.addEventListener("keydown", (e) => {
|
|
if (e.key === "ArrowLeft") {
|
|
s = clamp3(0, s - 0.01, 1);
|
|
updatePaletteInputAriaValue("s");
|
|
} else if (e.key === "ArrowRight") {
|
|
s = clamp3(0, s + 0.01, 1);
|
|
updatePaletteInputAriaValue("s");
|
|
} else if (e.key === "ArrowUp") {
|
|
v = clamp3(0, v + 0.01, 1);
|
|
updatePaletteInputAriaValue("v");
|
|
} else if (e.key === "ArrowDown") {
|
|
v = clamp3(0, v - 0.01, 1);
|
|
updatePaletteInputAriaValue("v");
|
|
} else {
|
|
return;
|
|
}
|
|
e.preventDefault();
|
|
update();
|
|
});
|
|
paletteInput.addEventListener("focus", () => {
|
|
updatePaletteInputAriaValue("s");
|
|
});
|
|
multiColorButton.addEventListener("click", () => {
|
|
isMultiColor = !isMultiColor;
|
|
update();
|
|
});
|
|
hueInput.addEventListener("input", (e) => {
|
|
isMultiColor = false;
|
|
h = e.currentTarget.valueAsNumber ?? 0;
|
|
update();
|
|
});
|
|
alphaInput.addEventListener("input", (e) => {
|
|
isMultiColor = false;
|
|
a = e.currentTarget.valueAsNumber ?? 0;
|
|
update();
|
|
});
|
|
colorInput.addEventListener("input", (e) => {
|
|
isMultiColor = false;
|
|
const hsva = getHsva(e.currentTarget.value);
|
|
if (hsva == null)
|
|
return;
|
|
[h, s, v, a] = hsva;
|
|
update();
|
|
});
|
|
colorInput.addEventListener("blur", () => update());
|
|
colorInput.addEventListener("keydown", (e) => {
|
|
if (e.key === "Enter") {
|
|
e.currentTarget.blur();
|
|
update();
|
|
}
|
|
});
|
|
return { element: colorPicker, initialFocus: paletteInput };
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/toolbar/buttonProperties.ts
|
|
import { BaseProperties as BaseProperties13, Property as Property31 } from "ag-charts-core";
|
|
var ToolbarButtonProperties = class extends BaseProperties13 {
|
|
};
|
|
__decorateClass([
|
|
Property31
|
|
], ToolbarButtonProperties.prototype, "icon", 2);
|
|
__decorateClass([
|
|
Property31
|
|
], ToolbarButtonProperties.prototype, "label", 2);
|
|
__decorateClass([
|
|
Property31
|
|
], ToolbarButtonProperties.prototype, "ariaLabel", 2);
|
|
__decorateClass([
|
|
Property31
|
|
], ToolbarButtonProperties.prototype, "tooltip", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/annotationsMenuOptions.ts
|
|
import { _ModuleSupport as _ModuleSupport32 } from "ag-charts-community";
|
|
function channelMenuItemVisible(scale) {
|
|
return !(scale instanceof _ModuleSupport32.LogScale) && !(scale instanceof _ModuleSupport32.BandScale);
|
|
}
|
|
var LINE_ANNOTATION_ITEMS = [
|
|
{
|
|
label: "toolbarAnnotationsTrendLine",
|
|
icon: "trend-line-drawing",
|
|
value: "line" /* Line */
|
|
},
|
|
{
|
|
label: "toolbarAnnotationsHorizontalLine",
|
|
icon: "horizontal-line-drawing",
|
|
value: "horizontal-line" /* HorizontalLine */
|
|
},
|
|
{
|
|
label: "toolbarAnnotationsVerticalLine",
|
|
icon: "vertical-line-drawing",
|
|
value: "vertical-line" /* VerticalLine */
|
|
},
|
|
{
|
|
label: "toolbarAnnotationsParallelChannel",
|
|
icon: "parallel-channel-drawing",
|
|
value: "parallel-channel" /* ParallelChannel */,
|
|
visible: channelMenuItemVisible
|
|
},
|
|
{
|
|
label: "toolbarAnnotationsDisjointChannel",
|
|
icon: "disjoint-channel-drawing",
|
|
value: "disjoint-channel" /* DisjointChannel */,
|
|
visible: channelMenuItemVisible
|
|
}
|
|
];
|
|
var FIBONACCI_ANNOTATION_ITEMS = [
|
|
{
|
|
label: "toolbarAnnotationsFibonacciRetracement",
|
|
icon: "fibonacci-retracement-drawing",
|
|
value: "fibonacci-retracement" /* FibonacciRetracement */
|
|
},
|
|
{
|
|
label: "toolbarAnnotationsFibonacciRetracementTrendBased",
|
|
icon: "fibonacci-retracement-trend-based-drawing",
|
|
value: "fibonacci-retracement-trend-based" /* FibonacciRetracementTrendBased */
|
|
}
|
|
];
|
|
var FIBONACCI_RATIO_ITEMS = [
|
|
{ label: "Fibonacci - Extended", value: 10 },
|
|
{ label: "Fibonacci - 6 Band", value: 6 },
|
|
{ label: "Fibonacci - 4 Band", value: 4 }
|
|
];
|
|
var TEXT_ANNOTATION_ITEMS = [
|
|
{ label: "toolbarAnnotationsText", icon: "text-annotation", value: "text" /* Text */ },
|
|
{ label: "toolbarAnnotationsComment", icon: "comment-annotation", value: "comment" /* Comment */ },
|
|
{ label: "toolbarAnnotationsCallout", icon: "callout-annotation", value: "callout" /* Callout */ },
|
|
{ label: "toolbarAnnotationsNote", icon: "note-annotation", value: "note" /* Note */ }
|
|
];
|
|
var SHAPE_ANNOTATION_ITEMS = [
|
|
{ label: "toolbarAnnotationsArrow", icon: "arrow-drawing", value: "arrow" /* Arrow */ },
|
|
{ label: "toolbarAnnotationsArrowUp", icon: "arrow-up-drawing", value: "arrow-up" /* ArrowUp */ },
|
|
{ label: "toolbarAnnotationsArrowDown", icon: "arrow-down-drawing", value: "arrow-down" /* ArrowDown */ }
|
|
];
|
|
var MEASURER_ANNOTATION_ITEMS = [
|
|
{
|
|
label: "toolbarAnnotationsQuickDatePriceRange",
|
|
icon: "measurer-drawing",
|
|
value: "quick-date-price-range" /* QuickDatePriceRange */
|
|
},
|
|
{ label: "toolbarAnnotationsDateRange", icon: "date-range-drawing", value: "date-range" /* DateRange */ },
|
|
{ label: "toolbarAnnotationsPriceRange", icon: "price-range-drawing", value: "price-range" /* PriceRange */ },
|
|
{
|
|
label: "toolbarAnnotationsDatePriceRange",
|
|
icon: "date-price-range-drawing",
|
|
value: "date-price-range" /* DatePriceRange */
|
|
}
|
|
];
|
|
var LINE_STROKE_WIDTH_ITEMS = [
|
|
{ strokeWidth: 1, label: "1", value: 1 },
|
|
{ strokeWidth: 2, label: "2", value: 2 },
|
|
{ strokeWidth: 3, label: "3", value: 3 },
|
|
{ strokeWidth: 4, label: "4", value: 4 },
|
|
{ strokeWidth: 8, label: "8", value: 8 }
|
|
];
|
|
var LINE_STYLE_TYPE_ITEMS = [
|
|
{ icon: "line-style-solid", altText: "iconAltTextLineStyleSolid", value: "solid" },
|
|
{ icon: "line-style-dashed", altText: "iconAltTextLineStyleDashed", value: "dashed" },
|
|
{ icon: "line-style-dotted", altText: "iconAltTextLineStyleDotted", value: "dotted" }
|
|
];
|
|
var TEXT_SIZE_ITEMS = [
|
|
{ label: "10", value: 10 },
|
|
{ label: "12", value: 12 },
|
|
{ label: "14", value: 14 },
|
|
{ label: "16", value: 16 },
|
|
{ label: "18", value: 18 },
|
|
{ label: "22", value: 22 },
|
|
{ label: "28", value: 28 },
|
|
{ label: "36", value: 36 },
|
|
{ label: "46", value: 46 }
|
|
];
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/annotationOptionsToolbar.ts
|
|
var { FloatingToolbar, Menu, ToolbarButtonWidget } = _ModuleSupport33;
|
|
var AnnotationOptionsButtonProperties = class extends ToolbarButtonProperties {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.checkedOverrides = new ToolbarButtonProperties();
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property32
|
|
], AnnotationOptionsButtonProperties.prototype, "value", 2);
|
|
__decorateClass([
|
|
Property32
|
|
], AnnotationOptionsButtonProperties.prototype, "checkedOverrides", 2);
|
|
__decorateClass([
|
|
Property32
|
|
], AnnotationOptionsButtonProperties.prototype, "color", 2);
|
|
__decorateClass([
|
|
Property32
|
|
], AnnotationOptionsButtonProperties.prototype, "strokeWidth", 2);
|
|
__decorateClass([
|
|
Property32
|
|
], AnnotationOptionsButtonProperties.prototype, "isMultiColor", 2);
|
|
var AnnotationOptionsButtonWidget = class extends ToolbarButtonWidget {
|
|
update(options) {
|
|
super.update(options);
|
|
if (options.value === "line-stroke-width" /* LineStrokeWidth */) {
|
|
this.updateLineStrokeWidth(options);
|
|
}
|
|
if (options.value === "fill-color" /* FillColor */ || options.value === "line-color" /* LineColor */ || options.value === "text-color" /* TextColor */) {
|
|
this.updateFillColor(options);
|
|
}
|
|
}
|
|
updateFillColor(options) {
|
|
const element = this.getElement();
|
|
element.classList.add("ag-charts-annotations__color-picker-button");
|
|
element.classList.toggle("ag-charts-annotations__color-picker-button--multi-color", options.isMultiColor);
|
|
element.style.setProperty("--color", options.color ?? null);
|
|
}
|
|
updateLineStrokeWidth(options) {
|
|
const element = this.getElement();
|
|
element.classList.add("ag-charts-annotations__stroke-width-button");
|
|
element.style.setProperty("--stroke-width", `${options.strokeWidth}px`);
|
|
}
|
|
};
|
|
var FloatingAnnotationOptionsToolbar = class extends FloatingToolbar {
|
|
createButtonWidget() {
|
|
return new AnnotationOptionsButtonWidget(this.localeManager);
|
|
}
|
|
};
|
|
var AnnotationOptionsToolbar = class extends BaseProperties14 {
|
|
constructor(ctx, getActiveDatum) {
|
|
super();
|
|
this.ctx = ctx;
|
|
this.getActiveDatum = getActiveDatum;
|
|
this.enabled = true;
|
|
this.buttons = new PropertiesArray(AnnotationOptionsButtonProperties);
|
|
this.cleanup = new CleanupRegistry2();
|
|
this.events = new EventEmitter();
|
|
this.visibleButtons = [];
|
|
this.toolbar = new FloatingAnnotationOptionsToolbar(
|
|
this.ctx,
|
|
"ariaLabelAnnotationOptionsToolbar",
|
|
"annotation-options"
|
|
);
|
|
this.colorPicker = new ColorPicker(this.ctx);
|
|
this.textSizeMenu = new Menu(this.ctx, "text-size");
|
|
this.lineStyleTypeMenu = new Menu(this.ctx, "annotations-line-style-type");
|
|
this.lineStrokeWidthMenu = new Menu(this.ctx, "annotations-line-stroke-width");
|
|
this.cleanup.register(
|
|
this.toolbar.addToolbarListener("button-pressed", this.onButtonPress.bind(this)),
|
|
this.toolbar.addToolbarListener("toolbar-moved", this.onToolbarMoved.bind(this)),
|
|
ctx.widgets.seriesWidget.addListener("drag-start", this.onDragStart.bind(this)),
|
|
ctx.widgets.seriesWidget.addListener("drag-end", this.onDragEnd.bind(this)),
|
|
() => {
|
|
this.colorPicker.destroy();
|
|
this.toolbar.destroy();
|
|
}
|
|
);
|
|
}
|
|
onDragStart() {
|
|
this.toolbar.ignorePointerEvents();
|
|
}
|
|
onDragEnd() {
|
|
this.toolbar.capturePointerEvents();
|
|
}
|
|
destroy() {
|
|
this.cleanup.flush();
|
|
}
|
|
show() {
|
|
if (!this.enabled)
|
|
return;
|
|
this.toolbar.show();
|
|
}
|
|
hide() {
|
|
this.toolbar.hide();
|
|
}
|
|
updateButtons(datum) {
|
|
if (!this.enabled)
|
|
return;
|
|
const visible = {
|
|
["line-style-type" /* LineStyleType */]: hasLineStyle(datum),
|
|
["line-stroke-width" /* LineStrokeWidth */]: hasLineStyle(datum),
|
|
["line-color" /* LineColor */]: hasLineColor(datum),
|
|
["text-color" /* TextColor */]: hasTextColor(datum),
|
|
["fill-color" /* FillColor */]: hasFillColor(datum),
|
|
["text-size" /* TextSize */]: hasFontSize(datum),
|
|
["settings" /* Settings */]: hasLineText(datum),
|
|
["lock" /* Lock */]: true,
|
|
["delete" /* Delete */]: true
|
|
};
|
|
this.visibleButtons = this.buttons.filter((button) => visible[button.value]);
|
|
this.toolbar.clearButtons();
|
|
this.toolbar.updateButtons(this.visibleButtons);
|
|
this.refreshButtons(datum);
|
|
}
|
|
setAnchorScene(scene) {
|
|
if (this.toolbar.hasBeenDragged())
|
|
return;
|
|
this.toolbar.setAnchor(scene.getAnchor());
|
|
}
|
|
hideOverlays() {
|
|
this.toolbar.clearActiveButton();
|
|
this.colorPicker.hide({ lastFocus: null });
|
|
this.textSizeMenu.hide();
|
|
this.lineStyleTypeMenu.hide();
|
|
this.lineStrokeWidthMenu.hide();
|
|
this.events.emit("hid-overlays", null);
|
|
}
|
|
clearActiveButton() {
|
|
this.toolbar.clearActiveButton();
|
|
}
|
|
updateColors(datum) {
|
|
this.updateColorPickerColor(
|
|
"line-color" /* LineColor */,
|
|
datum.getDefaultColor("line-color" /* LineColor */),
|
|
datum.getDefaultOpacity("line-color" /* LineColor */),
|
|
"isMultiColor" in datum && datum?.isMultiColor
|
|
);
|
|
this.updateColorPickerColor(
|
|
"fill-color" /* FillColor */,
|
|
datum.getDefaultColor("fill-color" /* FillColor */),
|
|
datum.getDefaultOpacity("fill-color" /* FillColor */),
|
|
"isMultiColor" in datum && datum?.isMultiColor
|
|
);
|
|
this.updateColorPickerColor(
|
|
"text-color" /* TextColor */,
|
|
datum.getDefaultColor("text-color" /* TextColor */),
|
|
datum.getDefaultOpacity("text-color" /* TextColor */),
|
|
"isMultiColor" in datum && datum?.isMultiColor
|
|
);
|
|
}
|
|
updateColorPickerColor(colorPickerType, color7, opacity, isMultiColor) {
|
|
if (color7 != null && opacity != null) {
|
|
const { r, g, b } = Color4.fromString(color7);
|
|
color7 = Color4.fromArray([r, g, b, opacity]).toHexString();
|
|
}
|
|
this.updateButtonByValue(colorPickerType, { color: color7, isMultiColor });
|
|
}
|
|
updateFontSize(fontSize) {
|
|
this.updateButtonByValue("text-size" /* TextSize */, {
|
|
label: fontSize == null ? void 0 : String(fontSize)
|
|
});
|
|
}
|
|
updateLineStyleType(item) {
|
|
this.updateButtonByValue("line-style-type" /* LineStyleType */, {
|
|
icon: item.icon
|
|
});
|
|
}
|
|
updateStrokeWidth(item) {
|
|
this.updateButtonByValue("line-stroke-width" /* LineStrokeWidth */, {
|
|
label: item.label,
|
|
strokeWidth: item.value
|
|
});
|
|
}
|
|
onButtonPress({
|
|
event,
|
|
button,
|
|
buttonWidget
|
|
}) {
|
|
const datum = this.getActiveDatum();
|
|
if (!datum)
|
|
return;
|
|
this.hideOverlays();
|
|
switch (button.value) {
|
|
case "line-style-type" /* LineStyleType */: {
|
|
const lineStyle = hasLineStyle(datum) ? getLineStyle(datum.lineDash, datum.lineStyle) : void 0;
|
|
this.lineStyleTypeMenu.show(buttonWidget, {
|
|
items: LINE_STYLE_TYPE_ITEMS,
|
|
ariaLabel: this.ctx.localeManager.t("toolbarAnnotationsLineStyle"),
|
|
value: lineStyle,
|
|
onPress: (item) => this.onLineStyleTypeMenuPress(item, datum),
|
|
class: "ag-charts-annotations__line-style-type-menu"
|
|
});
|
|
break;
|
|
}
|
|
case "line-stroke-width" /* LineStrokeWidth */: {
|
|
const strokeWidth = hasLineStyle(datum) ? datum.strokeWidth : void 0;
|
|
this.lineStrokeWidthMenu.show(buttonWidget, {
|
|
items: LINE_STROKE_WIDTH_ITEMS,
|
|
ariaLabel: this.ctx.localeManager.t("toolbarAnnotationsLineStrokeWidth"),
|
|
value: strokeWidth,
|
|
onPress: (item) => this.onLineStrokeWidthMenuPress(item, datum),
|
|
class: "ag-charts-annotations__line-stroke-width-menu"
|
|
});
|
|
break;
|
|
}
|
|
case "line-color" /* LineColor */:
|
|
case "fill-color" /* FillColor */:
|
|
case "text-color" /* TextColor */: {
|
|
this.toolbar.toggleActiveButtonByIndex(button.index);
|
|
this.colorPicker.show({
|
|
color: datum?.getDefaultColor(button.value),
|
|
opacity: datum?.getDefaultOpacity(button.value),
|
|
sourceEvent: event.sourceEvent,
|
|
hasMultiColorOption: "isMultiColor" in datum,
|
|
isMultiColor: "isMultiColor" in datum && datum?.isMultiColor,
|
|
onChange: datum == null ? void 0 : this.onColorPickerChange.bind(this, button.value, datum),
|
|
onChangeHide: ((type) => {
|
|
this.events.emit("saved-color", {
|
|
type: datum.type,
|
|
colorPickerType: button.value,
|
|
color: datum.getDefaultColor(type)
|
|
});
|
|
}).bind(this, button.value)
|
|
});
|
|
break;
|
|
}
|
|
case "text-size" /* TextSize */: {
|
|
const fontSize = isTextType(datum) ? datum.fontSize : void 0;
|
|
this.textSizeMenu.show(buttonWidget, {
|
|
items: TEXT_SIZE_ITEMS,
|
|
ariaLabel: this.ctx.localeManager.t("toolbarAnnotationsTextSize"),
|
|
value: fontSize,
|
|
onPress: (item) => this.onTextSizeMenuPress(item, datum),
|
|
class: "ag-charts-annotations__text-size-menu"
|
|
});
|
|
break;
|
|
}
|
|
case "delete" /* Delete */: {
|
|
this.events.emit("pressed-delete", null);
|
|
break;
|
|
}
|
|
case "lock" /* Lock */: {
|
|
datum.locked = !datum.locked;
|
|
this.refreshButtons(datum);
|
|
this.events.emit("pressed-lock", { locked: datum.locked });
|
|
break;
|
|
}
|
|
case "settings" /* Settings */: {
|
|
this.toolbar.toggleActiveButtonByIndex(button.index);
|
|
this.events.emit("pressed-settings", event);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
onToolbarMoved(event) {
|
|
const { buttonBounds, popoverBounds } = event;
|
|
const colorPickerAnchor = { x: popoverBounds.x, y: popoverBounds.y + popoverBounds.height + 4 };
|
|
const colorPickerFallbackAnchor = { y: popoverBounds.y - 4 };
|
|
this.colorPicker.setAnchor(colorPickerAnchor, colorPickerFallbackAnchor);
|
|
for (const [index, bounds] of buttonBounds.entries()) {
|
|
const button = this.visibleButtons.at(index);
|
|
if (!button)
|
|
continue;
|
|
const anchor = { x: bounds.x, y: bounds.y + bounds.height - 1 };
|
|
const fallbackAnchor = { y: bounds.y };
|
|
switch (button.value) {
|
|
case "line-stroke-width" /* LineStrokeWidth */:
|
|
this.lineStrokeWidthMenu.setAnchor(anchor, fallbackAnchor);
|
|
break;
|
|
case "line-style-type" /* LineStyleType */:
|
|
this.lineStyleTypeMenu.setAnchor(anchor, fallbackAnchor);
|
|
break;
|
|
case "text-size" /* TextSize */:
|
|
this.textSizeMenu.setAnchor(anchor, fallbackAnchor);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
onColorPickerChange(colorPickerType, datum, colorOpacity, color7, opacity, isMultiColor) {
|
|
this.events.emit("updated-color", {
|
|
type: datum.type,
|
|
colorPickerType,
|
|
colorOpacity,
|
|
color: color7,
|
|
opacity,
|
|
isMultiColor
|
|
});
|
|
this.updateColorPickerColor(colorPickerType, colorOpacity, opacity, isMultiColor);
|
|
}
|
|
onTextSizeMenuPress(item, datum) {
|
|
if (!hasFontSize(datum))
|
|
return;
|
|
const fontSize = item.value;
|
|
this.events.emit("updated-font-size", { type: datum.type, fontSize });
|
|
this.textSizeMenu.hide();
|
|
this.updateFontSize(fontSize);
|
|
}
|
|
onLineStyleTypeMenuPress(item, datum) {
|
|
if (!hasLineStyle(datum))
|
|
return;
|
|
const type = item.value;
|
|
this.events.emit("updated-line-style", { type: datum.type, lineStyleType: type });
|
|
this.lineStyleTypeMenu.hide();
|
|
this.updateLineStyleType(item);
|
|
}
|
|
onLineStrokeWidthMenuPress(item, datum) {
|
|
if (!hasLineStyle(datum)) {
|
|
return;
|
|
}
|
|
const strokeWidth = item.value;
|
|
this.events.emit("updated-line-width", { type: datum.type, strokeWidth });
|
|
this.lineStrokeWidthMenu.hide();
|
|
this.updateStrokeWidth(item);
|
|
}
|
|
refreshButtons(datum) {
|
|
const locked = datum.locked ?? false;
|
|
for (const [index, button] of this.visibleButtons.entries()) {
|
|
if (!button)
|
|
continue;
|
|
if (button.value === "lock" /* Lock */) {
|
|
this.toolbar.toggleSwitchCheckedByIndex(index, locked);
|
|
this.updateButtonByIndex(index, locked ? button.checkedOverrides.toJson() : button.toJson());
|
|
} else {
|
|
this.toolbar.toggleButtonEnabledByIndex(index, !locked);
|
|
}
|
|
}
|
|
if (hasFontSize(datum))
|
|
this.updateFontSize(datum.fontSize);
|
|
this.updateColors(datum);
|
|
this.updateLineStyles(datum);
|
|
}
|
|
updateLineStyles(datum) {
|
|
if (!hasLineStyle(datum))
|
|
return;
|
|
const strokeWidth = datum.strokeWidth ?? 1;
|
|
const lineStyleType = getLineStyle(datum.lineDash, datum.lineStyle);
|
|
this.updateStrokeWidth({
|
|
strokeWidth,
|
|
value: strokeWidth,
|
|
label: String(strokeWidth)
|
|
});
|
|
this.updateLineStyleType(
|
|
LINE_STYLE_TYPE_ITEMS.find((item) => item.value === lineStyleType) ?? LINE_STYLE_TYPE_ITEMS[0]
|
|
);
|
|
}
|
|
updateButtonByValue(value, change) {
|
|
const index = this.visibleButtons.findIndex((button) => button.value === value);
|
|
if (index === -1)
|
|
return;
|
|
this.updateButtonByIndex(index, change);
|
|
}
|
|
updateButtonByIndex(index, change) {
|
|
const button = this.visibleButtons.at(index);
|
|
if (!button)
|
|
return;
|
|
this.toolbar.updateButtonByIndex(index, { ...button.toJson(), ...change, value: change.value ?? button.value });
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property32
|
|
], AnnotationOptionsToolbar.prototype, "enabled", 2);
|
|
__decorateClass([
|
|
Property32
|
|
], AnnotationOptionsToolbar.prototype, "buttons", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/states/dragState.ts
|
|
import { Debug, StateMachine, StateMachineProperty, Vec2 as Vec22 } from "ag-charts-core";
|
|
var DragStateMachine = class extends StateMachine {
|
|
constructor(ctx) {
|
|
const actionKeyChange = ({ context }) => {
|
|
this.node?.drag(this.datum, this.offset, context, this.snapping);
|
|
ctx.update();
|
|
};
|
|
super("idle", {
|
|
idle: {
|
|
dragStart: {
|
|
target: "dragging",
|
|
action: ({ offset, context }) => {
|
|
this.hasMoved = false;
|
|
this.dragStart = offset;
|
|
this.offset = offset;
|
|
this.node?.dragStart(this.datum, offset, context);
|
|
}
|
|
}
|
|
},
|
|
dragging: {
|
|
keyDown: actionKeyChange,
|
|
keyUp: actionKeyChange,
|
|
drag: ({ offset, context }) => {
|
|
this.hasMoved = Vec22.lengthSquared(Vec22.sub(offset, this.dragStart)) > 0;
|
|
this.offset = offset;
|
|
this.node?.drag(this.datum, offset, context, this.snapping);
|
|
ctx.update();
|
|
},
|
|
dragEnd: {
|
|
target: StateMachine.parent,
|
|
action: () => {
|
|
this.node?.stopDragging();
|
|
if (this.hasMoved)
|
|
ctx.recordAction("Move annotation");
|
|
ctx.update();
|
|
}
|
|
}
|
|
}
|
|
});
|
|
this.debug = Debug.create(true, "annotations");
|
|
this.hasMoved = false;
|
|
this.snapping = false;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
StateMachineProperty()
|
|
], DragStateMachine.prototype, "snapping", 2);
|
|
__decorateClass([
|
|
StateMachineProperty()
|
|
], DragStateMachine.prototype, "datum", 2);
|
|
__decorateClass([
|
|
StateMachineProperty()
|
|
], DragStateMachine.prototype, "node", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/arrow-down/arrowDownProperties.ts
|
|
import { Property as Property33, isObject as isObject13 } from "ag-charts-core";
|
|
var ArrowDownProperties = class extends ShapePointProperties {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.type = "arrow-down" /* ArrowDown */;
|
|
}
|
|
static is(value) {
|
|
return isObject13(value) && value.type === "arrow-down" /* ArrowDown */;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property33
|
|
], ArrowDownProperties.prototype, "type", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/arrow-down/arrowDownScene.ts
|
|
import { _ModuleSupport as _ModuleSupport39 } from "ag-charts-community";
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/arrow-up/arrowUpScene.ts
|
|
import { _ModuleSupport as _ModuleSupport38 } from "ag-charts-community";
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/scenes/annotationScene.ts
|
|
import { _ModuleSupport as _ModuleSupport36 } from "ag-charts-community";
|
|
import { ZIndexMap as ZIndexMap3, isObject as isObject14 } from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/scenes/handle.ts
|
|
import { _ModuleSupport as _ModuleSupport35 } from "ag-charts-community";
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/scenes/annotationShape.ts
|
|
import { _ModuleSupport as _ModuleSupport34 } from "ag-charts-community";
|
|
var AnnotationShape = class extends _ModuleSupport34.Marker {
|
|
// Use exact method for this, rather than the Marker's high performance approximation.
|
|
isPointInPath(x, y) {
|
|
this.updatePathIfDirty();
|
|
return this.path.closedPath && this.path.isPointInPath(x, y);
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/scenes/handle.ts
|
|
var _Handle = class _Handle extends _ModuleSupport35.Group {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.active = false;
|
|
this.locked = false;
|
|
this.visible = false;
|
|
this.zIndex = 1;
|
|
}
|
|
drag(target) {
|
|
const { handle: handle3, locked } = this;
|
|
if (locked) {
|
|
return { point: { x: handle3.x, y: handle3.y }, offset: { x: 0, y: 0 } };
|
|
}
|
|
return {
|
|
point: target,
|
|
offset: { x: target.x - handle3.x, y: target.y - handle3.y }
|
|
};
|
|
}
|
|
toggleActive(active) {
|
|
this.active = active;
|
|
if (!active) {
|
|
this.handle.strokeWidth = _Handle.INACTIVE_STROKE_WIDTH;
|
|
}
|
|
}
|
|
toggleHovered(hovered) {
|
|
this.glow.visible = !this.locked && hovered;
|
|
this.glow.dirtyPath = true;
|
|
}
|
|
toggleDragging(dragging) {
|
|
if (this.locked)
|
|
return;
|
|
this.handle.visible = !dragging;
|
|
this.glow.visible = this.glow.visible && !dragging;
|
|
this.handle.dirtyPath = true;
|
|
this.glow.dirtyPath = true;
|
|
}
|
|
toggleLocked(locked) {
|
|
this.locked = locked;
|
|
}
|
|
getCursor() {
|
|
return void 0;
|
|
}
|
|
containsPoint(x, y) {
|
|
return this.handle.containsPoint(x, y);
|
|
}
|
|
};
|
|
_Handle.INACTIVE_STROKE_WIDTH = 2;
|
|
var Handle2 = _Handle;
|
|
var _InvariantHandle = class _InvariantHandle extends Handle2 {
|
|
constructor() {
|
|
super();
|
|
this.handle = new AnnotationShape({ shape: "circle" });
|
|
this.glow = new AnnotationShape({ shape: "circle" });
|
|
this.append([this.handle]);
|
|
this.handle.size = _InvariantHandle.HANDLE_SIZE;
|
|
this.handle.strokeWidth = Handle2.INACTIVE_STROKE_WIDTH;
|
|
this.handle.zIndex = 2;
|
|
}
|
|
update(styles) {
|
|
this.handle.setProperties({ ...styles, strokeWidth: Handle2.INACTIVE_STROKE_WIDTH });
|
|
}
|
|
drag(target) {
|
|
return { point: target, offset: { x: 0, y: 0 } };
|
|
}
|
|
};
|
|
_InvariantHandle.HANDLE_SIZE = 7;
|
|
_InvariantHandle.GLOW_SIZE = 9;
|
|
var InvariantHandle = _InvariantHandle;
|
|
var _UnivariantHandle = class _UnivariantHandle extends Handle2 {
|
|
constructor() {
|
|
super();
|
|
this.handle = new _ModuleSupport35.Rect();
|
|
this.glow = new _ModuleSupport35.Rect();
|
|
this.gradient = "horizontal";
|
|
this.append([this.glow, this.handle]);
|
|
this.handle.cornerRadius = _UnivariantHandle.CORNER_RADIUS;
|
|
this.handle.width = _UnivariantHandle.HANDLE_SIZE;
|
|
this.handle.height = _UnivariantHandle.HANDLE_SIZE;
|
|
this.handle.strokeWidth = Handle2.INACTIVE_STROKE_WIDTH;
|
|
this.handle.zIndex = 2;
|
|
this.glow.cornerRadius = _UnivariantHandle.CORNER_RADIUS;
|
|
this.glow.width = _UnivariantHandle.GLOW_SIZE;
|
|
this.glow.height = _UnivariantHandle.GLOW_SIZE;
|
|
this.glow.strokeWidth = 0;
|
|
this.glow.fillOpacity = 0.2;
|
|
this.glow.zIndex = 1;
|
|
this.glow.visible = false;
|
|
}
|
|
toggleLocked(locked) {
|
|
super.toggleLocked(locked);
|
|
if (locked) {
|
|
const offset = (_UnivariantHandle.HANDLE_SIZE - InvariantHandle.HANDLE_SIZE) / 2;
|
|
this.handle.cornerRadius = 1;
|
|
this.handle.fill = this.handle.stroke;
|
|
this.handle.strokeWidth = 0;
|
|
this.handle.x += offset;
|
|
this.handle.y += offset;
|
|
this.handle.width = InvariantHandle.HANDLE_SIZE;
|
|
this.handle.height = InvariantHandle.HANDLE_SIZE;
|
|
this.glow.width = InvariantHandle.GLOW_SIZE;
|
|
this.glow.height = InvariantHandle.GLOW_SIZE;
|
|
} else {
|
|
this.handle.cornerRadius = _UnivariantHandle.CORNER_RADIUS;
|
|
this.handle.width = _UnivariantHandle.HANDLE_SIZE;
|
|
this.handle.height = _UnivariantHandle.HANDLE_SIZE;
|
|
this.glow.width = _UnivariantHandle.GLOW_SIZE;
|
|
this.glow.height = _UnivariantHandle.GLOW_SIZE;
|
|
if (this.cachedStyles) {
|
|
this.handle.setProperties(this.cachedStyles);
|
|
}
|
|
}
|
|
}
|
|
update(styles) {
|
|
this.cachedStyles = { ...styles };
|
|
if (!this.active) {
|
|
delete styles.strokeWidth;
|
|
}
|
|
if (this.locked) {
|
|
delete styles.fill;
|
|
delete styles.strokeWidth;
|
|
const offset = (_UnivariantHandle.HANDLE_SIZE - InvariantHandle.HANDLE_SIZE) / 2;
|
|
styles.x -= offset;
|
|
styles.y -= offset;
|
|
this.cachedStyles.x -= offset;
|
|
this.cachedStyles.y -= offset;
|
|
}
|
|
this.handle.setProperties(styles);
|
|
this.glow.setProperties({
|
|
...styles,
|
|
x: (styles.x ?? this.glow.x) - 2,
|
|
y: (styles.y ?? this.glow.y) - 2,
|
|
strokeWidth: 0,
|
|
fill: styles.stroke
|
|
});
|
|
}
|
|
drag(target) {
|
|
if (this.locked) {
|
|
return { point: target, offset: { x: 0, y: 0 } };
|
|
}
|
|
if (this.gradient === "vertical") {
|
|
return {
|
|
point: { x: target.x, y: this.handle.y },
|
|
offset: { x: target.x - this.handle.x, y: 0 }
|
|
};
|
|
}
|
|
return {
|
|
point: { x: this.handle.x, y: target.y },
|
|
offset: { x: 0, y: target.y - this.handle.y }
|
|
};
|
|
}
|
|
getCursor() {
|
|
if (this.locked)
|
|
return;
|
|
return this.gradient === "vertical" ? "col-resize" : "row-resize";
|
|
}
|
|
};
|
|
_UnivariantHandle.HANDLE_SIZE = 12;
|
|
_UnivariantHandle.GLOW_SIZE = 16;
|
|
_UnivariantHandle.CORNER_RADIUS = 4;
|
|
var UnivariantHandle = _UnivariantHandle;
|
|
var _DivariantHandle = class _DivariantHandle extends Handle2 {
|
|
constructor() {
|
|
super();
|
|
this.handle = new AnnotationShape({ shape: "circle" });
|
|
this.glow = new AnnotationShape({ shape: "circle" });
|
|
this.append([this.glow, this.handle]);
|
|
this.handle.size = _DivariantHandle.HANDLE_SIZE;
|
|
this.handle.strokeWidth = Handle2.INACTIVE_STROKE_WIDTH;
|
|
this.handle.zIndex = 2;
|
|
this.glow.size = _DivariantHandle.GLOW_SIZE;
|
|
this.glow.strokeWidth = 0;
|
|
this.glow.fillOpacity = 0.2;
|
|
this.glow.zIndex = 1;
|
|
this.glow.visible = false;
|
|
}
|
|
toggleLocked(locked) {
|
|
super.toggleLocked(locked);
|
|
if (locked) {
|
|
this.handle.fill = this.handle.stroke;
|
|
this.handle.strokeWidth = 0;
|
|
this.handle.size = InvariantHandle.HANDLE_SIZE;
|
|
this.glow.size = InvariantHandle.GLOW_SIZE;
|
|
} else {
|
|
this.handle.size = _DivariantHandle.HANDLE_SIZE;
|
|
this.glow.size = _DivariantHandle.GLOW_SIZE;
|
|
if (this.cachedStyles) {
|
|
this.handle.setProperties(this.cachedStyles);
|
|
}
|
|
}
|
|
}
|
|
update(styles) {
|
|
this.cachedStyles = { ...styles };
|
|
if (!this.active) {
|
|
delete styles.strokeWidth;
|
|
}
|
|
if (this.locked) {
|
|
delete styles.fill;
|
|
delete styles.strokeWidth;
|
|
}
|
|
this.handle.setProperties(styles);
|
|
this.glow.setProperties({ ...styles, strokeWidth: 0, fill: styles.stroke });
|
|
}
|
|
getCursor() {
|
|
return "pointer";
|
|
}
|
|
};
|
|
_DivariantHandle.HANDLE_SIZE = 11;
|
|
_DivariantHandle.GLOW_SIZE = 17;
|
|
var DivariantHandle = _DivariantHandle;
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/scenes/annotationScene.ts
|
|
var AnnotationScene = class extends _ModuleSupport36.Group {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.name = "AnnotationScene";
|
|
this.zIndex = ZIndexMap3.CHART_ANNOTATION;
|
|
}
|
|
static isCheck(value, type) {
|
|
return isObject14(value) && Object.hasOwn(value, "type") && value.type === type;
|
|
}
|
|
toggleHovered(hovered, active, readOnly) {
|
|
if (readOnly === true)
|
|
return;
|
|
this.toggleHandles(hovered || active);
|
|
}
|
|
computeBBoxWithoutHandles() {
|
|
return _ModuleSupport36.Transformable.toCanvas(
|
|
this,
|
|
_ModuleSupport36.Group.computeChildrenBBox(this.excludeChildren({ instance: Handle2 }))
|
|
);
|
|
}
|
|
updateNode(constructor, node, isConfigured) {
|
|
if (!isConfigured && node) {
|
|
node.remove();
|
|
return;
|
|
}
|
|
if (isConfigured && node == null) {
|
|
node = new constructor();
|
|
this.appendChild(node);
|
|
}
|
|
return node;
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/scenes/pointScene.ts
|
|
import { Vec2 as Vec24 } from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/utils/coords.ts
|
|
import { _ModuleSupport as _ModuleSupport37 } from "ag-charts-community";
|
|
import { Vec2 as Vec23, entries, toRadians as toRadians3 } from "ag-charts-core";
|
|
var { ContinuousScale: ContinuousScale2 } = _ModuleSupport37;
|
|
function snapPoint(offset, context, snapping = false, origin, angleStep = 1) {
|
|
if (!snapping)
|
|
return invertCoords(offset, context);
|
|
const center = origin ? convertPoint(origin, context) : Vec23.origin();
|
|
return invertCoords(snapToAngle(offset, center, angleStep), context);
|
|
}
|
|
function snapToAngle(vector, center, step) {
|
|
const radial = Vec23.sub(vector, center);
|
|
const stepRadians = toRadians3(step);
|
|
const theta = Math.round(Vec23.angle(radial) / stepRadians) * stepRadians;
|
|
return Vec23.rotate(radial, theta, center);
|
|
}
|
|
function getDragStartState(points, context) {
|
|
const dragState = {};
|
|
for (const [name, point] of entries(points)) {
|
|
dragState[name] = convertPoint(point, context);
|
|
}
|
|
return dragState;
|
|
}
|
|
function translate(vectors, translation, context, options = {
|
|
overflowContinuous: 0,
|
|
translateVectors: void 0,
|
|
invertYVectors: void 0,
|
|
snap: void 0
|
|
}) {
|
|
const { xAxis, yAxis } = context;
|
|
const vectorNames = Object.keys(vectors);
|
|
const overflowsX = [];
|
|
const overflowsY = [];
|
|
const translateVectors = new Set(options.translateVectors ?? vectorNames);
|
|
const invertYVectors = new Set(options.invertYVectors ?? []);
|
|
const movingVectors = /* @__PURE__ */ new Set([...translateVectors, ...invertYVectors]);
|
|
const invertYTranslation = Vec23.multiply(translation, Vec23.from(1, -1));
|
|
for (const name of vectorNames) {
|
|
if (movingVectors.has(name)) {
|
|
vectors[name] = Vec23.add(vectors[name], invertYVectors.has(name) ? invertYTranslation : translation);
|
|
if (options.snap) {
|
|
vectors[name] = snapToAngle(vectors[name], options.snap.vectors[name], options.snap.angle);
|
|
}
|
|
}
|
|
overflowsX.push(xAxis.getRangeOverflow(vectors[name].x));
|
|
overflowsY.push(yAxis.getRangeOverflow(vectors[name].y));
|
|
}
|
|
const sortNumbersAbs = (a, b) => Math.abs(a) - Math.abs(b);
|
|
const overflowDirection = (scale, directionTranslation, overflows) => {
|
|
if (options.overflowContinuous === 0 || !ContinuousScale2.is(scale)) {
|
|
return overflows.toSorted(sortNumbersAbs).at(-1) ?? 0;
|
|
}
|
|
if (vectorNames.length === movingVectors.size) {
|
|
return overflows.toSorted(sortNumbersAbs).at(-options.overflowContinuous - 1) ?? 0;
|
|
}
|
|
if (overflows.filter((value) => value !== 0).length <= options.overflowContinuous) {
|
|
return 0;
|
|
}
|
|
const newTranslatedOverflows = overflows.filter(
|
|
(value, index) => value !== 0 && Math.abs(value) <= Math.abs(directionTranslation) && movingVectors.has(vectorNames[index])
|
|
);
|
|
return newTranslatedOverflows.toSorted(sortNumbersAbs).at(-1) ?? 0;
|
|
};
|
|
const overflow = Vec23.from(
|
|
overflowDirection(xAxis.scale, translation.x, overflowsX),
|
|
overflowDirection(yAxis.scale, translation.y, overflowsY)
|
|
);
|
|
if (!Vec23.equal(overflow, Vec23.origin())) {
|
|
for (const name of vectorNames) {
|
|
if (!movingVectors.has(name))
|
|
continue;
|
|
vectors[name] = Vec23.round(Vec23.sub(vectors[name], overflow), 4);
|
|
}
|
|
}
|
|
const result = {};
|
|
for (const name of vectorNames) {
|
|
result[name] = invertCoords(vectors[name], context);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/scenes/pointScene.ts
|
|
var PointScene = class extends AnnotationScene {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.handle = new DivariantHandle();
|
|
this.anchor = {
|
|
x: 0,
|
|
y: 0,
|
|
position: "above"
|
|
};
|
|
}
|
|
update(datum, context) {
|
|
const coords = convertPoint(datum, context);
|
|
this.updateHandle(datum, coords);
|
|
this.anchor = this.updateAnchor(datum, coords, context);
|
|
}
|
|
dragStart(datum, target, context) {
|
|
this.dragState = {
|
|
offset: target,
|
|
...getDragStartState({ handle: datum }, context)
|
|
};
|
|
}
|
|
drag(datum, target, context) {
|
|
const { dragState } = this;
|
|
if (!datum.isWriteable() || !dragState)
|
|
return;
|
|
const { point } = translate({ point: dragState.handle }, Vec24.sub(target, dragState.offset), context);
|
|
datum.x = point.x;
|
|
datum.y = point.y;
|
|
}
|
|
translate(datum, translation, context) {
|
|
if (!datum.isWriteable())
|
|
return;
|
|
const { point } = translate({ point: convertPoint(datum, context) }, translation, context);
|
|
datum.x = point.x;
|
|
datum.y = point.y;
|
|
}
|
|
toggleHandles(show) {
|
|
this.handle.visible = Boolean(show);
|
|
this.handle.toggleHovered(this.activeHandle === "handle");
|
|
}
|
|
toggleActive(active) {
|
|
this.toggleHandles(active);
|
|
this.handle.toggleActive(active);
|
|
}
|
|
stopDragging() {
|
|
this.handle.toggleDragging(false);
|
|
}
|
|
copy(datum, copiedDatum, context) {
|
|
const coords = convertPoint(datum, context);
|
|
const point = invertCoords({ x: coords.x - 30, y: coords.y - 30 }, context);
|
|
copiedDatum.x = point.x;
|
|
copiedDatum.y = point.y;
|
|
return copiedDatum;
|
|
}
|
|
getAnchor() {
|
|
return this.anchor;
|
|
}
|
|
getCursor() {
|
|
return "pointer";
|
|
}
|
|
containsPoint(x, y) {
|
|
const { handle: handle3 } = this;
|
|
this.activeHandle = void 0;
|
|
if (handle3.containsPoint(x, y)) {
|
|
this.activeHandle = "handle";
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
getNodeAtCoords(x, y) {
|
|
if (this.handle.containsPoint(x, y))
|
|
return "handle";
|
|
}
|
|
updateHandle(datum, point, bbox) {
|
|
const { x, y } = this.getHandleCoords(datum, point, bbox);
|
|
const styles = this.getHandleStyles(datum);
|
|
this.handle.update({ ...styles, x, y });
|
|
this.handle.toggleLocked(datum.locked ?? false);
|
|
}
|
|
updateAnchor(datum, point, context) {
|
|
const coords = this.getHandleCoords(datum, point);
|
|
return {
|
|
x: coords.x + context.seriesRect.x,
|
|
y: coords.y + context.seriesRect.y,
|
|
position: this.anchor.position
|
|
};
|
|
}
|
|
getHandleCoords(_datum, point, _bbox) {
|
|
return {
|
|
x: point.x,
|
|
y: point.y
|
|
};
|
|
}
|
|
getHandleStyles(datum) {
|
|
return {
|
|
fill: datum.handle.fill,
|
|
stroke: datum.handle.stroke,
|
|
strokeOpacity: datum.handle.strokeOpacity,
|
|
strokeWidth: datum.handle.strokeWidth
|
|
};
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/scenes/shapePointScene.ts
|
|
var ShapePointScene = class extends PointScene {
|
|
constructor() {
|
|
super();
|
|
this.append([this.handle]);
|
|
}
|
|
update(datum, context) {
|
|
super.update(datum, context);
|
|
const coords = convertPoint(datum, context);
|
|
this.updateShape(datum, coords);
|
|
}
|
|
updateShape(datum, point) {
|
|
this.updateShapeStyles(datum);
|
|
this.updateShapePath(datum, point);
|
|
}
|
|
updateShapeStyles(datum) {
|
|
const { shape } = this;
|
|
shape.fill = datum.fill;
|
|
shape.fillOpacity = datum.fillOpacity ?? 1;
|
|
}
|
|
updateShapePath(datum, point) {
|
|
const { shape } = this;
|
|
shape.x = point.x;
|
|
shape.y = point.y;
|
|
shape.size = datum.size;
|
|
}
|
|
containsPoint(x, y) {
|
|
return super.containsPoint(x, y) || this.shape.containsPoint(x, y);
|
|
}
|
|
getNodeAtCoords(x, y) {
|
|
if (this.shape.containsPoint(x, y))
|
|
return "shape";
|
|
return super.getNodeAtCoords(x, y);
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/arrow-up/arrowUpScene.ts
|
|
var arrowUpPoints = [
|
|
[0.5, 0],
|
|
[1, 0.5],
|
|
[0.75, 0.5],
|
|
[0.75, 1],
|
|
[0.25, 1],
|
|
[0.25, 0.5],
|
|
[0, 0.5]
|
|
];
|
|
function arrowUp(params) {
|
|
_ModuleSupport38.drawMarkerUnitPolygon(params, arrowUpPoints);
|
|
}
|
|
arrowUp.anchor = { x: 0.5, y: 0 };
|
|
var ArrowUpScene = class extends ShapePointScene {
|
|
constructor() {
|
|
super();
|
|
this.type = "arrow-up" /* ArrowUp */;
|
|
this.shape = new AnnotationShape({ shape: arrowUp });
|
|
this.append([this.shape]);
|
|
}
|
|
static is(value) {
|
|
return AnnotationScene.isCheck(value, "arrow-up" /* ArrowUp */);
|
|
}
|
|
getHandleCoords(datum, point) {
|
|
const halfSize = DivariantHandle.HANDLE_SIZE / 2;
|
|
const handleCoords = super.getHandleCoords(datum, point);
|
|
handleCoords.y -= halfSize;
|
|
return handleCoords;
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/arrow-down/arrowDownScene.ts
|
|
var arrowDownPoints = arrowUpPoints.map(([x, y]) => [x, 1 - y]);
|
|
function arrowDown(params) {
|
|
_ModuleSupport39.drawMarkerUnitPolygon(params, arrowDownPoints);
|
|
}
|
|
arrowDown.anchor = { x: 0.5, y: 1 };
|
|
var ArrowDownScene = class extends ShapePointScene {
|
|
constructor() {
|
|
super();
|
|
this.type = "arrow-down" /* ArrowDown */;
|
|
this.shape = new AnnotationShape({ shape: arrowDown });
|
|
this.append([this.shape]);
|
|
}
|
|
static is(value) {
|
|
return AnnotationScene.isCheck(value, "arrow-down" /* ArrowDown */);
|
|
}
|
|
updateAnchor(datum, point, context) {
|
|
const anchor = super.updateAnchor(datum, point, context);
|
|
anchor.y -= datum.size;
|
|
return anchor;
|
|
}
|
|
getHandleCoords(datum, point) {
|
|
const halfSize = DivariantHandle.HANDLE_SIZE / 2;
|
|
const handleCoords = super.getHandleCoords(datum, point);
|
|
handleCoords.y += halfSize;
|
|
return handleCoords;
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/states/pointState.ts
|
|
import { Debug as Debug2, StateMachine as StateMachine2, StateMachineProperty as StateMachineProperty2 } from "ag-charts-core";
|
|
var PointStateMachine = class extends StateMachine2 {
|
|
constructor(ctx) {
|
|
const actionCreate = ({ point }) => {
|
|
const datum = this.createDatum();
|
|
datum.set({ x: point.x, y: point.y });
|
|
ctx.create(datum);
|
|
};
|
|
const actionFirstRender = () => {
|
|
this.node?.toggleActive(true);
|
|
ctx.showAnnotationOptions();
|
|
ctx.update();
|
|
};
|
|
super("start", {
|
|
start: {
|
|
click: {
|
|
target: "waiting-first-render",
|
|
action: actionCreate
|
|
},
|
|
drag: {
|
|
target: "waiting-first-render",
|
|
action: actionCreate
|
|
},
|
|
cancel: StateMachine2.parent,
|
|
reset: StateMachine2.parent
|
|
},
|
|
"waiting-first-render": {
|
|
render: {
|
|
target: StateMachine2.parent,
|
|
action: actionFirstRender
|
|
}
|
|
}
|
|
});
|
|
this.debug = Debug2.create(true, "annotations");
|
|
}
|
|
};
|
|
__decorateClass([
|
|
StateMachineProperty2()
|
|
], PointStateMachine.prototype, "node", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/arrow-down/arrowDownState.ts
|
|
var ArrowDownStateMachine = class extends PointStateMachine {
|
|
createDatum() {
|
|
return new ArrowDownProperties();
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/arrow-down/arrowDownConfig.ts
|
|
var arrowDownConfig = {
|
|
type: "arrow-down" /* ArrowDown */,
|
|
datum: ArrowDownProperties,
|
|
scene: ArrowDownScene,
|
|
isDatum: ArrowDownProperties.is,
|
|
translate: (node, datum, translation, context) => {
|
|
if (ArrowDownProperties.is(datum) && ArrowDownScene.is(node))
|
|
node.translate(datum, translation, context);
|
|
},
|
|
copy: (node, datum, copiedDatum, context) => {
|
|
if (ArrowDownProperties.is(datum) && ArrowDownProperties.is(copiedDatum) && ArrowDownScene.is(node)) {
|
|
return node.copy(datum, copiedDatum, context);
|
|
}
|
|
},
|
|
update: (node, datum, context) => {
|
|
if (ArrowDownProperties.is(datum) && ArrowDownScene.is(node)) {
|
|
node.update(datum, context);
|
|
}
|
|
},
|
|
createState: (ctx, { createDatum }) => new ArrowDownStateMachine({
|
|
...ctx,
|
|
create: createDatum("arrow-down" /* ArrowDown */)
|
|
}),
|
|
dragState: (ctx) => new DragStateMachine(ctx)
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/arrow-up/arrowUpProperties.ts
|
|
import { Property as Property34, isObject as isObject15 } from "ag-charts-core";
|
|
var ArrowUpProperties = class extends ShapePointProperties {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.type = "arrow-up" /* ArrowUp */;
|
|
}
|
|
static is(value) {
|
|
return isObject15(value) && value.type === "arrow-up" /* ArrowUp */;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property34
|
|
], ArrowUpProperties.prototype, "type", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/arrow-up/arrowUpState.ts
|
|
var ArrowUpStateMachine = class extends PointStateMachine {
|
|
createDatum() {
|
|
return new ArrowUpProperties();
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/arrow-up/arrowUpConfig.ts
|
|
var arrowUpConfig = {
|
|
type: "arrow-up" /* ArrowUp */,
|
|
datum: ArrowUpProperties,
|
|
scene: ArrowUpScene,
|
|
isDatum: ArrowUpProperties.is,
|
|
translate: (node, datum, translation, context) => {
|
|
if (ArrowUpProperties.is(datum) && ArrowUpScene.is(node))
|
|
node.translate(datum, translation, context);
|
|
},
|
|
copy: (node, datum, copiedDatum, context) => {
|
|
if (ArrowUpProperties.is(datum) && ArrowUpProperties.is(copiedDatum) && ArrowUpScene.is(node)) {
|
|
return node.copy(datum, copiedDatum, context);
|
|
}
|
|
},
|
|
update: (node, datum, context) => {
|
|
if (ArrowUpProperties.is(datum) && ArrowUpScene.is(node)) {
|
|
node.update(datum, context);
|
|
}
|
|
},
|
|
createState: (ctx, { createDatum }) => new ArrowUpStateMachine({
|
|
...ctx,
|
|
create: createDatum("arrow-up" /* ArrowUp */)
|
|
}),
|
|
dragState: (ctx) => new DragStateMachine(ctx)
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/callout/calloutScene.ts
|
|
import { _ModuleSupport as _ModuleSupport41 } from "ag-charts-community";
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/scenes/textualStartEndScene.ts
|
|
import { _ModuleSupport as _ModuleSupport40 } from "ag-charts-community";
|
|
import { Vec4 as Vec43 } from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/scenes/startEndScene.ts
|
|
import { Vec2 as Vec26, Vec4 as Vec42, entries as entries2 } from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/scenes/linearScene.ts
|
|
import { Vec2 as Vec25, Vec4 } from "ag-charts-core";
|
|
var LinearScene = class extends AnnotationScene {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.overflowContinuous = 0;
|
|
}
|
|
extendLine({ x1, y1, x2, y2 }, datum, context) {
|
|
const linePoints = { x1, y1, x2, y2 };
|
|
if (!datum.extendStart && !datum.extendEnd) {
|
|
return linePoints;
|
|
}
|
|
const [left, right] = boundsIntersections(linePoints, context.yAxis.bounds);
|
|
const isFlippedX = linePoints.x2 < linePoints.x1;
|
|
const isFlippedY = linePoints.y1 >= linePoints.y2;
|
|
const isVertical = linePoints.x2 === linePoints.x1;
|
|
if (datum.extendEnd) {
|
|
if (isVertical) {
|
|
linePoints.y2 = isFlippedY ? right.y : left.y;
|
|
} else {
|
|
linePoints.x2 = isFlippedX ? left.x : right.x;
|
|
linePoints.y2 = isFlippedX ? left.y : right.y;
|
|
}
|
|
}
|
|
if (datum.extendStart) {
|
|
if (isVertical) {
|
|
linePoints.y1 = isFlippedY ? left.y : right.y;
|
|
} else {
|
|
linePoints.x1 = isFlippedX ? right.x : left.x;
|
|
linePoints.y1 = isFlippedX ? right.y : left.y;
|
|
}
|
|
}
|
|
return linePoints;
|
|
}
|
|
dragStart(datum, target, context) {
|
|
this.dragState = {
|
|
offset: target,
|
|
...getDragStartState({ start: datum.start, end: datum.end }, context)
|
|
};
|
|
}
|
|
drag(datum, target, context, snapping) {
|
|
if (!datum.isWriteable())
|
|
return;
|
|
if (this.activeHandle) {
|
|
this.dragHandle(datum, target, context, snapping);
|
|
} else {
|
|
this.dragAll(datum, target, context);
|
|
}
|
|
}
|
|
dragAll(datum, target, context) {
|
|
const { dragState } = this;
|
|
if (!dragState)
|
|
return;
|
|
this.translatePoints(datum, dragState.start, dragState.end, Vec25.sub(target, dragState.offset), context);
|
|
}
|
|
translate(datum, translation, context) {
|
|
if (!datum.isWriteable())
|
|
return;
|
|
this.translatePoints(
|
|
datum,
|
|
convertPoint(datum.start, context),
|
|
convertPoint(datum.end, context),
|
|
translation,
|
|
context
|
|
);
|
|
}
|
|
copy(datum, copiedDatum, context) {
|
|
const coords = convertLine(datum, context);
|
|
if (!coords) {
|
|
return;
|
|
}
|
|
const bbox = this.computeBBoxWithoutHandles();
|
|
const translation = { x: -bbox.width / 2, y: -bbox.height / 2 };
|
|
this.translatePoints(copiedDatum, Vec4.start(coords), Vec4.end(coords), translation, context);
|
|
return copiedDatum;
|
|
}
|
|
translatePoints(datum, start, end, translation, context) {
|
|
const vectors = this.getTranslatePointsVectors(start, end);
|
|
const points = translate(vectors, translation, context, {
|
|
overflowContinuous: this.overflowContinuous
|
|
});
|
|
datum.start.x = points.start.x;
|
|
datum.end.x = points.end.x;
|
|
datum.start.y = points.start.y;
|
|
datum.end.y = points.end.y;
|
|
}
|
|
getTranslatePointsVectors(start, end) {
|
|
return { start, end };
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/scenes/startEndScene.ts
|
|
var StartEndScene = class extends LinearScene {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.start = new DivariantHandle();
|
|
this.end = new DivariantHandle();
|
|
this.anchor = {
|
|
x: 0,
|
|
y: 0,
|
|
position: "above"
|
|
};
|
|
}
|
|
update(datum, context) {
|
|
const coords = convertLine(datum, context);
|
|
if (coords == null) {
|
|
return;
|
|
}
|
|
this.updateHandles(datum, coords);
|
|
this.updateAnchor(datum, coords, context);
|
|
}
|
|
toggleHandles(show) {
|
|
if (typeof show === "boolean") {
|
|
this.start.visible = show;
|
|
this.end.visible = show;
|
|
} else {
|
|
for (const [handle3, visible] of entries2(show)) {
|
|
this[handle3].visible = visible;
|
|
}
|
|
}
|
|
this.start.toggleHovered(this.activeHandle === "start");
|
|
this.end.toggleHovered(this.activeHandle === "end");
|
|
}
|
|
toggleActive(active) {
|
|
this.toggleHandles(active);
|
|
this.start.toggleActive(active);
|
|
this.end.toggleActive(active);
|
|
}
|
|
dragHandle(datum, target, context, snapping) {
|
|
const { activeHandle, dragState } = this;
|
|
if (!activeHandle || !dragState)
|
|
return;
|
|
this[activeHandle].toggleDragging(true);
|
|
const snapHandle = activeHandle === "start" ? "end" : "start";
|
|
const snap = snapping ? { vectors: { [activeHandle]: convertPoint(datum[snapHandle], context) }, angle: datum.snapToAngle } : void 0;
|
|
const { [activeHandle]: point } = translate(
|
|
{ [activeHandle]: dragState[activeHandle] },
|
|
Vec26.sub(target, dragState.offset),
|
|
context,
|
|
{ overflowContinuous: 0, snap }
|
|
);
|
|
datum[activeHandle].x = point.x;
|
|
datum[activeHandle].y = point.y;
|
|
}
|
|
stopDragging() {
|
|
this.start.toggleDragging(false);
|
|
this.end.toggleDragging(false);
|
|
}
|
|
getAnchor() {
|
|
return this.anchor;
|
|
}
|
|
getCursor() {
|
|
return "pointer";
|
|
}
|
|
containsPoint(x, y) {
|
|
const { start, end } = this;
|
|
this.activeHandle = void 0;
|
|
if (start.containsPoint(x, y)) {
|
|
this.activeHandle = "start";
|
|
return true;
|
|
}
|
|
if (end.containsPoint(x, y)) {
|
|
this.activeHandle = "end";
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
getNodeAtCoords(x, y) {
|
|
if (this.start.containsPoint(x, y) || this.end.containsPoint(x, y))
|
|
return "handle";
|
|
}
|
|
updateHandles(datum, coords, bbox) {
|
|
this.start.update({
|
|
...this.getHandleStyles(datum, "start"),
|
|
...this.getHandleCoords(datum, coords, "start")
|
|
});
|
|
this.end.update({
|
|
...this.getHandleStyles(datum, "end"),
|
|
...this.getHandleCoords(datum, coords, "end", bbox)
|
|
});
|
|
this.start.toggleLocked(datum.locked ?? false);
|
|
this.end.toggleLocked(datum.locked ?? false);
|
|
}
|
|
updateAnchor(_datum, coords, context, _bbox) {
|
|
this.anchor = {
|
|
x: coords.x1 + context.seriesRect.x,
|
|
y: coords.y1 + context.seriesRect.y,
|
|
position: this.anchor.position
|
|
};
|
|
}
|
|
getHandleCoords(_datum, coords, handle3, _bbox) {
|
|
return handle3 === "start" ? Vec42.start(coords) : Vec42.end(coords);
|
|
}
|
|
getHandleStyles(datum, _handle) {
|
|
return {
|
|
fill: datum.handle.fill,
|
|
stroke: datum.handle.stroke,
|
|
strokeOpacity: datum.handle.strokeOpacity,
|
|
strokeWidth: datum.handle.strokeWidth
|
|
};
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/scenes/textualStartEndScene.ts
|
|
var TextualStartEndScene = class extends StartEndScene {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.label = new _ModuleSupport40.Text({ zIndex: 1 });
|
|
this.anchor = {
|
|
x: 0,
|
|
y: 0,
|
|
position: "above-left"
|
|
};
|
|
}
|
|
setTextInputBBox(bbox) {
|
|
this.textInputBBox = bbox;
|
|
this.markDirty("TextualStartEndScene");
|
|
}
|
|
update(datum, context) {
|
|
const coords = convertLine(datum, context);
|
|
if (coords == null) {
|
|
return;
|
|
}
|
|
const bbox = this.getTextBBox(datum, coords);
|
|
this.updateLabel(datum, bbox, coords);
|
|
this.updateHandles(datum, coords, bbox);
|
|
this.updateShape(datum, bbox, coords);
|
|
this.updateAnchor(datum, coords, context, bbox);
|
|
}
|
|
containsPoint(x, y) {
|
|
return super.containsPoint(x, y) || this.label.containsPoint(x, y);
|
|
}
|
|
getNodeAtCoords(x, y) {
|
|
if (this.label.containsPoint(x, y))
|
|
return "text";
|
|
return super.getNodeAtCoords(x, y);
|
|
}
|
|
getTextBBox(datum, coords) {
|
|
const { text: text2 } = datum.getText();
|
|
return getBBox(datum, text2, Vec43.end(coords), this.textInputBBox);
|
|
}
|
|
updateLabel(datum, bbox, coords) {
|
|
const { text: text2, isPlaceholder } = datum.getText();
|
|
updateTextNode(this.label, text2, isPlaceholder, datum, this.getLabelCoords(datum, bbox, coords));
|
|
}
|
|
updateShape(_datum, _textBBox, _coords) {
|
|
}
|
|
getLabelCoords(_datum, _bbox, coords) {
|
|
return Vec43.end(coords);
|
|
}
|
|
getHandleStyles(datum, handle3) {
|
|
return {
|
|
...super.getHandleStyles(datum, handle3),
|
|
stroke: datum.handle.stroke ?? datum.color
|
|
};
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/callout/calloutScene.ts
|
|
var { drawCorner, Path: Path5 } = _ModuleSupport41;
|
|
var CalloutScene = class extends TextualStartEndScene {
|
|
constructor() {
|
|
super();
|
|
this.type = "callout" /* Callout */;
|
|
this.shape = new Path5();
|
|
this.append([this.shape, this.label, this.start, this.end]);
|
|
}
|
|
static is(value) {
|
|
return AnnotationScene.isCheck(value, "callout" /* Callout */);
|
|
}
|
|
drag(datum, target, context, snapping) {
|
|
if (!datum.isWriteable())
|
|
return;
|
|
if (this.activeHandle === "end") {
|
|
this.dragHandle(datum, target, context, snapping);
|
|
} else {
|
|
this.dragAll(datum, target, context);
|
|
}
|
|
}
|
|
getLabelCoords(datum, bbox, coords) {
|
|
const padding2 = datum.getPadding();
|
|
const {
|
|
bodyBounds = {
|
|
x: 0,
|
|
y: 0,
|
|
width: 0,
|
|
height: 0
|
|
}
|
|
} = this.getDimensions(datum, bbox, coords) ?? {};
|
|
return {
|
|
x: bodyBounds.x + padding2.left,
|
|
y: bodyBounds.y - padding2.bottom
|
|
};
|
|
}
|
|
getHandleStyles(datum, handle3) {
|
|
return handle3 === "start" ? {
|
|
fill: datum.handle.fill,
|
|
stroke: datum.handle.stroke ?? datum.stroke,
|
|
strokeOpacity: datum.handle.strokeOpacity,
|
|
strokeWidth: datum.handle.strokeWidth
|
|
} : { fill: void 0, strokeWidth: 0 };
|
|
}
|
|
updateAnchor(datum, coords, context, bbox) {
|
|
const { bodyBounds } = this.getDimensions(datum, bbox, coords) ?? {};
|
|
const bounds = bodyBounds ?? bbox;
|
|
this.anchor = {
|
|
x: bounds.x + context.seriesRect.x,
|
|
y: bounds.y + context.seriesRect.y - bounds.height,
|
|
position: this.anchor.position
|
|
};
|
|
}
|
|
updateShape(datum, textBox, coords) {
|
|
const { shape } = this;
|
|
shape.fill = datum.fill;
|
|
shape.fillOpacity = datum.fillOpacity ?? 1;
|
|
shape.stroke = datum.stroke;
|
|
shape.strokeWidth = datum.strokeWidth ?? 1;
|
|
shape.strokeOpacity = datum.strokeOpacity ?? 1;
|
|
const { tailPoint, bodyBounds } = this.getDimensions(datum, textBox, coords) ?? {};
|
|
if (!tailPoint || !bodyBounds) {
|
|
return;
|
|
}
|
|
this.updatePath(tailPoint, bodyBounds);
|
|
}
|
|
updatePath(tailPoint, bodyBounds) {
|
|
const { x: tailX, y: tailY } = tailPoint;
|
|
const { x, y, width, height } = bodyBounds;
|
|
const top = y - height;
|
|
const right = x + width;
|
|
const placement = this.calculateCalloutPlacement({ x: tailX, y: tailY }, bodyBounds);
|
|
const cornerRadius = 8;
|
|
const pathParams = [
|
|
{
|
|
coordinates: {
|
|
x0: x,
|
|
x1: x + cornerRadius,
|
|
y0: top + cornerRadius,
|
|
y1: top,
|
|
cx: placement === `topLeft` ? tailX : x + cornerRadius,
|
|
cy: placement === `topLeft` ? tailY : top + cornerRadius
|
|
},
|
|
type: placement === `topLeft` ? "calloutCorner" : "corner"
|
|
},
|
|
{
|
|
coordinates: {
|
|
x0: x + cornerRadius,
|
|
x1: right - cornerRadius,
|
|
y0: top,
|
|
y1: top,
|
|
cx: tailX,
|
|
cy: tailY
|
|
},
|
|
type: placement === `top` ? "calloutSide" : "side"
|
|
},
|
|
{
|
|
coordinates: {
|
|
x0: right - cornerRadius,
|
|
x1: right,
|
|
y0: top,
|
|
y1: top + cornerRadius,
|
|
cx: placement === `topRight` ? tailX : right - cornerRadius,
|
|
cy: placement === `topRight` ? tailY : top + cornerRadius
|
|
},
|
|
type: placement === `topRight` ? "calloutCorner" : "corner"
|
|
},
|
|
{
|
|
coordinates: {
|
|
x0: right,
|
|
x1: right,
|
|
y0: top + cornerRadius,
|
|
y1: y - cornerRadius,
|
|
cx: tailX,
|
|
cy: tailY
|
|
},
|
|
type: placement === `right` ? "calloutSide" : "side"
|
|
},
|
|
{
|
|
coordinates: {
|
|
x0: right,
|
|
x1: right - cornerRadius,
|
|
y0: y - cornerRadius,
|
|
y1: y,
|
|
cx: placement === `bottomRight` ? tailX : right - cornerRadius,
|
|
cy: placement === `bottomRight` ? tailY : y - cornerRadius
|
|
},
|
|
type: placement === `bottomRight` ? "calloutCorner" : "corner"
|
|
},
|
|
{
|
|
coordinates: {
|
|
x0: right - cornerRadius,
|
|
x1: x + cornerRadius,
|
|
y0: y,
|
|
y1: y,
|
|
cx: tailX,
|
|
cy: tailY
|
|
},
|
|
type: placement === `bottom` ? "calloutSide" : "side"
|
|
},
|
|
{
|
|
coordinates: {
|
|
x0: x + cornerRadius,
|
|
x1: x,
|
|
y0: y,
|
|
y1: y - cornerRadius,
|
|
cx: placement === `bottomLeft` ? tailX : x + cornerRadius,
|
|
cy: placement === `bottomLeft` ? tailY : y - cornerRadius
|
|
},
|
|
type: placement === `bottomLeft` ? "calloutCorner" : "corner"
|
|
},
|
|
{
|
|
coordinates: {
|
|
x0: x,
|
|
x1: x,
|
|
y0: y - cornerRadius,
|
|
y1: top + cornerRadius,
|
|
cx: tailX,
|
|
cy: tailY
|
|
},
|
|
type: placement === `left` ? "calloutSide" : "side"
|
|
}
|
|
];
|
|
const { path } = this.shape;
|
|
path.clear();
|
|
path.moveTo(x, top + cornerRadius);
|
|
for (const { coordinates, type } of pathParams) {
|
|
this.drawPath(path, coordinates, cornerRadius, type);
|
|
}
|
|
path.closePath();
|
|
}
|
|
drawPath(path, { x0, y0, x1, y1, cx, cy }, cornerRadius, type) {
|
|
const sideTailRadius = 6;
|
|
switch (type) {
|
|
case "calloutCorner": {
|
|
path.lineTo(cx, cy);
|
|
path.lineTo(x1, y1);
|
|
break;
|
|
}
|
|
case "corner": {
|
|
drawCorner(
|
|
path,
|
|
{
|
|
x0,
|
|
x1,
|
|
y0,
|
|
y1,
|
|
cx,
|
|
cy
|
|
},
|
|
cornerRadius,
|
|
false
|
|
);
|
|
break;
|
|
}
|
|
case "calloutSide": {
|
|
if (x0 === x1) {
|
|
const direction = y0 > y1 ? -1 : 1;
|
|
const midY = Math.min(y0, y1) + Math.abs(y0 - y1) / 2;
|
|
path.lineTo(x0, midY - sideTailRadius * direction);
|
|
path.lineTo(cx, cy);
|
|
path.lineTo(x0, midY + sideTailRadius * direction);
|
|
path.lineTo(x1, y1);
|
|
} else {
|
|
const direction = x0 > x1 ? -1 : 1;
|
|
const midX = Math.min(x0, x1) + Math.abs(x1 - x0) / 2;
|
|
path.lineTo(midX - sideTailRadius * direction, y0);
|
|
path.lineTo(cx, cy);
|
|
path.lineTo(midX + sideTailRadius * direction, y0);
|
|
path.lineTo(x1, y1);
|
|
}
|
|
break;
|
|
}
|
|
case "side":
|
|
default: {
|
|
path.lineTo(x1, y1);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
calculateCalloutPlacement(placement, bounds) {
|
|
const right = bounds.x + bounds.width;
|
|
const top = bounds.y - bounds.height;
|
|
let xPlacement;
|
|
let yPlacement;
|
|
if (placement.x > right) {
|
|
xPlacement = "right";
|
|
} else if (placement.x < bounds.x) {
|
|
xPlacement = "left";
|
|
}
|
|
if (placement.y > bounds.y) {
|
|
yPlacement = "bottom";
|
|
} else if (placement.y < top) {
|
|
yPlacement = "top";
|
|
}
|
|
if (xPlacement && yPlacement) {
|
|
return `${yPlacement}${xPlacement[0].toUpperCase()}${xPlacement.substring(1)}`;
|
|
} else {
|
|
return yPlacement ?? xPlacement;
|
|
}
|
|
}
|
|
getDimensions(datum, textBox, coords) {
|
|
const { fontSize } = datum;
|
|
const padding2 = datum.getPadding();
|
|
const horizontalPadding = padding2.left + padding2.right;
|
|
const verticalPadding = padding2.top + padding2.bottom;
|
|
const width = textBox.width + horizontalPadding;
|
|
const height = Math.max(textBox.height + verticalPadding, fontSize + verticalPadding);
|
|
return {
|
|
tailPoint: {
|
|
x: coords.x1,
|
|
y: coords.y1
|
|
},
|
|
bodyBounds: {
|
|
x: textBox.x,
|
|
y: textBox.y,
|
|
width,
|
|
height
|
|
}
|
|
};
|
|
}
|
|
containsPoint(x, y) {
|
|
const { start, end, shape } = this;
|
|
this.activeHandle = void 0;
|
|
if (start.containsPoint(x, y)) {
|
|
this.activeHandle = "start";
|
|
return true;
|
|
}
|
|
const bodyContainsPoint = end.containsPoint(x, y) || shape.containsPoint(x, y);
|
|
if (bodyContainsPoint) {
|
|
this.activeHandle = "end";
|
|
}
|
|
return bodyContainsPoint;
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/states/textualStartEndState.ts
|
|
import "ag-charts-community";
|
|
import { Debug as Debug3, StateMachine as StateMachine3, StateMachineProperty as StateMachineProperty3 } from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/states/textualStateUtils.ts
|
|
function guardCancelAndExit({ key }) {
|
|
return key === "Escape";
|
|
}
|
|
function guardSaveAndExit({ key, shiftKey }) {
|
|
return !shiftKey && key === "Enter";
|
|
}
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/states/textualStartEndState.ts
|
|
var TextualStartEndStateMachine = class extends StateMachine3 {
|
|
constructor(ctx) {
|
|
const actionCreate = ({ point }) => {
|
|
const datum = this.createDatum();
|
|
datum.set({ start: point, end: point, visible: true });
|
|
ctx.create(datum);
|
|
};
|
|
const actionFirstRender = () => {
|
|
const { node } = this;
|
|
node?.toggleActive(true);
|
|
node?.toggleHandles({ start: true });
|
|
};
|
|
const onStartEditing = () => {
|
|
ctx.showTextInput();
|
|
if (this.datum)
|
|
this.datum.visible = false;
|
|
};
|
|
const onStopEditing = () => {
|
|
ctx.hideTextInput();
|
|
if (this.datum)
|
|
this.datum.visible = true;
|
|
ctx.deselect();
|
|
};
|
|
const actionUpdateTextInputBBox = (bbox) => {
|
|
this.node?.setTextInputBBox(bbox);
|
|
ctx.update();
|
|
};
|
|
const onEndHover = ({ point }) => {
|
|
const { datum, node } = this;
|
|
datum?.set({ end: point });
|
|
node?.toggleActive(true);
|
|
node?.toggleHandles({ end: false });
|
|
ctx.update();
|
|
};
|
|
const onEndClick = () => {
|
|
ctx.showAnnotationOptions();
|
|
this.node?.toggleHandles({ end: true });
|
|
};
|
|
const actionColor = ({
|
|
colorPickerType,
|
|
colorOpacity,
|
|
color: color7,
|
|
opacity,
|
|
isMultiColor
|
|
}) => {
|
|
const { datum } = this;
|
|
if (!datum)
|
|
return;
|
|
if (colorPickerType === "text-color") {
|
|
ctx.updateTextInputColor(color7);
|
|
}
|
|
setColor(datum, colorPickerType, colorOpacity, color7, opacity, isMultiColor);
|
|
ctx.update();
|
|
};
|
|
const actionFontSize = (fontSize) => {
|
|
const { datum, node } = this;
|
|
if (!datum || !node || !isTextType(datum))
|
|
return;
|
|
datum.fontSize = fontSize;
|
|
ctx.updateTextInputFontSize(fontSize);
|
|
ctx.update();
|
|
};
|
|
const actionCancel = () => {
|
|
ctx.delete();
|
|
};
|
|
const actionSave = ({ textInputValue, bbox }) => {
|
|
const { datum } = this;
|
|
if (bbox != null && textInputValue != null && textInputValue.length > 0) {
|
|
if (!isTextType(datum)) {
|
|
return;
|
|
}
|
|
const wrappedText = maybeWrapText(datum, textInputValue, bbox.width);
|
|
datum?.set({ text: wrappedText });
|
|
ctx.update();
|
|
ctx.recordAction(`Create ${datum?.type} annotation`);
|
|
} else {
|
|
ctx.delete();
|
|
}
|
|
};
|
|
super("start", {
|
|
start: {
|
|
click: {
|
|
target: "waiting-first-render",
|
|
action: actionCreate
|
|
},
|
|
dragStart: {
|
|
target: "waiting-first-render",
|
|
action: actionCreate
|
|
},
|
|
cancel: StateMachine3.parent,
|
|
reset: StateMachine3.parent
|
|
},
|
|
"waiting-first-render": {
|
|
render: {
|
|
target: "end",
|
|
action: actionFirstRender
|
|
}
|
|
},
|
|
end: {
|
|
hover: onEndHover,
|
|
drag: onEndHover,
|
|
click: {
|
|
target: "edit",
|
|
action: onEndClick
|
|
},
|
|
dragEnd: {
|
|
target: "edit",
|
|
action: onEndClick
|
|
},
|
|
reset: {
|
|
target: StateMachine3.parent,
|
|
action: actionCancel
|
|
},
|
|
cancel: {
|
|
target: StateMachine3.parent,
|
|
action: actionCancel
|
|
}
|
|
},
|
|
edit: {
|
|
onEnter: onStartEditing,
|
|
updateTextInputBBox: actionUpdateTextInputBBox,
|
|
color: actionColor,
|
|
fontSize: actionFontSize,
|
|
textInput: [
|
|
{
|
|
guard: guardCancelAndExit,
|
|
target: StateMachine3.parent,
|
|
action: actionCancel
|
|
},
|
|
{
|
|
guard: guardSaveAndExit,
|
|
target: StateMachine3.parent,
|
|
action: actionSave
|
|
}
|
|
],
|
|
click: {
|
|
target: StateMachine3.parent,
|
|
action: actionSave
|
|
},
|
|
dragStart: {
|
|
target: StateMachine3.parent,
|
|
action: actionSave
|
|
},
|
|
resize: {
|
|
target: StateMachine3.parent,
|
|
action: actionSave
|
|
},
|
|
onExit: onStopEditing,
|
|
cancel: {
|
|
target: StateMachine3.parent,
|
|
action: actionCancel
|
|
}
|
|
}
|
|
});
|
|
this.debug = Debug3.create(true, "annotations");
|
|
}
|
|
};
|
|
__decorateClass([
|
|
StateMachineProperty3()
|
|
], TextualStartEndStateMachine.prototype, "datum", 2);
|
|
__decorateClass([
|
|
StateMachineProperty3()
|
|
], TextualStartEndStateMachine.prototype, "node", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/callout/calloutState.ts
|
|
var CalloutStateMachine = class extends TextualStartEndStateMachine {
|
|
createDatum() {
|
|
return new CalloutProperties();
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/callout/calloutConfig.ts
|
|
var calloutConfig = {
|
|
type: "callout" /* Callout */,
|
|
datum: CalloutProperties,
|
|
scene: CalloutScene,
|
|
isDatum: CalloutProperties.is,
|
|
translate: (node, datum, transition, context) => {
|
|
if (CalloutProperties.is(datum) && CalloutScene.is(node))
|
|
return node.translate(datum, transition, context);
|
|
},
|
|
copy: (node, datum, copiedDatum, context) => {
|
|
if (CalloutProperties.is(datum) && CalloutProperties.is(copiedDatum) && CalloutScene.is(node)) {
|
|
return node.copy(datum, copiedDatum, context);
|
|
}
|
|
},
|
|
update: (node, datum, context) => {
|
|
if (CalloutProperties.is(datum) && CalloutScene.is(node)) {
|
|
node.update(datum, context);
|
|
}
|
|
},
|
|
createState: (ctx, { createDatum }) => new CalloutStateMachine({
|
|
...ctx,
|
|
create: createDatum("callout" /* Callout */)
|
|
}),
|
|
dragState: (ctx) => new DragStateMachine(ctx)
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/comment/commentScene.ts
|
|
import { _ModuleSupport as _ModuleSupport44 } from "ag-charts-community";
|
|
import { calcLineHeight as calcLineHeight2 } from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/scenes/textualPointScene.ts
|
|
import { _ModuleSupport as _ModuleSupport43 } from "ag-charts-community";
|
|
var TextualPointScene = class extends PointScene {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.label = new _ModuleSupport43.Text({ zIndex: 1 });
|
|
this.anchor = {
|
|
x: 0,
|
|
y: 0,
|
|
position: "above-left"
|
|
};
|
|
}
|
|
setTextInputBBox(bbox) {
|
|
this.textInputBBox = bbox;
|
|
this.markDirty("TextualPointScene");
|
|
}
|
|
update(datum, context) {
|
|
const coords = convertPoint(datum, context);
|
|
const bbox = this.getTextBBox(datum, coords, context);
|
|
this.updateLabel(datum, bbox);
|
|
this.updateHandle(datum, coords, bbox);
|
|
this.updateShape(datum, bbox);
|
|
this.anchor = this.updateAnchor(datum, bbox, context);
|
|
}
|
|
copy(datum, copiedDatum, context) {
|
|
const coords = convertPoint(datum, context);
|
|
const bbox = this.getTextBBox(datum, coords, context);
|
|
const padding2 = datum.getPadding();
|
|
const horizontalPadding = padding2.left + padding2.right;
|
|
const verticalPadding = padding2.top + padding2.bottom;
|
|
const xOffset = (bbox.width + horizontalPadding) / 2;
|
|
const yOffset = bbox.height + verticalPadding;
|
|
const point = invertCoords({ x: coords.x - xOffset, y: coords.y - yOffset }, context);
|
|
copiedDatum.x = point.x;
|
|
copiedDatum.y = point.y;
|
|
return copiedDatum;
|
|
}
|
|
containsPoint(x, y) {
|
|
const { label } = this;
|
|
return super.containsPoint(x, y) || label.visible && label.containsPoint(x, y);
|
|
}
|
|
getNodeAtCoords(x, y) {
|
|
if (this.label.visible && this.label.containsPoint(x, y))
|
|
return "text";
|
|
return super.getNodeAtCoords(x, y);
|
|
}
|
|
getTextBBox(datum, coords, _context) {
|
|
const { text: text2 } = datum.getText();
|
|
return getBBox(datum, text2, { x: coords.x, y: coords.y }, this.textInputBBox);
|
|
}
|
|
updateLabel(datum, bbox) {
|
|
const { text: text2, isPlaceholder } = datum.getText();
|
|
updateTextNode(
|
|
this.label,
|
|
text2,
|
|
isPlaceholder,
|
|
datum,
|
|
this.getLabelCoords(datum, bbox),
|
|
this.getTextBaseline(datum)
|
|
);
|
|
}
|
|
updateShape(_datum, _bbox) {
|
|
}
|
|
updateAnchor(_datum, bbox, context) {
|
|
return {
|
|
x: bbox.x + context.seriesRect.x,
|
|
y: bbox.y + context.seriesRect.y - bbox.height,
|
|
position: this.anchor.position
|
|
};
|
|
}
|
|
getLabelCoords(_datum, bbox) {
|
|
return bbox;
|
|
}
|
|
getTextBaseline(datum) {
|
|
return datum.position == "center" ? "middle" : datum.position;
|
|
}
|
|
getHandleCoords(_datum, _coords, bbox) {
|
|
return bbox;
|
|
}
|
|
getHandleStyles(datum) {
|
|
const styles = super.getHandleStyles(datum);
|
|
styles.stroke = datum.handle.stroke ?? datum.color;
|
|
return styles;
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/comment/commentScene.ts
|
|
var { drawCorner: drawCorner2 } = _ModuleSupport44;
|
|
var CommentScene = class extends TextualPointScene {
|
|
constructor() {
|
|
super();
|
|
this.type = "comment" /* Comment */;
|
|
this.shape = new _ModuleSupport44.Path();
|
|
this.append([this.shape, this.label, this.handle]);
|
|
}
|
|
static is(value) {
|
|
return AnnotationScene.isCheck(value, "comment" /* Comment */);
|
|
}
|
|
updateShape(datum, bbox) {
|
|
const { shape } = this;
|
|
shape.fill = datum.fill;
|
|
shape.fillOpacity = datum.fillOpacity ?? 1;
|
|
shape.stroke = datum.stroke ?? "transparent";
|
|
shape.strokeWidth = datum.strokeWidth ?? 1;
|
|
shape.strokeOpacity = datum.strokeOpacity ?? 1;
|
|
this.updatePath(datum, bbox);
|
|
}
|
|
getLabelCoords(datum, point) {
|
|
const padding2 = datum.getPadding();
|
|
return {
|
|
x: point.x + padding2.left,
|
|
y: point.y - padding2.bottom
|
|
};
|
|
}
|
|
getHandleStyles(datum) {
|
|
return {
|
|
fill: datum.handle.fill,
|
|
stroke: datum.handle.stroke ?? datum.stroke ?? datum.fill,
|
|
strokeOpacity: datum.handle.strokeOpacity,
|
|
strokeWidth: datum.handle.strokeWidth
|
|
};
|
|
}
|
|
updateAnchor(datum, bbox, context) {
|
|
const anchor = super.updateAnchor(datum, bbox, context);
|
|
const padding2 = datum.getPadding();
|
|
anchor.y -= padding2.bottom + padding2.top;
|
|
return anchor;
|
|
}
|
|
updatePath(datum, bbox) {
|
|
const padding2 = datum.getPadding();
|
|
const { x, y } = bbox;
|
|
let { width, height } = bbox;
|
|
const { fontSize } = datum;
|
|
const horizontalPadding = padding2.left + padding2.right;
|
|
const verticalPadding = padding2.top + padding2.bottom;
|
|
width = width + horizontalPadding;
|
|
height = Math.max(height + verticalPadding, fontSize + verticalPadding);
|
|
const top = y - height;
|
|
const right = x + width;
|
|
const cornerRadius = (calcLineHeight2(fontSize, ANNOTATION_TEXT_LINE_HEIGHT) + verticalPadding) / 2;
|
|
const { path } = this.shape;
|
|
path.clear();
|
|
path.moveTo(x, y);
|
|
path.lineTo(x, top + cornerRadius);
|
|
drawCorner2(
|
|
path,
|
|
{
|
|
x0: x,
|
|
x1: x + cornerRadius,
|
|
y0: top + cornerRadius,
|
|
y1: top,
|
|
cx: x + cornerRadius,
|
|
cy: top + cornerRadius
|
|
},
|
|
cornerRadius,
|
|
false
|
|
);
|
|
path.lineTo(right - cornerRadius, top);
|
|
drawCorner2(
|
|
path,
|
|
{
|
|
x0: right - cornerRadius,
|
|
x1: right,
|
|
y0: top,
|
|
y1: top + cornerRadius,
|
|
cx: right - cornerRadius,
|
|
cy: top + cornerRadius
|
|
},
|
|
cornerRadius,
|
|
false
|
|
);
|
|
path.lineTo(right, y - cornerRadius);
|
|
drawCorner2(
|
|
path,
|
|
{
|
|
x0: right,
|
|
x1: right - cornerRadius,
|
|
y0: y - cornerRadius,
|
|
y1: y,
|
|
cx: right - cornerRadius,
|
|
cy: y - cornerRadius
|
|
},
|
|
cornerRadius,
|
|
false
|
|
);
|
|
path.closePath();
|
|
}
|
|
containsPoint(x, y) {
|
|
return super.containsPoint(x, y) || this.shape.containsPoint(x, y);
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/states/textualPointState.ts
|
|
import "ag-charts-community";
|
|
import { Debug as Debug4, StateMachine as StateMachine4, StateMachineProperty as StateMachineProperty4 } from "ag-charts-core";
|
|
var TextualPointStateMachine = class extends StateMachine4 {
|
|
constructor(ctx) {
|
|
const actionCreate = ({ point }) => {
|
|
const datum = this.createDatum();
|
|
datum.set({ x: point.x, y: point.y });
|
|
ctx.create(datum);
|
|
};
|
|
const actionFirstRender = () => {
|
|
this.node?.toggleActive(true);
|
|
ctx.showAnnotationOptions();
|
|
ctx.update();
|
|
};
|
|
const onStartEditing = () => {
|
|
ctx.showTextInput();
|
|
if (this.datum) {
|
|
this.datum.visible = false;
|
|
}
|
|
};
|
|
const onStopEditing = () => {
|
|
ctx.hideTextInput();
|
|
if (this.datum)
|
|
this.datum.visible = true;
|
|
ctx.deselect();
|
|
};
|
|
const actionUpdateTextInputBBox = (bbox) => {
|
|
this.node?.setTextInputBBox(bbox);
|
|
ctx.update();
|
|
};
|
|
const actionColor = ({
|
|
colorPickerType,
|
|
colorOpacity,
|
|
color: color7,
|
|
opacity,
|
|
isMultiColor
|
|
}) => {
|
|
if (!this.datum)
|
|
return;
|
|
if (colorPickerType === "text-color") {
|
|
ctx.updateTextInputColor(color7);
|
|
}
|
|
setColor(this.datum, colorPickerType, colorOpacity, color7, opacity, isMultiColor);
|
|
ctx.update();
|
|
};
|
|
const actionFontSize = (fontSize) => {
|
|
const { datum, node } = this;
|
|
if (!datum || !node || !isTextType(datum))
|
|
return;
|
|
datum.fontSize = fontSize;
|
|
ctx.updateTextInputFontSize(fontSize);
|
|
ctx.update();
|
|
};
|
|
const actionCancel = () => {
|
|
ctx.delete();
|
|
};
|
|
const actionSave = ({ textInputValue, bbox }) => {
|
|
if (bbox != null && textInputValue != null && textInputValue.length > 0) {
|
|
const { datum } = this;
|
|
if (!isTextType(datum)) {
|
|
return;
|
|
}
|
|
const wrappedText = maybeWrapText(datum, textInputValue, bbox.width);
|
|
datum?.set({ text: wrappedText });
|
|
ctx.update();
|
|
ctx.recordAction(`Create ${datum?.type} annotation`);
|
|
} else {
|
|
ctx.delete();
|
|
}
|
|
};
|
|
super("start", {
|
|
start: {
|
|
click: {
|
|
target: "waiting-first-render",
|
|
action: actionCreate
|
|
},
|
|
dragStart: {
|
|
target: "waiting-first-render",
|
|
action: actionCreate
|
|
},
|
|
cancel: StateMachine4.parent,
|
|
reset: StateMachine4.parent
|
|
},
|
|
"waiting-first-render": {
|
|
render: {
|
|
target: "edit",
|
|
action: actionFirstRender
|
|
}
|
|
},
|
|
edit: {
|
|
onEnter: onStartEditing,
|
|
updateTextInputBBox: actionUpdateTextInputBBox,
|
|
color: actionColor,
|
|
fontSize: actionFontSize,
|
|
textInput: [
|
|
{
|
|
guard: guardCancelAndExit,
|
|
target: StateMachine4.parent,
|
|
action: actionCancel
|
|
},
|
|
{
|
|
guard: guardSaveAndExit,
|
|
target: StateMachine4.parent,
|
|
action: actionSave
|
|
}
|
|
],
|
|
click: {
|
|
target: StateMachine4.parent,
|
|
action: actionSave
|
|
},
|
|
dragStart: {
|
|
target: StateMachine4.parent,
|
|
action: actionSave
|
|
},
|
|
resize: {
|
|
target: StateMachine4.parent,
|
|
action: actionSave
|
|
},
|
|
onExit: onStopEditing,
|
|
cancel: {
|
|
target: StateMachine4.parent,
|
|
action: actionCancel
|
|
}
|
|
}
|
|
});
|
|
this.debug = Debug4.create(true, "annotations");
|
|
}
|
|
};
|
|
__decorateClass([
|
|
StateMachineProperty4()
|
|
], TextualPointStateMachine.prototype, "datum", 2);
|
|
__decorateClass([
|
|
StateMachineProperty4()
|
|
], TextualPointStateMachine.prototype, "node", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/comment/commentState.ts
|
|
var CommentStateMachine = class extends TextualPointStateMachine {
|
|
createDatum() {
|
|
return new CommentProperties();
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/comment/commentConfig.ts
|
|
var commentConfig = {
|
|
type: "comment" /* Comment */,
|
|
datum: CommentProperties,
|
|
scene: CommentScene,
|
|
isDatum: CommentProperties.is,
|
|
translate: (node, datum, translation, context) => {
|
|
if (CommentProperties.is(datum) && CommentScene.is(node))
|
|
node.translate(datum, translation, context);
|
|
},
|
|
copy: (node, datum, copiedDatum, context) => {
|
|
if (CommentProperties.is(datum) && CommentProperties.is(copiedDatum) && CommentScene.is(node)) {
|
|
return node.copy(datum, copiedDatum, context);
|
|
}
|
|
},
|
|
update: (node, datum, context) => {
|
|
if (CommentProperties.is(datum) && CommentScene.is(node)) {
|
|
node.update(datum, context);
|
|
}
|
|
},
|
|
createState: (ctx, { createDatum }) => new CommentStateMachine({
|
|
...ctx,
|
|
create: createDatum("comment" /* Comment */)
|
|
}),
|
|
dragState: (ctx) => new DragStateMachine(ctx)
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/cross-line/crossLineScene.ts
|
|
import "ag-charts-community";
|
|
import { ChartAxisDirection as ChartAxisDirection6, Vec2 as Vec29, Vec4 as Vec44 } from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/scenes/axisLabelScene.ts
|
|
import { _ModuleSupport as _ModuleSupport46 } from "ag-charts-community";
|
|
var { calculateLabelTranslation } = _ModuleSupport46;
|
|
var AxisLabelScene = class extends _ModuleSupport46.Group {
|
|
constructor() {
|
|
super({ name: "AnnotationAxisLabelGroup" });
|
|
this.label = new _ModuleSupport46.Text({ zIndex: 1 });
|
|
this.rect = new _ModuleSupport46.Rect();
|
|
const { label } = this;
|
|
label.fontSize = 12;
|
|
label.fontFamily = "Verdana, sans-serif";
|
|
label.fill = "black";
|
|
label.textBaseline = "middle";
|
|
label.textAlign = "center";
|
|
this.append([this.rect, this.label]);
|
|
}
|
|
update(opts) {
|
|
this.updateLabel(opts);
|
|
this.updateRect(opts);
|
|
this.updatePosition(opts);
|
|
}
|
|
updateLabel({ value, styles, context }) {
|
|
const { fontWeight, fontSize, fontStyle, fontFamily, textAlign, color: color7 = "white", formatter } = styles;
|
|
const text2 = formatter ? formatter({ value }) : context.formatScaleValue(value, "annotation-label");
|
|
this.label.setProperties({
|
|
fontWeight,
|
|
fontSize,
|
|
fontStyle,
|
|
fontFamily,
|
|
textAlign,
|
|
fill: color7,
|
|
text: text2
|
|
});
|
|
}
|
|
updateRect({ styles }) {
|
|
const { rect } = this;
|
|
const { cornerRadius, fill, fillOpacity, stroke: stroke3, strokeOpacity } = styles;
|
|
rect.fill = fill;
|
|
rect.fillOpacity = fillOpacity ?? 1;
|
|
rect.stroke = stroke3;
|
|
rect.strokeOpacity = strokeOpacity ?? 1;
|
|
rect.cornerRadius = cornerRadius ?? 0;
|
|
}
|
|
updatePosition({ x, y, context, styles: { padding: padding2 } }) {
|
|
const { label, rect } = this;
|
|
const labelBBox = label.getBBox()?.clone();
|
|
const horizontalPadding = padding2 ?? 8;
|
|
const verticalPadding = padding2 ?? 4;
|
|
const { xTranslation, yTranslation } = calculateLabelTranslation({
|
|
yDirection: true,
|
|
padding: context.labelPadding,
|
|
position: context.position ?? "left",
|
|
bbox: labelBBox
|
|
});
|
|
labelBBox.grow(horizontalPadding, "horizontal");
|
|
labelBBox.grow(verticalPadding, "vertical");
|
|
const translationX = x + xTranslation;
|
|
const translationY = y + yTranslation;
|
|
label.x = translationX;
|
|
label.y = translationY;
|
|
rect.y = translationY - Math.round(labelBBox.height / 2);
|
|
rect.x = translationX - Math.round(labelBBox.width / 2);
|
|
rect.height = labelBBox.height;
|
|
rect.width = labelBBox.width;
|
|
}
|
|
};
|
|
AxisLabelScene.className = "AxisLabel";
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/scenes/collidableLineScene.ts
|
|
import { _ModuleSupport as _ModuleSupport47 } from "ag-charts-community";
|
|
import { Vec2 as Vec27, jsonDiff } from "ag-charts-core";
|
|
var CollidableLine = class extends _ModuleSupport47.Line {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.growCollisionBox = 9;
|
|
this.clipMask = /* @__PURE__ */ new Map();
|
|
}
|
|
setProperties(styles) {
|
|
super.setProperties(styles);
|
|
this.updateCollisionBBox();
|
|
return this;
|
|
}
|
|
updateCollisionBBox() {
|
|
const { growCollisionBox, strokeWidth, x1, y1, x2, y2 } = this;
|
|
let height = strokeWidth + growCollisionBox;
|
|
if (height % 2 === 0)
|
|
height += 1;
|
|
const topLeft = Vec27.from(x1, y1 - Math.floor(height / 2));
|
|
const bottomRight = Vec27.from(x2, y2);
|
|
const width = Vec27.distance(topLeft, bottomRight);
|
|
this.collisionBBox = new _ModuleSupport47.BBox(topLeft.x, topLeft.y, width, height);
|
|
}
|
|
isPointInPath(pointX, pointY) {
|
|
const { collisionBBox, x1, y1, x2, y2 } = this;
|
|
if (!collisionBBox)
|
|
return false;
|
|
const v1 = Vec27.from(x1, y1);
|
|
const v2 = Vec27.from(x2, y2);
|
|
const point = Vec27.sub(Vec27.from(pointX, pointY), v1);
|
|
const end = Vec27.sub(v2, v1);
|
|
const rotated = Vec27.rotate(point, Vec27.angle(point, end), v1);
|
|
return collisionBBox.containsPoint(rotated.x, rotated.y) ?? false;
|
|
}
|
|
render(renderCtx) {
|
|
const { clipMask } = this;
|
|
const { ctx } = renderCtx;
|
|
if (clipMask.size === 0) {
|
|
super.render(renderCtx);
|
|
return;
|
|
}
|
|
ctx.save();
|
|
try {
|
|
for (const mask of this.clipMask.values()) {
|
|
const { x, y, radius } = mask;
|
|
ctx.beginPath();
|
|
ctx.rect(0, 0, ctx.canvas.width, ctx.canvas.height);
|
|
ctx.ellipse(x, y, radius, radius, 0, Math.PI * 2, 0, true);
|
|
ctx.clip();
|
|
}
|
|
super.render(renderCtx);
|
|
} finally {
|
|
ctx.restore();
|
|
}
|
|
}
|
|
setClipMask(id, mask) {
|
|
const cm = this.clipMask.get(id);
|
|
if (jsonDiff(cm, mask) != null) {
|
|
this.markDirty("CollidableLine");
|
|
}
|
|
if (mask) {
|
|
this.clipMask.set(id, mask);
|
|
} else {
|
|
this.clipMask.delete(id);
|
|
}
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/scenes/collidableTextScene.ts
|
|
import { _ModuleSupport as _ModuleSupport48 } from "ag-charts-community";
|
|
var CollidableText = class extends _ModuleSupport48.TransformableText {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.growCollisionBox = {
|
|
top: 4,
|
|
right: 4,
|
|
bottom: 4,
|
|
left: 4
|
|
};
|
|
}
|
|
isPointInPath(pointX, pointY) {
|
|
const localPoint = this.fromParentPoint(pointX, pointY);
|
|
const uBBox = this.computeBBoxWithoutTransforms();
|
|
if (!uBBox)
|
|
return false;
|
|
return uBBox.grow(this.growCollisionBox).containsPoint(localPoint.x, localPoint.y);
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/utils/lineWithText.ts
|
|
import { Vec2 as Vec28 } from "ag-charts-core";
|
|
function updateLineText(id, line, coords, textProperties, textNode, text2, lineWidth) {
|
|
if (!text2 || !textNode || !textProperties) {
|
|
line.setClipMask(id);
|
|
return;
|
|
}
|
|
const { alignment, position } = textProperties;
|
|
const numbers = getNumbers(coords, textProperties.fontSize, lineWidth);
|
|
const { point, textBaseline } = positionAndAlignment(numbers, position, alignment);
|
|
setProperties(textNode, text2, textProperties, point, numbers.angle, textBaseline);
|
|
const { x, y, width, height } = textNode.getBBox();
|
|
const diameter = Vec28.length(Vec28.from(width, height));
|
|
const clipMask = {
|
|
x: x + width / 2,
|
|
y: y + height / 2,
|
|
radius: diameter / 2 + Vec28.length(numbers.offset)
|
|
};
|
|
if (position === "center") {
|
|
line.setClipMask(id, clipMask);
|
|
} else {
|
|
line.setClipMask(id);
|
|
}
|
|
return { clipMask, numbers };
|
|
}
|
|
function updateChannelText(offsetInsideTextLabel, top, bottom, textProperties, lineWidth, textNode, text2) {
|
|
if (!text2 || !textNode)
|
|
return;
|
|
const { alignment, position } = textProperties;
|
|
const [actualTop, actualBottom] = top.y1 <= bottom.y1 ? [top, bottom] : [bottom, top];
|
|
let relativeLine = actualTop;
|
|
if (position === "bottom") {
|
|
relativeLine = actualBottom;
|
|
} else if (position === "inside") {
|
|
relativeLine = {
|
|
x1: (actualTop.x1 + actualBottom.x1) / 2,
|
|
y1: (actualTop.y1 + actualBottom.y1) / 2,
|
|
x2: (actualTop.x2 + actualBottom.x2) / 2,
|
|
y2: (actualTop.y2 + actualBottom.y2) / 2
|
|
};
|
|
}
|
|
const numbers = getNumbers(relativeLine, textProperties.fontSize, lineWidth);
|
|
const { point, textBaseline } = positionAndAlignment(
|
|
numbers,
|
|
position === "inside" ? "center" : position,
|
|
alignment,
|
|
offsetInsideTextLabel
|
|
);
|
|
setProperties(textNode, text2, textProperties, point, numbers.angle, textBaseline);
|
|
}
|
|
function getNumbers(coords, fontSize, strokeWidth) {
|
|
let [left, right] = Vec28.from(coords);
|
|
if (left.x > right.x)
|
|
[left, right] = [right, left];
|
|
const normal = Vec28.normalized(Vec28.sub(right, left));
|
|
const angle = Vec28.angle(normal);
|
|
const inset = Vec28.multiply(normal, DivariantHandle.HANDLE_SIZE / 2 + (fontSize ?? 14) / 2);
|
|
const offset = Vec28.multiply(normal, (strokeWidth ?? 2) / 2 + (fontSize ?? 14) / 3);
|
|
return { left, right, normal, angle, inset, offset };
|
|
}
|
|
function positionAndAlignment({ left, right, normal, angle, inset, offset }, position, alignment, offsetInsideTextLabel) {
|
|
let point;
|
|
if (alignment === "right") {
|
|
point = Vec28.sub(right, inset);
|
|
} else if (alignment === "center") {
|
|
point = Vec28.add(left, Vec28.multiply(normal, Vec28.distance(left, right) / 2));
|
|
} else {
|
|
point = Vec28.add(left, inset);
|
|
}
|
|
let textBaseline = "bottom";
|
|
if (position === "bottom") {
|
|
point = Vec28.rotate(offset, angle + Math.PI / 2, point);
|
|
textBaseline = "top";
|
|
} else if (position === "center" && !offsetInsideTextLabel) {
|
|
textBaseline = "middle";
|
|
} else {
|
|
point = Vec28.rotate(offset, angle - Math.PI / 2, point);
|
|
}
|
|
return { point, textBaseline };
|
|
}
|
|
function setProperties(scene, text2, textProperties, point, angle, textBaseline) {
|
|
scene.setProperties({
|
|
text: text2,
|
|
x: point.x,
|
|
y: point.y,
|
|
rotation: angle,
|
|
rotationCenterX: point.x,
|
|
rotationCenterY: point.y,
|
|
fill: textProperties.color,
|
|
fontFamily: textProperties.fontFamily,
|
|
fontSize: textProperties.fontSize,
|
|
fontStyle: textProperties.fontStyle,
|
|
fontWeight: textProperties.fontWeight,
|
|
textAlign: textProperties.alignment,
|
|
textBaseline
|
|
});
|
|
}
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/cross-line/crossLineScene.ts
|
|
var CrossLineScene = class extends AnnotationScene {
|
|
constructor() {
|
|
super();
|
|
this.type = "cross-line";
|
|
this.line = new CollidableLine();
|
|
this.middle = new UnivariantHandle();
|
|
this.isHorizontal = false;
|
|
this.append([this.line, this.middle]);
|
|
}
|
|
static is(value) {
|
|
return AnnotationScene.isCheck(value, "cross-line");
|
|
}
|
|
update(datum, context) {
|
|
const { seriesRect } = context;
|
|
this.seriesRect = seriesRect;
|
|
this.isHorizontal = HorizontalLineProperties.is(datum);
|
|
const axisContext = this.isHorizontal ? context.yAxis : context.xAxis;
|
|
const coords = this.convertCrossLine(datum, axisContext);
|
|
if (coords == null) {
|
|
this.visible = false;
|
|
return;
|
|
}
|
|
this.visible = datum.visible ?? true;
|
|
if (!this.visible)
|
|
return;
|
|
this.updateLine(datum, coords);
|
|
this.updateHandle(datum, coords);
|
|
this.updateText(datum, coords);
|
|
this.updateAxisLabel(datum, axisContext, coords);
|
|
}
|
|
updateLine(datum, coords) {
|
|
const { line } = this;
|
|
const { lineDashOffset, stroke: stroke3, strokeWidth, strokeOpacity } = datum;
|
|
const { x1, y1, x2, y2 } = coords;
|
|
line.setProperties({
|
|
x1,
|
|
y1,
|
|
x2,
|
|
y2,
|
|
lineCap: datum.getLineCap(),
|
|
lineDash: datum.getLineDash(),
|
|
lineDashOffset,
|
|
stroke: stroke3,
|
|
strokeWidth,
|
|
strokeOpacity,
|
|
fillOpacity: 0
|
|
});
|
|
}
|
|
updateHandle(datum, coords) {
|
|
const { middle } = this;
|
|
const { locked, stroke: stroke3, strokeWidth, strokeOpacity } = datum;
|
|
const handleStyles = {
|
|
fill: datum.handle.fill,
|
|
stroke: datum.handle.stroke ?? stroke3,
|
|
strokeOpacity: datum.handle.strokeOpacity ?? strokeOpacity,
|
|
strokeWidth: datum.handle.strokeWidth ?? strokeWidth
|
|
};
|
|
const handlePosition = Vec29.sub(
|
|
Vec44.center(coords),
|
|
Vec29.from(middle.handle.width / 2, middle.handle.height / 2)
|
|
);
|
|
middle.gradient = this.isHorizontal ? "horizontal" : "vertical";
|
|
middle.update({ ...handleStyles, ...handlePosition });
|
|
middle.toggleLocked(locked ?? false);
|
|
}
|
|
updateText(datum, coords) {
|
|
this.text = this.updateNode(CollidableText, this.text, !!datum.text.label);
|
|
updateLineText(this.line.id, this.line, coords, datum.text, this.text, datum.text.label, datum.strokeWidth);
|
|
}
|
|
createAxisLabel(context) {
|
|
const axisLabel3 = new AxisLabelScene();
|
|
context.attachLabel(axisLabel3);
|
|
return axisLabel3;
|
|
}
|
|
updateAxisLabel(datum, axisContext, coords) {
|
|
this.axisLabel ?? (this.axisLabel = this.createAxisLabel(axisContext));
|
|
const { axisLabel: axisLabel3, seriesRect } = this;
|
|
const { direction, position } = axisContext;
|
|
if (datum.axisLabel.enabled) {
|
|
axisLabel3.visible = this.visible;
|
|
const labelCorner = position === "left" || position === "top" ? Vec44.start(coords) : Vec44.end(coords);
|
|
const labelPosition = direction === ChartAxisDirection6.X ? labelCorner.x : labelCorner.y;
|
|
if (!axisContext.inRange(labelPosition)) {
|
|
axisLabel3.visible = false;
|
|
return;
|
|
}
|
|
const value = getGroupingValue(datum.value);
|
|
axisLabel3.update({
|
|
...Vec29.add(labelCorner, Vec29.required(seriesRect)),
|
|
value,
|
|
styles: datum.axisLabel,
|
|
context: axisContext
|
|
});
|
|
} else {
|
|
axisLabel3.visible = false;
|
|
}
|
|
}
|
|
setAxisLabelOpacity(opacity) {
|
|
if (!this.axisLabel)
|
|
return;
|
|
this.axisLabel.opacity = opacity;
|
|
}
|
|
setAxisLabelVisible(visible) {
|
|
if (!this.axisLabel)
|
|
return;
|
|
this.axisLabel.visible = visible;
|
|
}
|
|
toggleHandles(show) {
|
|
this.middle.visible = show;
|
|
this.middle.toggleHovered(this.activeHandle === "middle");
|
|
}
|
|
destroy() {
|
|
super.destroy();
|
|
this.axisLabel?.destroy();
|
|
}
|
|
toggleActive(active) {
|
|
this.toggleHandles(active);
|
|
this.middle.toggleActive(active);
|
|
}
|
|
dragStart(datum, target, context) {
|
|
const middle = HorizontalLineProperties.is(datum) ? { x: target.x, y: convert(datum.value, context.yAxis) } : { x: convert(datum.value, context.xAxis), y: target.y };
|
|
this.dragState = {
|
|
offset: target,
|
|
middle
|
|
};
|
|
}
|
|
drag(datum, target, context) {
|
|
const { activeHandle, dragState } = this;
|
|
if (!datum.isWriteable() || !dragState)
|
|
return;
|
|
if (activeHandle) {
|
|
this[activeHandle].toggleDragging(true);
|
|
}
|
|
this.translatePoint(datum, dragState.middle, Vec29.sub(target, dragState.offset), context);
|
|
}
|
|
translate(datum, translation, context) {
|
|
if (!datum.isWriteable())
|
|
return;
|
|
const vector = HorizontalLineProperties.is(datum) ? Vec29.from(0, convert(datum.value, context.yAxis)) : Vec29.from(convert(datum.value, context.xAxis), 0);
|
|
this.translatePoint(datum, vector, translation, context);
|
|
}
|
|
translatePoint(datum, value, translation, context) {
|
|
const isHorizontal2 = HorizontalLineProperties.is(datum);
|
|
if (isHorizontal2) {
|
|
translation.x = 0;
|
|
} else {
|
|
translation.y = 0;
|
|
}
|
|
const { point } = translate({ point: value }, translation, context);
|
|
datum.value = isHorizontal2 ? point.y : point.x;
|
|
}
|
|
stopDragging() {
|
|
this.middle.toggleDragging(false);
|
|
}
|
|
copy(datum, copiedDatum, context) {
|
|
const isHorizontal2 = HorizontalLineProperties.is(datum);
|
|
const axisContext = this.isHorizontal ? context.yAxis : context.xAxis;
|
|
const coords = this.convertCrossLine(datum, axisContext);
|
|
if (!coords) {
|
|
return;
|
|
}
|
|
const yOffset = isHorizontal2 ? -30 : 0;
|
|
const xOffset = isHorizontal2 ? 0 : -30;
|
|
const point = invertCoords({ x: coords.x1 + xOffset, y: coords.y1 + yOffset }, context);
|
|
copiedDatum.set({ value: isHorizontal2 ? point.y : point.x });
|
|
return copiedDatum;
|
|
}
|
|
getCursor() {
|
|
if (this.activeHandle == null)
|
|
return "pointer";
|
|
return this[this.activeHandle].getCursor();
|
|
}
|
|
containsPoint(x, y) {
|
|
const { middle, line, text: text2 } = this;
|
|
this.activeHandle = void 0;
|
|
if (middle.containsPoint(x, y)) {
|
|
this.activeHandle = "middle";
|
|
return true;
|
|
}
|
|
return line.isPointInPath(x, y) || Boolean(text2?.containsPoint(x, y));
|
|
}
|
|
getNodeAtCoords(x, y) {
|
|
if (this.text?.containsPoint(x, y))
|
|
return "text";
|
|
if (this.line.isPointInPath(x, y))
|
|
return "line";
|
|
if (this.middle.containsPoint(x, y))
|
|
return "handle";
|
|
}
|
|
getAnchor() {
|
|
const bbox = this.computeBBoxWithoutHandles();
|
|
if (this.isHorizontal) {
|
|
return { x: bbox.x + bbox.width / 2, y: bbox.y };
|
|
}
|
|
return { x: bbox.x + bbox.width, y: bbox.y + bbox.height / 2, position: "right" };
|
|
}
|
|
convertCrossLine(datum, context) {
|
|
if (datum.value == null)
|
|
return;
|
|
let x1 = 0;
|
|
let y1 = 0;
|
|
let x2, y2;
|
|
const { bounds } = context;
|
|
const scaledValue = convert(datum.value, context);
|
|
if (HorizontalLineProperties.is(datum)) {
|
|
x2 = bounds.width;
|
|
y1 = scaledValue;
|
|
y2 = scaledValue;
|
|
} else {
|
|
x1 = scaledValue;
|
|
x2 = scaledValue;
|
|
y2 = bounds.height;
|
|
}
|
|
return { x1, y1, x2, y2 };
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/cross-line/crossLineState.ts
|
|
import "ag-charts-community";
|
|
import { Debug as Debug5, StateMachine as StateMachine5, StateMachineProperty as StateMachineProperty5 } from "ag-charts-core";
|
|
var CrossLineStateMachine = class extends StateMachine5 {
|
|
constructor(direction, ctx) {
|
|
const onClick = ({ point }) => {
|
|
const isHorizontal2 = direction === "horizontal";
|
|
const datum = isHorizontal2 ? new HorizontalLineProperties() : new VerticalLineProperties();
|
|
datum.set({ value: isHorizontal2 ? point.y : point.x });
|
|
ctx.create(datum);
|
|
ctx.recordAction(
|
|
`Create ${isHorizontal2 ? "horizontal-line" /* HorizontalLine */ : "vertical-line" /* VerticalLine */} annotation`
|
|
);
|
|
};
|
|
const actionFirstRender = () => {
|
|
this.node?.toggleActive(true);
|
|
ctx.showAnnotationOptions();
|
|
ctx.update();
|
|
};
|
|
super("start", {
|
|
start: {
|
|
click: {
|
|
target: "waiting-first-render",
|
|
action: onClick
|
|
},
|
|
drag: {
|
|
target: "waiting-first-render",
|
|
action: onClick
|
|
},
|
|
reset: StateMachine5.parent,
|
|
cancel: StateMachine5.parent
|
|
},
|
|
"waiting-first-render": {
|
|
render: {
|
|
target: StateMachine5.parent,
|
|
action: actionFirstRender
|
|
}
|
|
}
|
|
});
|
|
this.debug = Debug5.create(true, "annotations");
|
|
}
|
|
};
|
|
__decorateClass([
|
|
StateMachineProperty5()
|
|
], CrossLineStateMachine.prototype, "node", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/cross-line/crossLineConfig.ts
|
|
var horizontalLineConfig = {
|
|
type: "horizontal-line" /* HorizontalLine */,
|
|
datum: HorizontalLineProperties,
|
|
scene: CrossLineScene,
|
|
isDatum: HorizontalLineProperties.is,
|
|
translate: (node, datum, translation, context) => {
|
|
if (HorizontalLineProperties.is(datum) && CrossLineScene.is(node))
|
|
node.translate(datum, translation, context);
|
|
},
|
|
copy: (node, datum, copiedDatum, context) => {
|
|
if (HorizontalLineProperties.is(datum) && HorizontalLineProperties.is(copiedDatum) && CrossLineScene.is(node)) {
|
|
return node.copy(datum, copiedDatum, context);
|
|
}
|
|
},
|
|
update: (node, datum, context) => {
|
|
if (HorizontalLineProperties.is(datum) && CrossLineScene.is(node)) {
|
|
node.update(datum, context);
|
|
}
|
|
},
|
|
createState: (ctx, { createDatum }) => new CrossLineStateMachine("horizontal", {
|
|
...ctx,
|
|
create: createDatum("horizontal-line" /* HorizontalLine */)
|
|
}),
|
|
dragState: (ctx) => new DragStateMachine(ctx)
|
|
};
|
|
var verticalLineConfig = {
|
|
type: "vertical-line" /* VerticalLine */,
|
|
datum: VerticalLineProperties,
|
|
scene: CrossLineScene,
|
|
isDatum: VerticalLineProperties.is,
|
|
translate: (node, datum, translation, context) => {
|
|
if (VerticalLineProperties.is(datum) && CrossLineScene.is(node))
|
|
node.translate(datum, translation, context);
|
|
},
|
|
copy: (node, datum, copiedDatum, context) => {
|
|
if (VerticalLineProperties.is(datum) && VerticalLineProperties.is(copiedDatum) && CrossLineScene.is(node)) {
|
|
return node.copy(datum, copiedDatum, context);
|
|
}
|
|
},
|
|
update: (node, datum, context) => {
|
|
if (VerticalLineProperties.is(datum) && CrossLineScene.is(node)) {
|
|
node.update(datum, context);
|
|
}
|
|
},
|
|
createState: (ctx, { createDatum }) => new CrossLineStateMachine("vertical", {
|
|
...ctx,
|
|
create: createDatum("vertical-line" /* VerticalLine */)
|
|
}),
|
|
dragState: (ctx) => new DragStateMachine(ctx)
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/disjoint-channel/disjointChannelScene.ts
|
|
import { Vec2 as Vec210, Vec4 as Vec46 } from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/scenes/channelScene.ts
|
|
import { _ModuleSupport as _ModuleSupport50 } from "ag-charts-community";
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/scenes/withBackgroundScene.ts
|
|
import { Vec4 as Vec45 } from "ag-charts-core";
|
|
var WithBackgroundScene = class {
|
|
static updateBackground(datum, top, bottom, context) {
|
|
const { background } = this;
|
|
const { seriesRect } = context;
|
|
background.path.clear(true);
|
|
const bounds = Vec45.from(0, 0, seriesRect.width, seriesRect.height);
|
|
const points = this.getBackgroundPoints(datum, top, bottom, bounds);
|
|
for (let i = 0; i < points.length; i++) {
|
|
const point = points[i];
|
|
if (i === 0) {
|
|
background.path.moveTo(point.x, point.y);
|
|
} else {
|
|
background.path.lineTo(point.x, point.y);
|
|
}
|
|
}
|
|
background.path.closePath();
|
|
background.checkPathDirty();
|
|
const backgroundStyles = this.getBackgroundStyles?.(datum) ?? datum.background;
|
|
background.fill = backgroundStyles.fill;
|
|
background.fillOpacity = backgroundStyles.fillOpacity ?? 1;
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/scenes/channelScene.ts
|
|
var ChannelScene = class extends LinearScene {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.handles = {};
|
|
this.overflowContinuous = 2;
|
|
this.topLine = new CollidableLine();
|
|
this.bottomLine = new CollidableLine();
|
|
this.background = new _ModuleSupport50.Path({ zIndex: -1 });
|
|
this.anchor = { x: 0, y: 0 };
|
|
this.updateBackground = WithBackgroundScene.updateBackground.bind(this);
|
|
}
|
|
update(datum, context) {
|
|
const { locked, visible } = datum;
|
|
const top = convertLine(datum, context);
|
|
const bottom = convertLine(datum.bottom, context);
|
|
if (top == null || bottom == null) {
|
|
this.visible = false;
|
|
return;
|
|
} else {
|
|
this.visible = visible ?? true;
|
|
}
|
|
const topLine = this.extendLine(top, datum, context);
|
|
const bottomLine = this.extendLine(bottom, datum, context);
|
|
this.updateLines(datum, topLine, bottomLine, context, top, bottom);
|
|
this.updateHandles(datum, top, bottom);
|
|
this.updateText(datum, top, bottom);
|
|
this.updateBackground(datum, topLine, bottomLine, context);
|
|
this.updateAnchor(top, bottom);
|
|
for (const handle3 of Object.values(this.handles)) {
|
|
handle3.toggleLocked(locked ?? false);
|
|
}
|
|
}
|
|
toggleHandles(show) {
|
|
const { handles } = this;
|
|
if (typeof show === "boolean") {
|
|
for (const [handle3, node] of Object.entries(handles)) {
|
|
node.visible = show;
|
|
node.toggleHovered(this.activeHandle === handle3);
|
|
}
|
|
return;
|
|
}
|
|
for (const [handle3, visible] of Object.entries(show)) {
|
|
const node = handles[handle3];
|
|
node.visible = visible ?? true;
|
|
node.toggleHovered(this.activeHandle === handle3);
|
|
}
|
|
}
|
|
toggleActive(active) {
|
|
this.toggleHandles(active);
|
|
for (const node of Object.values(this.handles)) {
|
|
node.toggleActive(active);
|
|
}
|
|
}
|
|
stopDragging() {
|
|
const { activeHandle, handles } = this;
|
|
if (activeHandle == null)
|
|
return;
|
|
handles[activeHandle].toggleDragging(false);
|
|
}
|
|
getAnchor() {
|
|
return this.anchor;
|
|
}
|
|
getCursor() {
|
|
if (this.activeHandle == null)
|
|
return "pointer";
|
|
return this.handles[this.activeHandle].getCursor();
|
|
}
|
|
containsPoint(x, y) {
|
|
const { handles, topLine, bottomLine, text: text2 } = this;
|
|
this.activeHandle = void 0;
|
|
for (const [handle3, child] of Object.entries(handles)) {
|
|
if (child.containsPoint(x, y)) {
|
|
this.activeHandle = handle3;
|
|
return true;
|
|
}
|
|
}
|
|
return topLine.containsPoint(x, y) || bottomLine.containsPoint(x, y) || Boolean(text2?.containsPoint(x, y));
|
|
}
|
|
getNodeAtCoords(x, y) {
|
|
if (this.text?.containsPoint(x, y))
|
|
return "text";
|
|
if (this.topLine.containsPoint(x, y) || this.bottomLine.containsPoint(x, y))
|
|
return "line";
|
|
for (const [, child] of Object.entries(this.handles)) {
|
|
if (child.containsPoint(x, y))
|
|
return "handle";
|
|
}
|
|
}
|
|
updateAnchor(top, bottom) {
|
|
const { x, y } = _ModuleSupport50.Transformable.toCanvasPoint(
|
|
this.topLine,
|
|
(top.x1 + top.x2) / 2,
|
|
Math.min(top.y1, top.y2, bottom.y1, bottom.y2)
|
|
);
|
|
this.anchor.x = x;
|
|
this.anchor.y = y;
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/disjoint-channel/disjointChannelScene.ts
|
|
var DisjointChannelScene = class extends ChannelScene {
|
|
constructor() {
|
|
super();
|
|
this.type = "disjoint-channel";
|
|
this.handles = {
|
|
topLeft: new DivariantHandle(),
|
|
topRight: new DivariantHandle(),
|
|
bottomLeft: new DivariantHandle(),
|
|
bottomRight: new UnivariantHandle()
|
|
};
|
|
this.append([this.background, this.topLine, this.bottomLine, ...Object.values(this.handles)]);
|
|
}
|
|
static is(value) {
|
|
return AnnotationScene.isCheck(value, "disjoint-channel");
|
|
}
|
|
dragHandle(datum, target, context, snapping) {
|
|
const { activeHandle, handles } = this;
|
|
if (activeHandle == null)
|
|
return;
|
|
const { offset } = handles[activeHandle].drag(target);
|
|
handles[activeHandle].toggleDragging(true);
|
|
if (activeHandle === "bottomRight") {
|
|
offset.x = 0;
|
|
}
|
|
let translateVectors = [];
|
|
let invertYVectors = [];
|
|
let allowSnapping = snapping;
|
|
switch (activeHandle) {
|
|
case "topLeft":
|
|
translateVectors = ["topLeft"];
|
|
invertYVectors = ["bottomLeft"];
|
|
break;
|
|
case "bottomLeft":
|
|
translateVectors = ["bottomLeft"];
|
|
invertYVectors = ["topLeft"];
|
|
break;
|
|
case "topRight":
|
|
translateVectors = ["topRight"];
|
|
invertYVectors = ["bottomRight"];
|
|
break;
|
|
case "bottomRight":
|
|
translateVectors = ["bottomLeft", "bottomRight"];
|
|
allowSnapping = false;
|
|
break;
|
|
}
|
|
const top = convertLine(datum, context);
|
|
const bottom = convertLine(datum.bottom, context);
|
|
if (!top || !bottom)
|
|
return;
|
|
const vectors = {
|
|
topLeft: Vec46.start(top),
|
|
topRight: Vec46.end(top),
|
|
bottomLeft: Vec46.start(bottom),
|
|
bottomRight: Vec46.end(bottom)
|
|
};
|
|
const snap = {
|
|
vectors: {
|
|
topLeft: vectors.topRight,
|
|
bottomLeft: vectors.bottomRight,
|
|
topRight: vectors.topLeft,
|
|
bottomRight: vectors.bottomLeft
|
|
},
|
|
angle: datum.snapToAngle
|
|
};
|
|
const points = translate(vectors, offset, context, {
|
|
overflowContinuous: this.overflowContinuous,
|
|
translateVectors,
|
|
invertYVectors,
|
|
snap: allowSnapping ? snap : void 0
|
|
});
|
|
datum.start.x = points.topLeft.x;
|
|
datum.start.y = points.topLeft.y;
|
|
datum.end.x = points.topRight.x;
|
|
datum.end.y = points.topRight.y;
|
|
datum.startHeight = points.topLeft.y - points.bottomLeft.y;
|
|
datum.endHeight = points.topRight.y - points.bottomRight.y;
|
|
}
|
|
getTranslatePointsVectors(start, end) {
|
|
const { bottomLeft, bottomRight, topLeft, topRight } = this.handles;
|
|
const startHeight = bottomLeft.getBBox().y - topLeft.getBBox().y;
|
|
const endHeight = bottomRight.getBBox().y - topRight.getBBox().y;
|
|
const bottomStart = Vec210.add(start, Vec210.from(0, startHeight));
|
|
const bottomEnd = Vec210.add(end, Vec210.from(0, endHeight));
|
|
return { start, end, bottomStart, bottomEnd };
|
|
}
|
|
updateLines(datum, top, bottom) {
|
|
const { topLine, bottomLine } = this;
|
|
const { lineDashOffset, stroke: stroke3, strokeOpacity, strokeWidth } = datum;
|
|
const lineStyles = {
|
|
lineCap: datum.getLineCap(),
|
|
lineDash: datum.getLineDash(),
|
|
lineDashOffset,
|
|
stroke: stroke3,
|
|
strokeOpacity,
|
|
strokeWidth
|
|
};
|
|
topLine.setProperties({ ...top, ...lineStyles });
|
|
bottomLine.setProperties({ ...bottom, ...lineStyles });
|
|
}
|
|
updateHandles(datum, top, bottom) {
|
|
const {
|
|
handles: { topLeft, topRight, bottomLeft, bottomRight }
|
|
} = this;
|
|
const handleStyles = {
|
|
fill: datum.handle.fill,
|
|
stroke: datum.handle.stroke ?? datum.stroke,
|
|
strokeOpacity: datum.handle.strokeOpacity ?? datum.strokeOpacity,
|
|
strokeWidth: datum.handle.strokeWidth ?? datum.strokeWidth
|
|
};
|
|
topLeft.update({ ...handleStyles, ...Vec46.start(top) });
|
|
topRight.update({ ...handleStyles, ...Vec46.end(top) });
|
|
bottomLeft.update({ ...handleStyles, ...Vec46.start(bottom) });
|
|
bottomRight.update({
|
|
...handleStyles,
|
|
...Vec210.sub(Vec46.end(bottom), Vec210.from(bottomRight.handle.width / 2, bottomRight.handle.height / 2))
|
|
});
|
|
}
|
|
updateText(datum, top, bottom) {
|
|
this.text = this.updateNode(CollidableText, this.text, !!datum.text.label);
|
|
updateChannelText(false, top, bottom, datum.text, datum.strokeWidth, this.text, datum.text.label);
|
|
}
|
|
getBackgroundPoints(datum, top, bottom, bounds) {
|
|
const isFlippedX = top.x1 > top.x2;
|
|
const isFlippedY = top.y1 > top.y2;
|
|
const topY = isFlippedY ? bounds.y2 : bounds.y1;
|
|
const bottomY = isFlippedY ? bounds.y1 : bounds.y2;
|
|
const points = Vec210.from(top);
|
|
if (datum.extendEnd && top.y2 === bottomY) {
|
|
points.push(Vec210.from(isFlippedX ? bounds.x1 : bounds.x2, isFlippedY ? bounds.y1 : bounds.y2));
|
|
}
|
|
if (datum.extendEnd && bottom.y2 === topY) {
|
|
points.push(Vec210.from(isFlippedX ? bounds.x1 : bounds.x2, isFlippedY ? bounds.y2 : bounds.y1));
|
|
}
|
|
points.push(...Vec210.from(bottom).reverse());
|
|
if (datum.extendStart && bottom.y1 === bottomY) {
|
|
points.push(Vec210.from(isFlippedX ? bounds.x2 : bounds.x1, isFlippedY ? bounds.y1 : bounds.y2));
|
|
}
|
|
if (datum.extendStart && top.y1 === topY) {
|
|
points.push(Vec210.from(isFlippedX ? bounds.x2 : bounds.x1, isFlippedY ? bounds.y2 : bounds.y1));
|
|
}
|
|
return points;
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/disjoint-channel/disjointChannelState.ts
|
|
import { Debug as Debug6, StateMachine as StateMachine6, StateMachineProperty as StateMachineProperty6, isNumber as isNumber2 } from "ag-charts-core";
|
|
var DisjointChannelStateMachine = class extends StateMachine6 {
|
|
constructor(ctx) {
|
|
const actionCreate = ({ point }) => {
|
|
const datum = new DisjointChannelProperties();
|
|
datum.set({ start: point, end: point, startHeight: 0, endHeight: 0 });
|
|
ctx.create(datum);
|
|
};
|
|
const actionFirstRender = () => {
|
|
const { node } = this;
|
|
node?.toggleActive(true);
|
|
node?.toggleHandles({ topLeft: true, topRight: false, bottomLeft: false, bottomRight: false });
|
|
};
|
|
const actionEndUpdate = ({ offset, context }) => {
|
|
const { datum, snapping } = this;
|
|
if (!datum)
|
|
return;
|
|
datum.set({ end: snapPoint(offset, context, snapping, datum.start, datum.snapToAngle) });
|
|
ctx.update();
|
|
};
|
|
const actionEndFinish = () => {
|
|
this.node?.toggleHandles({ topRight: true });
|
|
ctx.update();
|
|
};
|
|
const actionHeightUpdate = ({ point }) => {
|
|
const { datum, node } = this;
|
|
const endY = getGroupingValue(datum?.end.y);
|
|
const startY = getGroupingValue(datum?.start.y);
|
|
const { y: pointY } = point;
|
|
if (datum == null || !isNumber2(startY) || !isNumber2(endY) || !isNumber2(pointY))
|
|
return;
|
|
const endHeight = endY - (pointY ?? 0);
|
|
const startHeight = (startY - endY) * 2 + endHeight;
|
|
const bottomStart = { x: datum?.start.x, y: startY - startHeight };
|
|
const bottomEnd = { x: datum?.end.x, y: point.y };
|
|
node?.toggleHandles({ bottomLeft: true, bottomRight: true });
|
|
if (!ctx.validatePoint(bottomStart, { overflowContinuous: true }) || !ctx.validatePoint(bottomEnd, { overflowContinuous: true })) {
|
|
return;
|
|
}
|
|
datum.set({ startHeight, endHeight });
|
|
ctx.update();
|
|
};
|
|
const actionHeightFinish = ({ point }) => {
|
|
const { datum, node } = this;
|
|
const endY = getGroupingValue(datum?.end.y);
|
|
const startY = getGroupingValue(datum?.start.y);
|
|
const { y: pointY } = point;
|
|
if (datum == null || !isNumber2(startY) || !isNumber2(endY) || !isNumber2(pointY))
|
|
return;
|
|
const endHeight = endY - (pointY ?? 0);
|
|
const startHeight = (startY - endY) * 2 + endHeight;
|
|
const bottomStart = { x: datum.start.x, y: startY - endHeight };
|
|
const bottomEnd = { x: datum.end.x, y: point.y };
|
|
node?.toggleHandles(true);
|
|
if (!ctx.validatePoint(bottomStart, { overflowContinuous: true }) || !ctx.validatePoint(bottomEnd, { overflowContinuous: true })) {
|
|
return;
|
|
}
|
|
datum.set({ startHeight, endHeight });
|
|
ctx.recordAction(`Create ${"disjoint-channel" /* DisjointChannel */} annotation`);
|
|
ctx.showAnnotationOptions();
|
|
ctx.update();
|
|
};
|
|
const actionCancel = () => ctx.delete();
|
|
super("start", {
|
|
start: {
|
|
click: {
|
|
target: "waiting-first-render",
|
|
action: actionCreate
|
|
},
|
|
drag: {
|
|
target: "waiting-first-render",
|
|
action: actionCreate
|
|
},
|
|
reset: StateMachine6.parent
|
|
},
|
|
"waiting-first-render": {
|
|
render: {
|
|
target: "end",
|
|
action: actionFirstRender
|
|
}
|
|
},
|
|
end: {
|
|
hover: actionEndUpdate,
|
|
drag: actionEndUpdate,
|
|
click: {
|
|
target: "height",
|
|
action: actionEndFinish
|
|
},
|
|
dragEnd: {
|
|
target: "height",
|
|
action: actionEndFinish
|
|
},
|
|
reset: {
|
|
target: StateMachine6.parent,
|
|
action: actionCancel
|
|
},
|
|
cancel: {
|
|
target: StateMachine6.parent,
|
|
action: actionCancel
|
|
}
|
|
},
|
|
height: {
|
|
hover: actionHeightUpdate,
|
|
click: {
|
|
target: StateMachine6.parent,
|
|
action: actionHeightFinish
|
|
},
|
|
drag: {
|
|
target: StateMachine6.parent,
|
|
action: actionHeightFinish
|
|
},
|
|
reset: {
|
|
target: StateMachine6.parent,
|
|
action: actionCancel
|
|
},
|
|
cancel: {
|
|
target: StateMachine6.parent,
|
|
action: actionCancel
|
|
}
|
|
}
|
|
});
|
|
this.debug = Debug6.create(true, "annotations");
|
|
this.snapping = false;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
StateMachineProperty6()
|
|
], DisjointChannelStateMachine.prototype, "datum", 2);
|
|
__decorateClass([
|
|
StateMachineProperty6()
|
|
], DisjointChannelStateMachine.prototype, "node", 2);
|
|
__decorateClass([
|
|
StateMachineProperty6()
|
|
], DisjointChannelStateMachine.prototype, "snapping", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/disjoint-channel/disjointChannelConfig.ts
|
|
var disjointChannelConfig = {
|
|
type: "disjoint-channel" /* DisjointChannel */,
|
|
datum: DisjointChannelProperties,
|
|
scene: DisjointChannelScene,
|
|
isDatum: DisjointChannelProperties.is,
|
|
translate: (node, datum, transition, context) => {
|
|
if (DisjointChannelProperties.is(datum) && DisjointChannelScene.is(node)) {
|
|
node.translate(datum, transition, context);
|
|
}
|
|
},
|
|
copy: (node, datum, copiedDatum, context) => {
|
|
if (DisjointChannelProperties.is(datum) && DisjointChannelProperties.is(copiedDatum) && DisjointChannelScene.is(node)) {
|
|
return node.copy(datum, copiedDatum, context);
|
|
}
|
|
},
|
|
update: (node, datum, context) => {
|
|
if (DisjointChannelProperties.is(datum) && DisjointChannelScene.is(node)) {
|
|
node.update(datum, context);
|
|
}
|
|
},
|
|
createState: (ctx, { createDatum }) => new DisjointChannelStateMachine({
|
|
...ctx,
|
|
create: createDatum("disjoint-channel" /* DisjointChannel */)
|
|
}),
|
|
dragState: (ctx) => new DragStateMachine(ctx)
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/fibonacci-retracement-trend-based/fibonacciRetracementTrendBasedScene.ts
|
|
import { Vec2 as Vec212, Vec4 as Vec48, entries as entries3 } from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/scenes/fibonacciScene.ts
|
|
import { _ModuleSupport as _ModuleSupport51 } from "ag-charts-community";
|
|
import { Vec2 as Vec211, Vec4 as Vec47 } from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/utils/fibonacci.ts
|
|
var FIBONACCI_RETRACEMENT_RATIOS = [0, 23.6, 38.2, 50, 61.8, 78.6, 100];
|
|
var FIBONACCI_EXTENSION_RATIOS = [161.8, 261.8, 361.8, 423.6];
|
|
var FIBONACCI_RATIOS = [...FIBONACCI_RETRACEMENT_RATIOS, ...FIBONACCI_EXTENSION_RATIOS];
|
|
var FIBONACCI_RATIOS_MAP = {
|
|
10: FIBONACCI_RATIOS,
|
|
6: FIBONACCI_RETRACEMENT_RATIOS,
|
|
4: FIBONACCI_RETRACEMENT_RATIOS.filter((r) => r !== 78.6 && r !== 23.6)
|
|
};
|
|
var FIBONACCI_RANGE_LABEL_PADDING = 10;
|
|
function getFibonacciCoords(coords1, coords2) {
|
|
const { x2, y1, y2 } = coords1;
|
|
const trendLineVerticalDistance = y1 - y2;
|
|
if (coords2 == null) {
|
|
return {
|
|
x1: x2,
|
|
x2,
|
|
y1: y2 - trendLineVerticalDistance,
|
|
y2
|
|
};
|
|
}
|
|
return {
|
|
x1: coords2.x1,
|
|
x2: coords2.x2,
|
|
y1: coords2.y2 - trendLineVerticalDistance,
|
|
y2: coords2.y2
|
|
};
|
|
}
|
|
function createFibonacciRangesData({ x1, y1, x2, y2 }, context, reverse, yZero, bands = 10) {
|
|
const verticalDistance = y1 - y2;
|
|
const direction = reverse ? -1 : 1;
|
|
let startY = yZero;
|
|
const data = [];
|
|
for (const [index, ratio8] of FIBONACCI_RATIOS_MAP[bands].entries()) {
|
|
const endY = yZero + verticalDistance * (ratio8 / 100) * direction;
|
|
const yDatumVal = context.yAxis.scaleInvert(endY);
|
|
data.push({
|
|
id: index,
|
|
x1,
|
|
x2,
|
|
y1: startY,
|
|
y2: endY,
|
|
tag: ratio8 == 100 ? 0 /* OneLine */ : 1 /* HorizontalLine */,
|
|
label: {
|
|
x1: Math.min(x1, x2) - FIBONACCI_RANGE_LABEL_PADDING,
|
|
x2,
|
|
y1: endY,
|
|
y2: endY,
|
|
text: `${(ratio8 / 100).toFixed(3)} (${yDatumVal.toFixed(2)})`
|
|
}
|
|
});
|
|
startY = endY;
|
|
}
|
|
return data;
|
|
}
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/scenes/fibonacciScene.ts
|
|
var FibonacciScene = class extends AnnotationScene {
|
|
constructor() {
|
|
super();
|
|
this.trendLine = new CollidableLine();
|
|
this.rangeFillsGroup = new _ModuleSupport51.Group({
|
|
name: `${this.id}-range-fills`
|
|
});
|
|
this.rangeFillsGroupSelection = _ModuleSupport51.Selection.select(this.rangeFillsGroup, _ModuleSupport51.Range);
|
|
this.rangeStrokesGroup = new _ModuleSupport51.Group({
|
|
name: `${this.id}-range-strokes`
|
|
});
|
|
this.rangeStrokesGroupSelection = _ModuleSupport51.Selection.select(this.rangeStrokesGroup, CollidableLine);
|
|
this.labelsGroup = new _ModuleSupport51.Group({
|
|
name: `${this.id}-ranges-labels`
|
|
});
|
|
this.labelsGroupSelection = _ModuleSupport51.Selection.select(this.labelsGroup, CollidableText);
|
|
this.anchor = {
|
|
x: 0,
|
|
y: 0,
|
|
position: "above"
|
|
};
|
|
this.append([this.trendLine, this.rangeFillsGroup, this.rangeStrokesGroup, this.labelsGroup]);
|
|
}
|
|
update(datum, context) {
|
|
let coords = convertLine(datum, context);
|
|
if (coords == null) {
|
|
this.visible = false;
|
|
return;
|
|
}
|
|
coords = Vec47.round(coords);
|
|
this.visible = datum.visible ?? true;
|
|
if (!this.visible)
|
|
return;
|
|
this.updateLine(datum, coords, this.trendLine);
|
|
this.updateHandles(datum, coords);
|
|
this.updateAnchor(datum, coords, context);
|
|
const { reverse } = datum;
|
|
const extendedCoords = this.extendLine(coords, datum, context);
|
|
const yZero = reverse ? extendedCoords.y1 : extendedCoords.y2;
|
|
const yOne = reverse ? extendedCoords.y2 : extendedCoords.y1;
|
|
const data = createFibonacciRangesData(extendedCoords, context, datum.reverse, yZero, datum.bands);
|
|
this.updateRanges(datum, data, context);
|
|
const oneLinePoints = { ...extendedCoords, y1: yOne, y2: yOne };
|
|
this.updateText(datum, oneLinePoints);
|
|
}
|
|
extendLine({ x1, y1, x2, y2 }, datum, context) {
|
|
const linePoints = { x1, y1, x2, y2 };
|
|
if (!datum.extendStart && !datum.extendEnd) {
|
|
return linePoints;
|
|
}
|
|
const { x, width } = context.xAxis.bounds;
|
|
if (datum.extendEnd) {
|
|
linePoints[x1 > x2 ? "x1" : "x2"] = x + width;
|
|
}
|
|
if (datum.extendStart) {
|
|
linePoints[x1 > x2 ? "x2" : "x1"] = x;
|
|
}
|
|
return linePoints;
|
|
}
|
|
updateLine(datum, coords, line) {
|
|
if (!coords || !line) {
|
|
return;
|
|
}
|
|
const { lineDashOffset, strokeWidth, strokeOpacity, stroke: stroke3 } = datum;
|
|
line.setProperties({
|
|
...coords,
|
|
lineCap: datum.getLineCap(),
|
|
lineDash: [3, 4],
|
|
lineDashOffset,
|
|
strokeWidth,
|
|
strokeOpacity,
|
|
fillOpacity: 0,
|
|
stroke: stroke3
|
|
});
|
|
}
|
|
updateRangeStrokes(datum) {
|
|
const { lineDashOffset, strokeWidth, strokeOpacity, strokes, rangeStroke, isMultiColor } = datum;
|
|
this.rangeStrokesGroupSelection.each((line, { x1, x2, y2, tag }, index) => {
|
|
const y = y2;
|
|
const color7 = isMultiColor ? strokes[index % strokes.length] : rangeStroke;
|
|
line.setProperties({
|
|
x1,
|
|
x2,
|
|
y1: y,
|
|
y2: y,
|
|
stroke: color7,
|
|
strokeOpacity,
|
|
strokeWidth,
|
|
lineCap: datum.getLineCap(),
|
|
lineDash: datum.getLineDash(),
|
|
lineDashOffset,
|
|
tag
|
|
});
|
|
});
|
|
}
|
|
updateRanges(datum, data, context) {
|
|
const getDatumId = (d) => d.id;
|
|
this.rangeFillsGroupSelection.update(data, void 0, getDatumId);
|
|
this.rangeStrokesGroupSelection.update(data, void 0, getDatumId);
|
|
this.labelsGroupSelection.update(data, void 0, getDatumId);
|
|
this.updateRangeFills(datum);
|
|
this.updateRangeStrokes(datum);
|
|
this.updateRangeLabels(datum, context);
|
|
}
|
|
updateRangeFills(datum) {
|
|
const {
|
|
lineDashOffset,
|
|
strokeWidth,
|
|
strokeOpacity,
|
|
strokes: colors,
|
|
rangeStroke,
|
|
showFill,
|
|
isMultiColor
|
|
} = datum;
|
|
this.rangeFillsGroupSelection.each((range2, { x1, x2, y1, y2 }, index) => {
|
|
const color7 = isMultiColor ? colors[index % colors.length] : rangeStroke;
|
|
if (!showFill) {
|
|
range2.visible = false;
|
|
return;
|
|
}
|
|
range2.setProperties({
|
|
x1,
|
|
x2,
|
|
y1,
|
|
y2,
|
|
startLine: false,
|
|
endLine: false,
|
|
stroke: color7,
|
|
strokeOpacity,
|
|
fill: color7,
|
|
fillOpacity: (strokeOpacity ?? 1) * 0.15,
|
|
strokeWidth,
|
|
lineCap: datum.getLineCap(),
|
|
lineDash: datum.getLineDash(),
|
|
lineDashOffset,
|
|
visible: true
|
|
});
|
|
});
|
|
}
|
|
updateRangeLabels(trendLineProperties, { xAxis }) {
|
|
const { rangeStrokesGroupSelection } = this;
|
|
const {
|
|
strokes: colors,
|
|
strokeWidth,
|
|
rangeStroke,
|
|
isMultiColor,
|
|
label: { fontFamily, fontSize, fontStyle, fontWeight, color: color7 }
|
|
} = trendLineProperties;
|
|
const labelProperties = {
|
|
fontFamily,
|
|
fontSize,
|
|
fontStyle,
|
|
fontWeight
|
|
};
|
|
const withinBounds = this.checkWithinBounds(xAxis, labelProperties, this.labelsGroupSelection.at(0));
|
|
this.labelsGroupSelection.each((textNode, datum, index) => {
|
|
const textColor = color7 ?? (isMultiColor ? colors[index % colors.length] : rangeStroke);
|
|
const line = rangeStrokesGroupSelection.at(index);
|
|
if (!line) {
|
|
return;
|
|
}
|
|
const { text: text2, ...coords } = datum.label;
|
|
if (withinBounds) {
|
|
textNode.setProperties({
|
|
...labelProperties,
|
|
text: text2,
|
|
x: coords.x1,
|
|
y: coords.y1,
|
|
textBaseline: "middle",
|
|
textAlign: "end",
|
|
fill: textColor
|
|
});
|
|
updateLineText(textNode.id, line, coords);
|
|
} else {
|
|
const textProperties = {
|
|
...labelProperties,
|
|
label: text2,
|
|
position: "center",
|
|
alignment: "left",
|
|
color: textColor
|
|
};
|
|
updateLineText(textNode.id, line, coords, textProperties, textNode, text2, strokeWidth);
|
|
}
|
|
});
|
|
}
|
|
checkWithinBounds(xAxis, fontOptions, textNode) {
|
|
if (!textNode) {
|
|
return false;
|
|
}
|
|
const { text: text2, ...coords } = textNode.datum.label;
|
|
textNode.setProperties({
|
|
...fontOptions,
|
|
text: text2,
|
|
x: coords.x1,
|
|
y: coords.y1,
|
|
textBaseline: "middle",
|
|
textAlign: "end"
|
|
});
|
|
const { x } = textNode.getBBox();
|
|
return x >= xAxis.bounds.x && x <= xAxis.bounds.x + xAxis.bounds.width;
|
|
}
|
|
updateText(datum, coords) {
|
|
const oneLine = this.rangeStrokesGroupSelection.selectByTag(0 /* OneLine */)[0];
|
|
if (!oneLine) {
|
|
return;
|
|
}
|
|
const { text: textProperties, strokeWidth } = datum;
|
|
this.text = this.updateNode(CollidableText, this.text, !!textProperties.label);
|
|
updateLineText(oneLine.id, oneLine, coords, textProperties, this.text, textProperties.label, strokeWidth);
|
|
}
|
|
updateAnchor(_datum, coords, _context, _bbox) {
|
|
const point = Vec47.topCenter(coords);
|
|
Vec211.apply(this.anchor, _ModuleSupport51.Transformable.toCanvasPoint(this.trendLine, point.x, point.y));
|
|
}
|
|
containsPoint(x, y) {
|
|
const { trendLine, rangeStrokesGroupSelection, text: text2 } = this;
|
|
let isInStrokePath = false;
|
|
rangeStrokesGroupSelection.each((line) => isInStrokePath || (isInStrokePath = line.isPointInPath(x, y)));
|
|
return isInStrokePath || trendLine.isPointInPath(x, y) || Boolean(text2?.containsPoint(x, y));
|
|
}
|
|
getNodeAtCoords(x, y) {
|
|
if (this.text?.containsPoint(x, y))
|
|
return "text";
|
|
if (this.trendLine.isPointInPath(x, y))
|
|
return "line";
|
|
}
|
|
getHandleStyles(datum) {
|
|
return {
|
|
fill: datum.handle.fill,
|
|
stroke: datum.handle.stroke ?? datum.stroke,
|
|
strokeOpacity: datum.handle.strokeOpacity ?? datum.strokeOpacity,
|
|
strokeWidth: datum.handle.strokeWidth ?? datum.strokeWidth
|
|
};
|
|
}
|
|
drag(datum, target, context, snapping) {
|
|
if (!datum.isWriteable())
|
|
return;
|
|
if (this.activeHandle) {
|
|
this.dragHandle(datum, target, context, snapping);
|
|
} else {
|
|
this.dragAll(datum, target, context);
|
|
}
|
|
}
|
|
getAnchor() {
|
|
return this.anchor;
|
|
}
|
|
getCursor() {
|
|
return "pointer";
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/utils/validation.ts
|
|
import { _ModuleSupport as _ModuleSupport52 } from "ag-charts-community";
|
|
import { Logger as Logger3 } from "ag-charts-core";
|
|
var { ContinuousScale: ContinuousScale3 } = _ModuleSupport52;
|
|
function validateDatumPoint(context, point, options = { overflowContinuous: false }, warningPrefix) {
|
|
if (point.x == null || point.y == null) {
|
|
if (warningPrefix) {
|
|
Logger3.warnOnce(`${warningPrefix}requires both an [x] and [y] property, ignoring.`);
|
|
}
|
|
return false;
|
|
}
|
|
const { xAxis, yAxis } = context;
|
|
const continuousX = options.overflowContinuous && ContinuousScale3.is(xAxis.scale);
|
|
const continuousY = options.overflowContinuous && ContinuousScale3.is(yAxis.scale);
|
|
const validX = continuousX || validateDatumPointDirection(point.x, xAxis);
|
|
const validY = continuousY || validateDatumPointDirection(point.y, yAxis);
|
|
if (validX && validY)
|
|
return true;
|
|
if (warningPrefix) {
|
|
let text2 = "x & y domains";
|
|
if (validX)
|
|
text2 = "y domain";
|
|
if (validY)
|
|
text2 = "x domain";
|
|
const xValue = getGroupingValue(point.x);
|
|
const yValue = getGroupingValue(point.y);
|
|
Logger3.warnOnce(`${warningPrefix}is outside the ${text2}, ignoring. - x: [${xValue}], y: ${yValue}]`);
|
|
}
|
|
return false;
|
|
}
|
|
function validateDatumPointDirection(d, context) {
|
|
const { domain } = context.scale;
|
|
const value = getGroupingValue(d);
|
|
if (domain && value != null && context.continuous) {
|
|
return value >= domain[0] && value <= domain.at(-1);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/fibonacci-retracement-trend-based/fibonacciRetracementTrendBasedScene.ts
|
|
var FibonacciRetracementTrendBasedScene = class extends FibonacciScene {
|
|
constructor() {
|
|
super();
|
|
this.type = "fibonacci-retracement-trend-based";
|
|
this.endRetracementLine = new CollidableLine();
|
|
this.start = new DivariantHandle();
|
|
this.end = new DivariantHandle();
|
|
this.endRetracement = new DivariantHandle();
|
|
this.append([this.endRetracementLine, this.start, this.end, this.endRetracement]);
|
|
}
|
|
static is(value) {
|
|
return AnnotationScene.isCheck(value, "fibonacci-retracement-trend-based");
|
|
}
|
|
update(datum, context) {
|
|
let { coords1, coords2 } = this.getCoords(datum, context);
|
|
if (coords1 == null || coords2 == null) {
|
|
this.visible = false;
|
|
return;
|
|
}
|
|
coords1 = Vec48.round(coords1);
|
|
coords2 = Vec48.round(coords2);
|
|
this.visible = datum.visible ?? true;
|
|
if (!this.visible)
|
|
return;
|
|
if (datum.endRetracement.x == void 0 || datum.endRetracement.y == void 0) {
|
|
coords2 = void 0;
|
|
}
|
|
this.updateLine(datum, coords1, this.trendLine);
|
|
this.updateLine(datum, coords2, this.endRetracementLine);
|
|
this.updateHandles(datum, coords1, coords2);
|
|
this.updateAnchor(datum, coords2 ?? coords1, context);
|
|
const { reverse, bands } = datum;
|
|
const coords = getFibonacciCoords(coords1, coords2);
|
|
const extendedCoords = this.extendLine(coords, datum, context);
|
|
const yZero = extendedCoords.y2;
|
|
const yOne = extendedCoords.y1;
|
|
const data = coords2 ? createFibonacciRangesData(extendedCoords, context, reverse, yZero, bands) : [];
|
|
this.updateRanges(datum, data, context);
|
|
const oneLinePoints = { ...extendedCoords, y1: yOne, y2: yOne };
|
|
this.updateText(datum, oneLinePoints);
|
|
}
|
|
containsPoint(x, y) {
|
|
const { start, end, endRetracement, endRetracementLine } = this;
|
|
this.activeHandle = void 0;
|
|
if (start.containsPoint(x, y)) {
|
|
this.activeHandle = "start";
|
|
return true;
|
|
}
|
|
if (end.containsPoint(x, y)) {
|
|
this.activeHandle = "end";
|
|
return true;
|
|
}
|
|
if (endRetracement.containsPoint(x, y)) {
|
|
this.activeHandle = "endRetracement";
|
|
return true;
|
|
}
|
|
return endRetracementLine.isPointInPath(x, y) || super.containsPoint(x, y);
|
|
}
|
|
getNodeAtCoords(x, y) {
|
|
if (this.start.containsPoint(x, y) || this.end.containsPoint(x, y) || this.endRetracement.containsPoint(x, y))
|
|
return "handle";
|
|
if (this.endRetracementLine.isPointInPath(x, y))
|
|
return "line";
|
|
return super.getNodeAtCoords(x, y);
|
|
}
|
|
dragStart(datum, target, context) {
|
|
this.dragState = {
|
|
offset: target,
|
|
...getDragStartState({ start: datum.start, end: datum.end, endRetracement: datum.endRetracement }, context)
|
|
};
|
|
}
|
|
stopDragging() {
|
|
this.start.toggleDragging(false);
|
|
this.end.toggleDragging(false);
|
|
this.endRetracement.toggleDragging(false);
|
|
}
|
|
dragAll(datum, target, context) {
|
|
const { dragState } = this;
|
|
if (!dragState)
|
|
return;
|
|
this.translatePoints({
|
|
datum,
|
|
start: dragState.start,
|
|
end: dragState.end,
|
|
endRetracement: dragState.endRetracement,
|
|
translation: Vec212.sub(target, dragState.offset),
|
|
context
|
|
});
|
|
}
|
|
dragHandle(datum, target, context, snapping) {
|
|
const { activeHandle, dragState } = this;
|
|
if (!activeHandle || !dragState)
|
|
return;
|
|
this[activeHandle].toggleDragging(true);
|
|
const point = snapping ? this.snapToAngle(datum, target, context) : invertCoords(this[activeHandle].drag(target).point, context);
|
|
if (!point || !validateDatumPoint(context, point))
|
|
return;
|
|
datum[activeHandle].x = point.x;
|
|
datum[activeHandle].y = point.y;
|
|
}
|
|
snapToAngle(datum, coords, context) {
|
|
const { activeHandle } = this;
|
|
const handles = ["start", "end", "endRetracement"];
|
|
if (!activeHandle)
|
|
return;
|
|
const index = (handles.indexOf(activeHandle) + 1) % handles.length;
|
|
const fixedHandle = handles[index];
|
|
this[activeHandle].toggleDragging(true);
|
|
const fixed = convertPoint(datum[fixedHandle], context);
|
|
return invertCoords(snapToAngle(coords, fixed, datum.snapToAngle), context);
|
|
}
|
|
translatePoints({
|
|
datum,
|
|
start,
|
|
end,
|
|
endRetracement,
|
|
translation,
|
|
context
|
|
}) {
|
|
const points = translate({ start, end, endRetracement }, translation, context, { overflowContinuous: 2 });
|
|
datum.start.x = points.start.x;
|
|
datum.end.x = points.end.x;
|
|
datum.endRetracement.x = points.endRetracement.x;
|
|
datum.start.y = points.start.y;
|
|
datum.end.y = points.end.y;
|
|
datum.endRetracement.y = points.endRetracement.y;
|
|
}
|
|
translate(datum, translation, context) {
|
|
this.translatePoints({
|
|
datum,
|
|
start: convertPoint(datum.start, context),
|
|
end: convertPoint(datum.end, context),
|
|
endRetracement: convertPoint(datum.endRetracement, context),
|
|
translation,
|
|
context
|
|
});
|
|
}
|
|
copy(datum, copiedDatum, context) {
|
|
const { coords1, coords2 } = this.getCoords(datum, context);
|
|
if (!coords1 || !coords2) {
|
|
return;
|
|
}
|
|
const bbox = this.computeBBoxWithoutHandles();
|
|
this.translatePoints({
|
|
datum: copiedDatum,
|
|
start: Vec48.start(coords1),
|
|
end: Vec48.end(coords1),
|
|
endRetracement: Vec48.end(coords2),
|
|
translation: { x: -bbox.width / 2, y: -bbox.height / 2 },
|
|
context
|
|
});
|
|
return copiedDatum;
|
|
}
|
|
getCoords(datum, context) {
|
|
return {
|
|
coords1: convertLine(datum, context),
|
|
coords2: convertLine({ start: datum.end, end: datum.endRetracement }, context)
|
|
};
|
|
}
|
|
toggleHandles(show) {
|
|
if (typeof show === "boolean") {
|
|
this.start.visible = show;
|
|
this.end.visible = show;
|
|
this.endRetracement.visible = show;
|
|
} else {
|
|
for (const [handle3, visible] of entries3(show)) {
|
|
this[handle3].visible = visible;
|
|
}
|
|
}
|
|
this.start.toggleHovered(this.activeHandle === "start");
|
|
this.end.toggleHovered(this.activeHandle === "end");
|
|
this.endRetracement.toggleHovered(this.activeHandle === "endRetracement");
|
|
}
|
|
toggleActive(active) {
|
|
this.toggleHandles(active);
|
|
this.start.toggleActive(active);
|
|
this.end.toggleActive(active);
|
|
this.endRetracement.toggleActive(active);
|
|
}
|
|
updateHandles(datum, coords1, coords2, bbox) {
|
|
this.start.update({
|
|
...this.getHandleStyles(datum),
|
|
...this.getHandleCoords(datum, coords1, "start")
|
|
});
|
|
this.end.update({
|
|
...this.getHandleStyles(datum),
|
|
...this.getHandleCoords(datum, coords1, "end", bbox)
|
|
});
|
|
if (coords2) {
|
|
this.endRetracement.update({
|
|
...this.getHandleStyles(datum),
|
|
...this.getHandleCoords(datum, coords2, "endRetracement", bbox)
|
|
});
|
|
}
|
|
this.start.toggleLocked(datum.locked ?? false);
|
|
this.end.toggleLocked(datum.locked ?? false);
|
|
this.endRetracement.toggleLocked(datum.locked ?? false);
|
|
}
|
|
getHandleCoords(_datum, coords, handle3, _bbox) {
|
|
return handle3 === "start" ? Vec48.start(coords) : Vec48.end(coords);
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/fibonacci-retracement-trend-based/fibonacciRetracementTrendBasedState.ts
|
|
import { Debug as Debug7, StateMachine as StateMachine7, StateMachineProperty as StateMachineProperty7 } from "ag-charts-core";
|
|
var FibonacciRetracementTrendBasedStateMachine = class extends StateMachine7 {
|
|
constructor(ctx) {
|
|
const actionCreate = ({ point }) => {
|
|
const datum = this.createDatum();
|
|
datum.set({ start: point, end: point });
|
|
ctx.create(datum);
|
|
};
|
|
const actionFirstRender = () => {
|
|
const { node } = this;
|
|
node?.toggleActive(true);
|
|
node?.toggleHandles({ start: true, end: false, endRetracement: false });
|
|
};
|
|
const actionEndUpdate = ({ offset, context }) => {
|
|
const { datum, snapping } = this;
|
|
if (!datum)
|
|
return;
|
|
datum.set({ end: snapPoint(offset, context, snapping, datum.start, datum.snapToAngle) });
|
|
ctx.update();
|
|
};
|
|
const actionEndFinish = () => {
|
|
const { datum } = this;
|
|
if (!datum)
|
|
return;
|
|
datum.endRetracement.x = datum.end.x;
|
|
datum.endRetracement.y = datum.end.y;
|
|
this.node?.toggleHandles({ end: true });
|
|
ctx.update();
|
|
};
|
|
const actionEndRetracementUpdate = ({ offset, context }) => {
|
|
const { datum, snapping } = this;
|
|
if (!datum)
|
|
return;
|
|
datum.set({ endRetracement: snapPoint(offset, context, snapping, datum.end, datum.snapToAngle) });
|
|
ctx.update();
|
|
};
|
|
const actionEndRetracementFinish = () => {
|
|
this.node?.toggleHandles({ endRetracement: true });
|
|
ctx.update();
|
|
};
|
|
const actionCancel = () => ctx.delete();
|
|
const onExitEnd = () => {
|
|
ctx.showAnnotationOptions();
|
|
ctx.recordAction(`Create ${this.datum?.type} annotation`);
|
|
};
|
|
super("start", {
|
|
start: {
|
|
click: {
|
|
target: "waiting-first-render",
|
|
action: actionCreate
|
|
},
|
|
drag: {
|
|
target: "waiting-first-render",
|
|
action: actionCreate
|
|
},
|
|
reset: StateMachine7.parent
|
|
},
|
|
"waiting-first-render": {
|
|
render: {
|
|
target: "end",
|
|
action: actionFirstRender
|
|
}
|
|
},
|
|
end: {
|
|
hover: actionEndUpdate,
|
|
click: {
|
|
target: "endRetracement",
|
|
action: actionEndFinish
|
|
},
|
|
drag: actionEndUpdate,
|
|
dragEnd: {
|
|
target: "endRetracement",
|
|
action: actionEndFinish
|
|
},
|
|
reset: {
|
|
target: StateMachine7.parent,
|
|
action: actionCancel
|
|
},
|
|
cancel: {
|
|
target: StateMachine7.parent,
|
|
action: actionCancel
|
|
},
|
|
onExit: onExitEnd
|
|
},
|
|
endRetracement: {
|
|
hover: actionEndRetracementUpdate,
|
|
click: {
|
|
target: StateMachine7.parent,
|
|
action: actionEndRetracementFinish
|
|
},
|
|
drag: {
|
|
target: StateMachine7.parent,
|
|
action: actionEndRetracementFinish
|
|
},
|
|
reset: {
|
|
target: StateMachine7.parent,
|
|
action: actionCancel
|
|
},
|
|
cancel: {
|
|
target: StateMachine7.parent,
|
|
action: actionCancel
|
|
}
|
|
}
|
|
});
|
|
this.debug = Debug7.create(true, "annotations");
|
|
this.snapping = false;
|
|
}
|
|
createDatum() {
|
|
return new FibonacciRetracementTrendBasedProperties();
|
|
}
|
|
};
|
|
__decorateClass([
|
|
StateMachineProperty7()
|
|
], FibonacciRetracementTrendBasedStateMachine.prototype, "datum", 2);
|
|
__decorateClass([
|
|
StateMachineProperty7()
|
|
], FibonacciRetracementTrendBasedStateMachine.prototype, "node", 2);
|
|
__decorateClass([
|
|
StateMachineProperty7()
|
|
], FibonacciRetracementTrendBasedStateMachine.prototype, "snapping", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/fibonacci-retracement-trend-based/fibonacciRetracementTrendBasedConfig.ts
|
|
var fibonacciRetracementTrendBasedConfig = {
|
|
type: "fibonacci-retracement-trend-based" /* FibonacciRetracementTrendBased */,
|
|
datum: FibonacciRetracementTrendBasedProperties,
|
|
scene: FibonacciRetracementTrendBasedScene,
|
|
isDatum: FibonacciRetracementTrendBasedProperties.is,
|
|
translate: (node, datum, transition, context) => {
|
|
if (FibonacciRetracementTrendBasedProperties.is(datum) && FibonacciRetracementTrendBasedScene.is(node))
|
|
node.translate(datum, transition, context);
|
|
},
|
|
copy: (node, datum, copiedDatum, context) => {
|
|
if (FibonacciRetracementTrendBasedProperties.is(datum) && FibonacciRetracementTrendBasedProperties.is(copiedDatum) && FibonacciRetracementTrendBasedScene.is(node)) {
|
|
return node.copy(datum, copiedDatum, context);
|
|
}
|
|
},
|
|
update: (node, datum, context) => {
|
|
if (FibonacciRetracementTrendBasedProperties.is(datum) && FibonacciRetracementTrendBasedScene.is(node)) {
|
|
node.update(datum, context);
|
|
}
|
|
},
|
|
createState: (ctx, { createDatum }) => new FibonacciRetracementTrendBasedStateMachine({
|
|
...ctx,
|
|
create: createDatum("fibonacci-retracement-trend-based" /* FibonacciRetracementTrendBased */)
|
|
}),
|
|
dragState: (ctx) => new DragStateMachine(ctx)
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/fibonacci-retracement/fibonacciRetracementScene.ts
|
|
import { Vec2 as Vec213, Vec4 as Vec49, entries as entries4 } from "ag-charts-core";
|
|
var FibonacciRetracementScene = class extends FibonacciScene {
|
|
constructor() {
|
|
super();
|
|
this.type = "fibonacci-retracement";
|
|
this.start = new DivariantHandle();
|
|
this.end = new DivariantHandle();
|
|
this.append([this.start, this.end]);
|
|
}
|
|
static is(value) {
|
|
return AnnotationScene.isCheck(value, "fibonacci-retracement");
|
|
}
|
|
containsPoint(x, y) {
|
|
const { start, end } = this;
|
|
this.activeHandle = void 0;
|
|
if (start.containsPoint(x, y)) {
|
|
this.activeHandle = "start";
|
|
return true;
|
|
}
|
|
if (end.containsPoint(x, y)) {
|
|
this.activeHandle = "end";
|
|
return true;
|
|
}
|
|
return super.containsPoint(x, y);
|
|
}
|
|
getNodeAtCoords(x, y) {
|
|
if (this.start.containsPoint(x, y) || this.end.containsPoint(x, y))
|
|
return "handle";
|
|
return super.getNodeAtCoords(x, y);
|
|
}
|
|
dragStart(datum, target, context) {
|
|
this.dragState = {
|
|
offset: target,
|
|
...getDragStartState({ start: datum.start, end: datum.end }, context)
|
|
};
|
|
}
|
|
stopDragging() {
|
|
this.start.toggleDragging(false);
|
|
this.end.toggleDragging(false);
|
|
}
|
|
dragAll(datum, target, context) {
|
|
const { dragState } = this;
|
|
if (!dragState)
|
|
return;
|
|
this.translatePoints({
|
|
datum,
|
|
start: dragState.start,
|
|
end: dragState.end,
|
|
translation: Vec213.sub(target, dragState.offset),
|
|
context
|
|
});
|
|
}
|
|
dragHandle(datum, target, context, snapping) {
|
|
const { activeHandle, dragState } = this;
|
|
if (!activeHandle || !dragState)
|
|
return;
|
|
this[activeHandle].toggleDragging(true);
|
|
const point = snapping ? this.snapToAngle(datum, target, context) : invertCoords(this[activeHandle].drag(target).point, context);
|
|
if (!point || !validateDatumPoint(context, point))
|
|
return;
|
|
datum[activeHandle].x = point.x;
|
|
datum[activeHandle].y = point.y;
|
|
}
|
|
snapToAngle(datum, coords, context) {
|
|
const { activeHandle } = this;
|
|
const handles = ["start", "end"];
|
|
const fixedHandle = handles.find((handle3) => handle3 !== activeHandle);
|
|
if (!activeHandle || !fixedHandle)
|
|
return;
|
|
this[activeHandle].toggleDragging(true);
|
|
const fixed = convertPoint(datum[fixedHandle], context);
|
|
return invertCoords(snapToAngle(coords, fixed, datum.snapToAngle), context);
|
|
}
|
|
translatePoints({
|
|
datum,
|
|
start,
|
|
end,
|
|
translation,
|
|
context
|
|
}) {
|
|
const points = translate({ start, end }, translation, context, { overflowContinuous: 1 });
|
|
datum.start.x = points.start.x;
|
|
datum.end.x = points.end.x;
|
|
datum.start.y = points.start.y;
|
|
datum.end.y = points.end.y;
|
|
}
|
|
translate(datum, translation, context) {
|
|
this.translatePoints({
|
|
datum,
|
|
start: convertPoint(datum.start, context),
|
|
end: convertPoint(datum.end, context),
|
|
translation,
|
|
context
|
|
});
|
|
}
|
|
copy(datum, copiedDatum, context) {
|
|
const coords = convertLine(datum, context);
|
|
if (!coords) {
|
|
return;
|
|
}
|
|
const bbox = this.computeBBoxWithoutHandles();
|
|
this.translatePoints({
|
|
datum: copiedDatum,
|
|
start: { x: coords.x1, y: coords.y1 },
|
|
end: { x: coords.x2, y: coords.y2 },
|
|
translation: { x: -bbox.width / 2, y: -bbox.height / 2 },
|
|
context
|
|
});
|
|
return copiedDatum;
|
|
}
|
|
toggleHandles(show) {
|
|
if (typeof show === "boolean") {
|
|
this.start.visible = show;
|
|
this.end.visible = show;
|
|
} else {
|
|
for (const [handle3, visible] of entries4(show)) {
|
|
this[handle3].visible = visible;
|
|
}
|
|
}
|
|
this.start.toggleHovered(this.activeHandle === "start");
|
|
this.end.toggleHovered(this.activeHandle === "end");
|
|
}
|
|
toggleActive(active) {
|
|
this.toggleHandles(active);
|
|
this.start.toggleActive(active);
|
|
this.end.toggleActive(active);
|
|
}
|
|
updateHandles(datum, coords, _coords2, bbox) {
|
|
this.start.update({
|
|
...this.getHandleStyles(datum),
|
|
...this.getHandleCoords(datum, coords, "start")
|
|
});
|
|
this.end.update({
|
|
...this.getHandleStyles(datum),
|
|
...this.getHandleCoords(datum, coords, "end", bbox)
|
|
});
|
|
this.start.toggleLocked(datum.locked ?? false);
|
|
this.end.toggleLocked(datum.locked ?? false);
|
|
}
|
|
getHandleCoords(_datum, coords, handle3, _bbox) {
|
|
return handle3 === "start" ? Vec49.start(coords) : Vec49.end(coords);
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/line/lineState.ts
|
|
import { Debug as Debug8, StateMachine as StateMachine8, StateMachineProperty as StateMachineProperty8 } from "ag-charts-core";
|
|
var LineTypeStateMachine = class extends StateMachine8 {
|
|
constructor(ctx) {
|
|
const actionCreate = ({ point }) => {
|
|
const datum = this.createDatum();
|
|
datum.set({ start: point, end: point });
|
|
ctx.create(datum);
|
|
};
|
|
const actionFirstRender = () => {
|
|
const { node } = this;
|
|
node?.toggleActive(true);
|
|
node?.toggleHandles({ start: true, end: false });
|
|
};
|
|
const actionEndUpdate = ({ offset, context }) => {
|
|
const { datum, snapping } = this;
|
|
if (!datum)
|
|
return;
|
|
datum.set({ end: snapPoint(offset, context, snapping, datum.start, datum.snapToAngle) });
|
|
ctx.update();
|
|
};
|
|
const actionEndFinish = () => {
|
|
this.node?.toggleHandles({ end: true });
|
|
ctx.update();
|
|
};
|
|
const actionCancel = () => ctx.delete();
|
|
const onExitEnd = () => {
|
|
ctx.showAnnotationOptions();
|
|
ctx.recordAction(`Create ${this.datum?.type} annotation`);
|
|
};
|
|
super("start", {
|
|
start: {
|
|
click: {
|
|
target: "waiting-first-render",
|
|
action: actionCreate
|
|
},
|
|
drag: {
|
|
target: "waiting-first-render",
|
|
action: actionCreate
|
|
},
|
|
reset: StateMachine8.parent
|
|
},
|
|
"waiting-first-render": {
|
|
render: {
|
|
target: "end",
|
|
action: actionFirstRender
|
|
}
|
|
},
|
|
end: {
|
|
hover: actionEndUpdate,
|
|
click: {
|
|
target: StateMachine8.parent,
|
|
action: actionEndFinish
|
|
},
|
|
drag: actionEndUpdate,
|
|
dragEnd: {
|
|
target: StateMachine8.parent,
|
|
action: actionEndFinish
|
|
},
|
|
reset: {
|
|
target: StateMachine8.parent,
|
|
action: actionCancel
|
|
},
|
|
cancel: {
|
|
target: StateMachine8.parent,
|
|
action: actionCancel
|
|
},
|
|
onExit: onExitEnd
|
|
}
|
|
});
|
|
this.debug = Debug8.create(true, "annotations");
|
|
this.snapping = false;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
StateMachineProperty8()
|
|
], LineTypeStateMachine.prototype, "datum", 2);
|
|
__decorateClass([
|
|
StateMachineProperty8()
|
|
], LineTypeStateMachine.prototype, "node", 2);
|
|
__decorateClass([
|
|
StateMachineProperty8()
|
|
], LineTypeStateMachine.prototype, "snapping", 2);
|
|
var ArrowStateMachine = class extends LineTypeStateMachine {
|
|
createDatum() {
|
|
return new ArrowProperties();
|
|
}
|
|
};
|
|
var LineStateMachine = class extends LineTypeStateMachine {
|
|
createDatum() {
|
|
return new LineProperties();
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/fibonacci-retracement/fibonacciRetracementState.ts
|
|
var FibonacciRetracementStateMachine = class extends LineTypeStateMachine {
|
|
createDatum() {
|
|
return new FibonacciRetracementProperties();
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/fibonacci-retracement/fibonacciRetracementConfig.ts
|
|
var fibonacciRetracementConfig = {
|
|
type: "fibonacci-retracement" /* FibonacciRetracement */,
|
|
datum: FibonacciRetracementProperties,
|
|
scene: FibonacciRetracementScene,
|
|
isDatum: FibonacciRetracementProperties.is,
|
|
translate: (node, datum, transition, context) => {
|
|
if (FibonacciRetracementProperties.is(datum) && FibonacciRetracementScene.is(node))
|
|
node.translate(datum, transition, context);
|
|
},
|
|
copy: (node, datum, copiedDatum, context) => {
|
|
if (FibonacciRetracementProperties.is(datum) && FibonacciRetracementProperties.is(copiedDatum) && FibonacciRetracementScene.is(node)) {
|
|
return node.copy(datum, copiedDatum, context);
|
|
}
|
|
},
|
|
update: (node, datum, context) => {
|
|
if (FibonacciRetracementProperties.is(datum) && FibonacciRetracementScene.is(node)) {
|
|
node.update(datum, context);
|
|
}
|
|
},
|
|
createState: (ctx, { createDatum }) => new FibonacciRetracementStateMachine({
|
|
...ctx,
|
|
create: createDatum("fibonacci-retracement" /* FibonacciRetracement */)
|
|
}),
|
|
dragState: (ctx) => new DragStateMachine(ctx)
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/line/lineScene.ts
|
|
import { _ModuleSupport as _ModuleSupport54 } from "ag-charts-community";
|
|
import { Vec2 as Vec215, Vec4 as Vec410 } from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/scenes/capScene.ts
|
|
import { _ModuleSupport as _ModuleSupport53 } from "ag-charts-community";
|
|
import { Vec2 as Vec214 } from "ag-charts-core";
|
|
var CapScene = class extends _ModuleSupport53.Group {
|
|
};
|
|
var ArrowCapScene = class extends CapScene {
|
|
constructor() {
|
|
super();
|
|
this.type = "arrow";
|
|
this.path = new _ModuleSupport53.Path();
|
|
this.armLength = 6;
|
|
this.append([this.path]);
|
|
}
|
|
update(options) {
|
|
const { path } = this;
|
|
const { x, y, angle, ...rest } = options;
|
|
const origin = Vec214.from(x, y);
|
|
const offsetAngle = 3 * Math.PI / 4;
|
|
const armLength = this.armLength + (options.strokeWidth ?? 0) * 2;
|
|
const leftEnd = Vec214.rotate(Vec214.from(0, armLength), angle + offsetAngle, origin);
|
|
const rightEnd = Vec214.rotate(Vec214.from(armLength, 0), angle - offsetAngle, origin);
|
|
path.setProperties(rest);
|
|
path.fillOpacity = 0;
|
|
path.path.clear();
|
|
path.path.moveTo(leftEnd.x, leftEnd.y);
|
|
path.path.lineTo(origin.x, origin.y);
|
|
path.path.lineTo(rightEnd.x, rightEnd.y);
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/line/lineScene.ts
|
|
var { Transformable: Transformable2 } = _ModuleSupport54;
|
|
var LineScene = class extends StartEndScene {
|
|
constructor() {
|
|
super();
|
|
this.type = "line";
|
|
this.line = new CollidableLine();
|
|
this.append([this.line, this.start, this.end]);
|
|
}
|
|
static is(value) {
|
|
return AnnotationScene.isCheck(value, "line");
|
|
}
|
|
update(datum, context) {
|
|
let coords = convertLine(datum, context);
|
|
if (coords == null) {
|
|
this.visible = false;
|
|
return;
|
|
}
|
|
coords = Vec410.round(coords);
|
|
this.visible = datum.visible ?? true;
|
|
if (!this.visible)
|
|
return;
|
|
this.updateLine(datum, coords, context);
|
|
this.updateHandles(datum, coords);
|
|
this.updateText(datum, coords);
|
|
this.updateCaps(datum, coords);
|
|
this.updateAnchor(datum, coords, context);
|
|
}
|
|
updateLine(datum, coords, context) {
|
|
const { line } = this;
|
|
const { lineDashOffset, stroke: stroke3, strokeWidth, strokeOpacity } = datum;
|
|
const linePoints = this.extendLine(coords, datum, context);
|
|
line.setProperties({
|
|
...linePoints,
|
|
lineCap: datum.getLineCap(),
|
|
lineDash: datum.getLineDash(),
|
|
lineDashOffset,
|
|
stroke: stroke3,
|
|
strokeWidth,
|
|
strokeOpacity,
|
|
fillOpacity: 0
|
|
});
|
|
}
|
|
updateText(datum, coords) {
|
|
this.text = this.updateNode(CollidableText, this.text, !!datum.text.label);
|
|
updateLineText(this.line.id, this.line, coords, datum.text, this.text, datum.text.label, datum.strokeWidth);
|
|
}
|
|
updateCaps(datum, coords) {
|
|
if (!datum.startCap && this.startCap) {
|
|
this.startCap.remove();
|
|
this.startCap = void 0;
|
|
}
|
|
if (!datum.endCap && this.endCap) {
|
|
this.endCap.remove();
|
|
this.endCap = void 0;
|
|
}
|
|
if (!datum.startCap && !datum.endCap)
|
|
return;
|
|
const { stroke: stroke3, strokeWidth, strokeOpacity } = datum;
|
|
const [start, end] = Vec215.from(coords);
|
|
const angle = Vec215.angle(Vec215.sub(end, start));
|
|
if (datum.startCap) {
|
|
if (this.startCap && this.startCap.type !== datum.startCap) {
|
|
this.startCap.remove();
|
|
this.startCap = void 0;
|
|
}
|
|
if (this.startCap == null) {
|
|
this.startCap = new ArrowCapScene();
|
|
this.append([this.startCap]);
|
|
}
|
|
this.startCap.update({
|
|
x: start.x,
|
|
y: start.y,
|
|
angle: angle - Math.PI,
|
|
stroke: stroke3,
|
|
strokeWidth,
|
|
strokeOpacity
|
|
});
|
|
}
|
|
if (datum.endCap) {
|
|
if (this.endCap && this.endCap.type !== datum.endCap) {
|
|
this.endCap.remove();
|
|
this.endCap = void 0;
|
|
}
|
|
if (this.endCap == null) {
|
|
this.endCap = new ArrowCapScene();
|
|
this.append([this.endCap]);
|
|
}
|
|
this.endCap.update({
|
|
x: end.x,
|
|
y: end.y,
|
|
angle,
|
|
stroke: stroke3,
|
|
strokeWidth,
|
|
strokeOpacity
|
|
});
|
|
}
|
|
}
|
|
updateAnchor(_datum, coords, _context, _bbox) {
|
|
const point = Vec410.topCenter(coords);
|
|
Vec215.apply(this.anchor, Transformable2.toCanvasPoint(this.line, point.x, point.y));
|
|
}
|
|
containsPoint(x, y) {
|
|
const { line, text: text2 } = this;
|
|
return super.containsPoint(x, y) || line.isPointInPath(x, y) || Boolean(text2?.containsPoint(x, y));
|
|
}
|
|
getNodeAtCoords(x, y) {
|
|
if (this.text?.containsPoint(x, y))
|
|
return "text";
|
|
if (this.line.isPointInPath(x, y))
|
|
return "line";
|
|
return super.getNodeAtCoords(x, y);
|
|
}
|
|
getHandleCoords(_datum, coords, handle3, _bbox) {
|
|
const { startCap, endCap } = this;
|
|
let [startPoint, endPoint] = Vec215.from(coords);
|
|
const angle = Vec215.angle(Vec215.sub(endPoint, startPoint));
|
|
if (startCap) {
|
|
startPoint = Vec215.rotate(Vec215.from(0, -DivariantHandle.HANDLE_SIZE / 2), angle, startPoint);
|
|
}
|
|
if (endCap) {
|
|
endPoint = Vec215.rotate(Vec215.from(0, DivariantHandle.HANDLE_SIZE / 2), angle, endPoint);
|
|
}
|
|
return handle3 === "start" ? startPoint : endPoint;
|
|
}
|
|
getHandleStyles(datum) {
|
|
return {
|
|
fill: datum.handle.fill,
|
|
stroke: datum.handle.stroke ?? datum.stroke,
|
|
strokeOpacity: datum.handle.strokeOpacity ?? datum.strokeOpacity,
|
|
strokeWidth: datum.handle.strokeWidth ?? datum.strokeWidth
|
|
};
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/line/lineConfig.ts
|
|
var lineConfig = {
|
|
type: "line" /* Line */,
|
|
datum: LineProperties,
|
|
scene: LineScene,
|
|
isDatum: LineProperties.is,
|
|
translate: (node, datum, transition, context) => {
|
|
if (LineProperties.is(datum) && LineScene.is(node))
|
|
node.translate(datum, transition, context);
|
|
},
|
|
copy: (node, datum, copiedDatum, context) => {
|
|
if (LineProperties.is(datum) && LineProperties.is(copiedDatum) && LineScene.is(node)) {
|
|
return node.copy(datum, copiedDatum, context);
|
|
}
|
|
},
|
|
update: (node, datum, context) => {
|
|
if (LineProperties.is(datum) && LineScene.is(node)) {
|
|
node.update(datum, context);
|
|
}
|
|
},
|
|
createState: (ctx, { createDatum }) => new LineStateMachine({
|
|
...ctx,
|
|
create: createDatum("line" /* Line */)
|
|
}),
|
|
dragState: (ctx) => new DragStateMachine(ctx)
|
|
};
|
|
var arrowConfig = {
|
|
type: "arrow" /* Arrow */,
|
|
datum: ArrowProperties,
|
|
scene: LineScene,
|
|
isDatum: ArrowProperties.is,
|
|
translate: (node, datum, transition, context) => {
|
|
if (ArrowProperties.is(datum) && LineScene.is(node))
|
|
node.translate(datum, transition, context);
|
|
},
|
|
copy: (node, datum, copiedDatum, context) => {
|
|
if (ArrowProperties.is(datum) && ArrowProperties.is(copiedDatum) && LineScene.is(node)) {
|
|
return node.copy(datum, copiedDatum, context);
|
|
}
|
|
},
|
|
update: (node, datum, context) => {
|
|
if (ArrowProperties.is(datum) && LineScene.is(node)) {
|
|
node.update(datum, context);
|
|
}
|
|
},
|
|
createState: (ctx, { createDatum }) => new ArrowStateMachine({
|
|
...ctx,
|
|
create: createDatum("arrow" /* Arrow */)
|
|
}),
|
|
dragState: (ctx) => new DragStateMachine(ctx)
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/measurer/measurerScene.ts
|
|
import { _ModuleSupport as _ModuleSupport57 } from "ag-charts-community";
|
|
import { Vec2 as Vec216, Vec4 as Vec412, isDate as isDate2, isNumber as isNumber3 } from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/measurer/measurerStatisticsScene.ts
|
|
import { _ModuleSupport as _ModuleSupport56 } from "ag-charts-community";
|
|
import { Vec4 as Vec411 } from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/utils/layout.ts
|
|
import { _ModuleSupport as _ModuleSupport55 } from "ag-charts-community";
|
|
function layoutScenesRow(scenes, startX = 0, gap = 0) {
|
|
let x = startX;
|
|
for (const scene of scenes) {
|
|
if (Array.isArray(scene)) {
|
|
for (const scene_ of scene) {
|
|
layoutSetX(scene_, x);
|
|
}
|
|
x += _ModuleSupport55.Group.computeChildrenBBox(scene).width + gap;
|
|
} else {
|
|
layoutSetX(scene, x);
|
|
x += scene.getBBox().width + gap;
|
|
}
|
|
}
|
|
}
|
|
function layoutScenesColumn(scenes, startY = 0, gap = 0) {
|
|
let y = startY;
|
|
for (const scene of scenes) {
|
|
if (Array.isArray(scene)) {
|
|
for (const scene_ of scene) {
|
|
layoutSetY(scene_, y);
|
|
}
|
|
y += _ModuleSupport55.Group.computeChildrenBBox(scene).height + gap;
|
|
} else {
|
|
layoutSetY(scene, y);
|
|
y += scene.getBBox().height + gap;
|
|
}
|
|
}
|
|
}
|
|
function layoutSetX(scene, x) {
|
|
if ("x1" in scene) {
|
|
scene.x2 = x + (scene.x2 - scene.x1);
|
|
scene.x1 = x;
|
|
} else {
|
|
scene.x = x;
|
|
}
|
|
}
|
|
function layoutSetY(scene, y) {
|
|
if ("y1" in scene) {
|
|
scene.y2 = y + (scene.y2 - scene.y1);
|
|
scene.y1 = y;
|
|
} else {
|
|
scene.y = y;
|
|
}
|
|
}
|
|
function layoutAddX(scene, x) {
|
|
if ("x1" in scene) {
|
|
scene.x1 += x;
|
|
scene.x2 += x;
|
|
} else {
|
|
scene.x += x;
|
|
}
|
|
}
|
|
function layoutAddY(scene, y) {
|
|
if ("y1" in scene) {
|
|
scene.y1 += y;
|
|
scene.y2 += y;
|
|
} else {
|
|
scene.y += y;
|
|
}
|
|
}
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/measurer/measurerStatisticsScene.ts
|
|
var MeasurerStatisticsScene = class extends _ModuleSupport56.Group {
|
|
constructor() {
|
|
super();
|
|
this.name = "MeasurerStatisticsScene";
|
|
this.background = new _ModuleSupport56.Rect();
|
|
this.dateRangeBarsText = new _ModuleSupport56.Text();
|
|
this.dateRangeDivider = new _ModuleSupport56.Line();
|
|
this.dateRangeValueText = new _ModuleSupport56.Text();
|
|
this.priceRangeValueText = new _ModuleSupport56.Text();
|
|
this.priceRangeDivider = new _ModuleSupport56.Line();
|
|
this.priceRangePercentageText = new _ModuleSupport56.Text();
|
|
this.volumeText = new _ModuleSupport56.Text();
|
|
this.volumeFormatter = new Intl.NumberFormat("en-US", {
|
|
notation: "compact",
|
|
minimumFractionDigits: 2,
|
|
maximumFractionDigits: 2
|
|
});
|
|
this.append([
|
|
this.background,
|
|
this.dateRangeBarsText,
|
|
this.dateRangeDivider,
|
|
this.dateRangeValueText,
|
|
this.priceRangeValueText,
|
|
this.priceRangeDivider,
|
|
this.priceRangePercentageText,
|
|
this.volumeText
|
|
]);
|
|
}
|
|
update(datum, stats, anchor, coords, context, verticalDirection, localeManager) {
|
|
this.verticalDirection = verticalDirection;
|
|
const scenes = this.updateStatistics(datum, stats, anchor, localeManager);
|
|
const bbox = _ModuleSupport56.Group.computeChildrenBBox(scenes.flat());
|
|
const padding2 = 10;
|
|
bbox.grow(padding2);
|
|
this.updateBackground(datum, bbox, padding2);
|
|
this.reposition(scenes, padding2, context);
|
|
this.checkVisibility(datum, context, coords);
|
|
}
|
|
checkVisibility(datum, context, coords) {
|
|
const bounds = Vec411.from(context.seriesRect);
|
|
this.visible = Vec411.collides(coords, bounds) && (datum.visible ?? true);
|
|
}
|
|
updateStatistics(datum, stats, anchor, localeManager) {
|
|
const {
|
|
dateRangeBarsText,
|
|
dateRangeDivider,
|
|
dateRangeValueText,
|
|
priceRangeValueText,
|
|
priceRangeDivider,
|
|
priceRangePercentageText,
|
|
volumeText
|
|
} = this;
|
|
const horizontalGap = 8;
|
|
const verticalGap = 6;
|
|
const dividerLineHeight = datum.statistics.fontSize + 3;
|
|
const dividerLineOffset = -2;
|
|
const textStyles = this.getTextStyles(datum);
|
|
const dividerLineStyles = {
|
|
...this.getDividerStyles(datum),
|
|
x1: 0,
|
|
y1: 0,
|
|
x2: 0,
|
|
y2: dividerLineHeight
|
|
};
|
|
const dateScenes = [dateRangeBarsText, dateRangeDivider, dateRangeValueText];
|
|
const priceScenes = [priceRangeValueText, priceRangeDivider, priceRangePercentageText];
|
|
const scenes = [];
|
|
if (stats.priceRange) {
|
|
priceRangeValueText.setProperties({
|
|
...textStyles,
|
|
text: this.formatPriceRangeValue(stats.priceRange.value, localeManager)
|
|
});
|
|
priceRangeDivider.setProperties(dividerLineStyles);
|
|
priceRangePercentageText.setProperties({
|
|
...textStyles,
|
|
text: this.formatPriceRangePercentage(stats.priceRange.percentage, localeManager)
|
|
});
|
|
layoutScenesRow(priceScenes, anchor.x, horizontalGap);
|
|
scenes.push(priceScenes);
|
|
}
|
|
if (stats.dateRange) {
|
|
dateRangeBarsText.setProperties({
|
|
...textStyles,
|
|
text: this.formatDateRangeBars(stats.dateRange.bars, localeManager)
|
|
});
|
|
dateRangeDivider.setProperties(dividerLineStyles);
|
|
dateRangeValueText.setProperties({
|
|
...textStyles,
|
|
text: this.formatDateRangeValue(stats.dateRange.value)
|
|
});
|
|
layoutScenesRow(dateScenes, anchor.x, horizontalGap);
|
|
scenes.push(dateScenes);
|
|
}
|
|
if (stats.volume == null) {
|
|
volumeText.visible = false;
|
|
} else {
|
|
volumeText.setProperties({
|
|
...textStyles,
|
|
x: anchor.x,
|
|
text: this.formatVolume(stats.volume, localeManager),
|
|
visible: true
|
|
});
|
|
scenes.push(volumeText);
|
|
}
|
|
layoutScenesColumn(scenes, anchor.y, verticalGap);
|
|
priceRangeDivider.y1 += dividerLineOffset;
|
|
priceRangeDivider.y2 += dividerLineOffset;
|
|
dateRangeDivider.y1 += dividerLineOffset;
|
|
dateRangeDivider.y2 += dividerLineOffset;
|
|
return scenes;
|
|
}
|
|
updateBackground(datum, bbox, padding2) {
|
|
const styles = this.getBackgroundStyles(datum);
|
|
this.background.setProperties({
|
|
...styles,
|
|
...bbox,
|
|
x: bbox.x - bbox.width / 2 + padding2,
|
|
y: bbox.y
|
|
});
|
|
}
|
|
reposition(scenes, padding2, context) {
|
|
const { width, height } = context.seriesRect;
|
|
const background = Vec411.from(this.background.getBBox());
|
|
let offsetX = 0;
|
|
if (background.x1 < 0)
|
|
offsetX = -background.x1;
|
|
if (background.x2 > width)
|
|
offsetX = width - background.x2;
|
|
const offsetY = Math.min(padding2, height - background.y2);
|
|
for (const scene of scenes) {
|
|
if (Array.isArray(scene)) {
|
|
const rowWidth = _ModuleSupport56.Group.computeChildrenBBox(scene).width;
|
|
for (const scene_ of scene) {
|
|
layoutAddX(scene_, offsetX - rowWidth / 2);
|
|
layoutAddY(scene_, offsetY);
|
|
}
|
|
} else {
|
|
layoutAddX(scene, offsetX - scene.getBBox().width / 2);
|
|
layoutAddY(scene, offsetY);
|
|
}
|
|
}
|
|
this.background.x += offsetX;
|
|
this.background.y += offsetY;
|
|
}
|
|
getTextStyles(datum) {
|
|
return {
|
|
fill: datum.statistics.color,
|
|
fontFamily: datum.statistics.fontFamily,
|
|
fontSize: datum.statistics.fontSize,
|
|
fontStyle: datum.statistics.fontStyle,
|
|
fontWeight: datum.statistics.fontWeight,
|
|
textBaseline: "top"
|
|
};
|
|
}
|
|
getDividerStyles(datum) {
|
|
return {
|
|
stroke: datum.statistics.divider.stroke,
|
|
strokeOpacity: datum.statistics.divider.strokeOpacity,
|
|
strokeWidth: datum.statistics.divider.strokeWidth
|
|
};
|
|
}
|
|
getBackgroundStyles(datum) {
|
|
return {
|
|
fill: datum.statistics.fill,
|
|
stroke: datum.statistics.stroke,
|
|
strokeOpacity: datum.statistics.strokeOpacity,
|
|
strokeWidth: datum.statistics.strokeWidth,
|
|
cornerRadius: 4
|
|
};
|
|
}
|
|
formatDateRangeBars(bars, localeManager) {
|
|
return localeManager?.t("measurerDateRangeBars", { value: bars }) ?? `${bars}`;
|
|
}
|
|
formatDateRangeValue(time) {
|
|
const range2 = [];
|
|
const sign = time >= 0 ? "" : "-";
|
|
time = Math.abs(time);
|
|
const MINUTE = 1e3 * 60;
|
|
const HOUR = MINUTE * 60;
|
|
const DAY2 = HOUR * 24;
|
|
const minutes = Math.floor(time / MINUTE);
|
|
const hours = Math.floor(time / HOUR);
|
|
const days = Math.floor(time / DAY2);
|
|
const remainderHours = hours % (DAY2 / HOUR);
|
|
const remainderMinutes = minutes % (HOUR / MINUTE);
|
|
if (days >= 1)
|
|
range2.push(`${days}d`);
|
|
if (hours >= 1 && (time < DAY2 || remainderHours !== 0))
|
|
range2.push(`${remainderHours}h`);
|
|
if (time < HOUR || remainderMinutes !== 0)
|
|
range2.push(`${remainderMinutes}m`);
|
|
range2[0] = `${sign}${range2[0]}`;
|
|
return range2.join(" ");
|
|
}
|
|
formatPriceRangeValue(value, localeManager) {
|
|
return localeManager?.t("measurerPriceRangeValue", { value: Number(value.toFixed(2)) }) ?? `${value}`;
|
|
}
|
|
formatPriceRangePercentage(percentage, localeManager) {
|
|
return localeManager?.t("measurerPriceRangePercent", { value: percentage }) ?? `${percentage}`;
|
|
}
|
|
formatVolume(volume, localeManager) {
|
|
const volumeString = Number.isNaN(volume) ? "" : this.volumeFormatter.format(volume);
|
|
return localeManager?.t("measurerVolume", { value: volumeString }) ?? volumeString;
|
|
}
|
|
};
|
|
var QuickMeasurerStatisticsScene = class extends MeasurerStatisticsScene {
|
|
getDirectionStyles(datum) {
|
|
return this.verticalDirection === "down" ? datum.down.statistics : datum.up.statistics;
|
|
}
|
|
getTextStyles(datum) {
|
|
const styles = this.getDirectionStyles(datum);
|
|
return {
|
|
...super.getTextStyles(datum),
|
|
fill: styles.color,
|
|
fontFamily: styles.fontFamily,
|
|
fontSize: styles.fontSize,
|
|
fontStyle: styles.fontStyle,
|
|
fontWeight: styles.fontWeight
|
|
};
|
|
}
|
|
getDividerStyles(datum) {
|
|
const styles = this.getDirectionStyles(datum);
|
|
return {
|
|
stroke: styles.divider.stroke,
|
|
strokeOpacity: styles.divider.strokeOpacity,
|
|
strokeWidth: styles.divider.strokeWidth
|
|
};
|
|
}
|
|
getBackgroundStyles(datum) {
|
|
const styles = this.getDirectionStyles(datum);
|
|
return {
|
|
...super.getBackgroundStyles(datum),
|
|
fill: styles.fill,
|
|
stroke: styles.stroke,
|
|
strokeOpacity: styles.strokeOpacity,
|
|
strokeWidth: styles.strokeWidth
|
|
};
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/measurer/measurerScene.ts
|
|
var MeasurerScene = class extends StartEndScene {
|
|
constructor() {
|
|
super();
|
|
this.type = "measurer";
|
|
this.horizontalLine = new CollidableLine();
|
|
this.verticalLine = new CollidableLine();
|
|
// These four bounding lines are named after the way they are drawn, e.g. the horizontalStartLine is a horizontal
|
|
// line that is only shown when the measurer has the 'vertical' direction.
|
|
this.horizontalStartLine = new CollidableLine();
|
|
this.horizontalEndLine = new CollidableLine();
|
|
this.verticalStartLine = new CollidableLine();
|
|
this.verticalEndLine = new CollidableLine();
|
|
this.horizontalEndCap = new ArrowCapScene();
|
|
this.verticalEndCap = new ArrowCapScene();
|
|
this.background = new _ModuleSupport57.Path({ zIndex: -1 });
|
|
this.updateBackground = WithBackgroundScene.updateBackground.bind(this);
|
|
this.statistics = this.createStatisticsScene();
|
|
this.statistics.zIndex = 1;
|
|
this.append([
|
|
this.background,
|
|
this.verticalStartLine,
|
|
this.verticalEndLine,
|
|
this.horizontalStartLine,
|
|
this.horizontalEndLine,
|
|
this.horizontalLine,
|
|
this.verticalLine,
|
|
this.horizontalEndCap,
|
|
this.verticalEndCap,
|
|
this.start,
|
|
this.end,
|
|
this.statistics
|
|
]);
|
|
}
|
|
static is(value) {
|
|
return AnnotationScene.isCheck(value, "measurer");
|
|
}
|
|
createStatisticsScene() {
|
|
return new MeasurerStatisticsScene();
|
|
}
|
|
update(datum, context) {
|
|
const coords = convertLine(datum, context);
|
|
if (coords == null) {
|
|
this.visible = false;
|
|
return;
|
|
}
|
|
this.visible = datum.visible ?? true;
|
|
if (!this.visible)
|
|
return;
|
|
const extended = this.extendPerpendicular(coords, datum, context);
|
|
const verticalStart = { ...extended, y2: extended.y1 };
|
|
const verticalEnd = { ...extended, y1: extended.y2 };
|
|
this.verticalDirection = coords.y1 < coords.y2 ? "down" : "up";
|
|
this.updateVisibilities(datum);
|
|
this.updateLines(datum, coords);
|
|
this.updateHandles(datum, coords);
|
|
this.updateText(datum, coords);
|
|
this.updateCaps(datum, coords);
|
|
this.updateBoundingLines(datum, extended);
|
|
this.updateBackground(datum, verticalStart, verticalEnd, context);
|
|
this.updateStatistics(datum, coords, context);
|
|
this.updateAnchor(datum, coords, context);
|
|
}
|
|
extendPerpendicular(coords, datum, context) {
|
|
const extended = {
|
|
x1: Math.min(coords.x1, coords.x2),
|
|
x2: Math.max(coords.x1, coords.x2),
|
|
y1: Math.min(coords.y1, coords.y2),
|
|
y2: Math.max(coords.y1, coords.y2)
|
|
};
|
|
const [start, end] = Vec216.from(context.yAxis.bounds);
|
|
if (DateRangeProperties.is(datum)) {
|
|
if (datum.extendAbove)
|
|
extended.y1 = start.y;
|
|
if (datum.extendBelow)
|
|
extended.y2 = end.y;
|
|
} else if (PriceRangeProperties.is(datum)) {
|
|
if (datum.extendLeft)
|
|
extended.x1 = start.x;
|
|
if (datum.extendRight)
|
|
extended.x2 = end.x;
|
|
}
|
|
return extended;
|
|
}
|
|
updateVisibilities(datum) {
|
|
const {
|
|
horizontalStartLine,
|
|
horizontalEndLine,
|
|
horizontalEndCap,
|
|
verticalStartLine,
|
|
verticalEndLine,
|
|
verticalEndCap
|
|
} = this;
|
|
const { direction } = datum;
|
|
verticalStartLine.visible = direction !== "vertical";
|
|
verticalEndLine.visible = direction !== "vertical";
|
|
horizontalEndCap.visible = direction !== "vertical";
|
|
horizontalStartLine.visible = direction !== "horizontal";
|
|
horizontalEndLine.visible = direction !== "horizontal";
|
|
verticalEndCap.visible = direction !== "horizontal";
|
|
}
|
|
updateLines(datum, coords) {
|
|
const { horizontalLine, verticalLine } = this;
|
|
const { direction } = datum;
|
|
const { x1, y1, x2, y2 } = coords;
|
|
const center = Vec216.round(Vec412.center(coords), 0);
|
|
const lineStyles = this.getLineStyles(datum);
|
|
if (direction !== "vertical") {
|
|
horizontalLine.setProperties({
|
|
...lineStyles,
|
|
x1,
|
|
x2,
|
|
y1: center.y,
|
|
y2: center.y
|
|
});
|
|
}
|
|
if (direction !== "horizontal") {
|
|
verticalLine.setProperties({
|
|
...lineStyles,
|
|
x1: center.x,
|
|
x2: center.x,
|
|
y1,
|
|
y2
|
|
});
|
|
}
|
|
}
|
|
updateText(datum, coords) {
|
|
const { direction } = datum;
|
|
const center = Vec216.round(Vec412.center(coords), 0);
|
|
let line;
|
|
const textCoords = { ...coords };
|
|
if (direction === "vertical") {
|
|
line = this.verticalLine;
|
|
textCoords.x1 = center.x;
|
|
textCoords.x2 = center.x;
|
|
} else {
|
|
line = this.horizontalLine;
|
|
textCoords.y1 = center.y;
|
|
textCoords.y2 = center.y;
|
|
}
|
|
this.text = this.updateNode(CollidableText, this.text, !!datum.text.label);
|
|
const { id } = line;
|
|
const clip = updateLineText(id, line, textCoords, datum.text, this.text, datum.text.label, datum.strokeWidth);
|
|
let verticalClipMask;
|
|
if (direction === "both" && clip && this.text) {
|
|
const textBBox = Vec412.from(this.text.getBBox());
|
|
const { offset } = clip.numbers;
|
|
const crossesVerticalLine = textBBox.x1 <= center.x + offset.x && textBBox.x2 >= center.x - offset.x;
|
|
if (crossesVerticalLine) {
|
|
verticalClipMask = {
|
|
x: center.x,
|
|
y: clip.clipMask.y,
|
|
radius: this.text.getBBox().height / 2 + Vec216.length(offset)
|
|
};
|
|
}
|
|
}
|
|
this.verticalLine.setClipMask(id, verticalClipMask);
|
|
}
|
|
updateCaps(datum, coords) {
|
|
const { horizontalEndCap, verticalEndCap } = this;
|
|
const { direction } = datum;
|
|
const { x1, y1, x2, y2 } = coords;
|
|
const center = Vec216.round(Vec412.center(coords), 0);
|
|
const { stroke: stroke3, strokeWidth, strokeOpacity } = this.getLineStyles(datum);
|
|
const capStyles = { stroke: stroke3, strokeWidth, strokeOpacity };
|
|
if (direction !== "vertical") {
|
|
const angle = x1 <= x2 ? 0 : Math.PI;
|
|
let x = x2;
|
|
if (direction === "horizontal") {
|
|
x += x1 <= x2 ? -2 : 2;
|
|
}
|
|
horizontalEndCap.update({ ...capStyles, x, y: center.y, angle });
|
|
}
|
|
if (direction !== "horizontal") {
|
|
const angle = y1 <= y2 ? Math.PI / 2 : Math.PI / -2;
|
|
let y = y2;
|
|
if (direction === "vertical") {
|
|
y += y1 <= y2 ? -2 : 2;
|
|
}
|
|
verticalEndCap.update({ ...capStyles, x: center.x, y, angle });
|
|
}
|
|
}
|
|
updateBoundingLines(datum, extendedCoords) {
|
|
const { verticalStartLine, verticalEndLine, horizontalStartLine, horizontalEndLine } = this;
|
|
const { direction } = datum;
|
|
const { x1, y1, x2, y2 } = extendedCoords;
|
|
const lineStyles = this.getLineStyles(datum);
|
|
if (direction === "horizontal") {
|
|
verticalStartLine.setProperties({ ...lineStyles, x1, y1, x2: x1, y2 });
|
|
verticalEndLine.setProperties({ ...lineStyles, x1: x2, y1, x2, y2 });
|
|
}
|
|
if (direction === "vertical") {
|
|
horizontalStartLine.setProperties({ ...lineStyles, x1, y1, x2, y2: y1 });
|
|
horizontalEndLine.setProperties({ ...lineStyles, x1, y1: y2, x2, y2 });
|
|
}
|
|
}
|
|
updateStatistics(datum, coords, context) {
|
|
const point = Vec216.add(Vec412.bottomCenter(coords), Vec216.from(0, 10));
|
|
const statistics = { volume: this.getVolume(datum) };
|
|
if (datum.hasPriceRange) {
|
|
statistics.priceRange = {
|
|
percentage: this.getPriceRangePercentage(datum),
|
|
value: this.getPriceRangeValue(datum)
|
|
};
|
|
}
|
|
if (datum.hasDateRange) {
|
|
statistics.dateRange = {
|
|
bars: this.getDateRangeBars(coords, context),
|
|
value: this.getDateRangeValue(datum)
|
|
};
|
|
}
|
|
this.statistics.update(datum, statistics, point, coords, context, this.verticalDirection, datum.localeManager);
|
|
}
|
|
updateAnchor(_datum, coords, _context, _bbox) {
|
|
const point = Vec412.topCenter(coords);
|
|
Vec216.apply(this.anchor, _ModuleSupport57.Transformable.toCanvasPoint(this.horizontalLine, point.x, point.y));
|
|
}
|
|
getBackgroundPoints(_datum, verticalStart, verticalEnd, _bounds) {
|
|
const [startStart, startEnd] = Vec216.from(verticalStart);
|
|
const [endStart, endEnd] = Vec216.from(verticalEnd);
|
|
return [startStart, startEnd, endEnd, endStart];
|
|
}
|
|
getLineStyles(datum) {
|
|
const { lineDashOffset, stroke: stroke3, strokeWidth, strokeOpacity } = datum;
|
|
return {
|
|
lineCap: datum.getLineCap(),
|
|
lineDash: datum.getLineDash(),
|
|
lineDashOffset,
|
|
stroke: stroke3,
|
|
strokeWidth,
|
|
strokeOpacity,
|
|
fillOpacity: 0
|
|
};
|
|
}
|
|
getBackgroundStyles(datum) {
|
|
const { background } = datum;
|
|
return {
|
|
fill: background.fill,
|
|
fillOpacity: background.fillOpacity
|
|
};
|
|
}
|
|
getHandleStyles(datum) {
|
|
return {
|
|
fill: datum.handle.fill,
|
|
stroke: datum.handle.stroke ?? datum.stroke,
|
|
strokeOpacity: datum.handle.strokeOpacity ?? datum.strokeOpacity,
|
|
strokeWidth: datum.handle.strokeWidth ?? datum.strokeWidth
|
|
};
|
|
}
|
|
containsPoint(x, y) {
|
|
const {
|
|
horizontalLine,
|
|
text: text2,
|
|
verticalLine,
|
|
horizontalStartLine,
|
|
horizontalEndLine,
|
|
verticalStartLine,
|
|
verticalEndLine
|
|
} = this;
|
|
return super.containsPoint(x, y) || horizontalLine.isPointInPath(x, y) || verticalLine.isPointInPath(x, y) || horizontalStartLine.visible && horizontalStartLine.isPointInPath(x, y) || horizontalEndLine.visible && horizontalEndLine.isPointInPath(x, y) || verticalStartLine.visible && verticalStartLine.isPointInPath(x, y) || verticalEndLine.visible && verticalEndLine.isPointInPath(x, y) || Boolean(text2?.containsPoint(x, y));
|
|
}
|
|
getNodeAtCoords(x, y) {
|
|
if (this.text?.containsPoint(x, y))
|
|
return "text";
|
|
if (this.start.containsPoint(x, y) || this.end.containsPoint(x, y))
|
|
return "handle";
|
|
return "line";
|
|
}
|
|
getDateRangeBars(coords, context) {
|
|
const { step } = context.xAxis.scale;
|
|
const sign = coords.x1 <= coords.x2 ? 1 : -1;
|
|
return step ? Math.round(Vec412.width(coords) / step) * sign : 0;
|
|
}
|
|
getDateRangeValue(datum) {
|
|
const start = getGroupingValue(datum.start.x);
|
|
const end = getGroupingValue(datum.end.x);
|
|
if (!isDate2(start) || !isDate2(end)) {
|
|
throw new Error("Can not create a date range measurement of non-date x-axis.");
|
|
}
|
|
return end.getTime() - start.getTime();
|
|
}
|
|
getPriceRangePercentage(datum) {
|
|
if (datum.start.y == null || datum.end.y == null) {
|
|
throw new Error("Can not create a price range measurement of a non-numeric y-axis");
|
|
}
|
|
const endY = getGroupingValue(datum.end.y);
|
|
const startY = getGroupingValue(datum.start.y);
|
|
if (!isNumber3(endY) || !isNumber3(startY)) {
|
|
throw new Error("Can not create a price range measurement of a non-numeric y-axis");
|
|
}
|
|
return (endY - startY) / startY;
|
|
}
|
|
getPriceRangeValue(datum) {
|
|
if (datum.start.y == null || datum.end.y == null) {
|
|
throw new Error("Can not create a price range measurement of a non-numeric y-axis");
|
|
}
|
|
const endY = getGroupingValue(datum.end.y);
|
|
const startY = getGroupingValue(datum.start.y);
|
|
if (!isNumber3(endY) || !isNumber3(startY)) {
|
|
throw new Error("Can not create a price range measurement of a non-numeric y-axis");
|
|
}
|
|
return endY - startY;
|
|
}
|
|
getVolume(datum) {
|
|
return datum.getVolume(datum.start.x, datum.end.x);
|
|
}
|
|
};
|
|
var QuickMeasurerScene = class extends MeasurerScene {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.type = "quick-measurer";
|
|
}
|
|
static is(value) {
|
|
return AnnotationScene.isCheck(value, "quick-measurer");
|
|
}
|
|
createStatisticsScene() {
|
|
return new QuickMeasurerStatisticsScene();
|
|
}
|
|
getDirectionStyles(datum) {
|
|
return this.verticalDirection === "down" ? datum.down : datum.up;
|
|
}
|
|
getLineStyles(datum) {
|
|
const styles = this.getDirectionStyles(datum);
|
|
return {
|
|
...super.getLineStyles(datum),
|
|
stroke: styles.stroke,
|
|
strokeWidth: styles.strokeWidth,
|
|
strokeOpacity: styles.strokeOpacity
|
|
};
|
|
}
|
|
getBackgroundStyles(datum) {
|
|
const styles = this.getDirectionStyles(datum);
|
|
return {
|
|
fill: styles.fill,
|
|
fillOpacity: styles.fillOpacity
|
|
};
|
|
}
|
|
getHandleStyles(datum) {
|
|
const styles = this.getDirectionStyles(datum);
|
|
return {
|
|
fill: styles.handle.fill,
|
|
stroke: styles.handle.stroke ?? styles.stroke,
|
|
strokeOpacity: styles.handle.strokeOpacity ?? styles.strokeOpacity,
|
|
strokeWidth: styles.handle.strokeWidth ?? styles.strokeWidth
|
|
};
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/measurer/measurerState.ts
|
|
import { Debug as Debug9, StateMachine as StateMachine9, StateMachineProperty as StateMachineProperty9 } from "ag-charts-core";
|
|
var MeasurerTypeStateMachine = class extends StateMachine9 {
|
|
constructor(ctx) {
|
|
const actionCreate = ({ point }) => {
|
|
const datum = this.createDatum();
|
|
datum.set({ start: point, end: point });
|
|
ctx.create(datum);
|
|
};
|
|
const actionEndUpdate = ({ point }) => {
|
|
const { datum, node } = this;
|
|
datum?.set({ end: point });
|
|
node?.toggleActive(true);
|
|
node?.toggleHandles({ end: false });
|
|
ctx.update();
|
|
};
|
|
const actionEndFinish = () => {
|
|
this.node?.toggleHandles({ end: true });
|
|
};
|
|
const actionCancel = () => ctx.delete();
|
|
const onExitEnd = () => {
|
|
ctx.showAnnotationOptions();
|
|
ctx.recordAction(`Create ${this.node?.type} annotation`);
|
|
};
|
|
super("start", {
|
|
start: {
|
|
reset: StateMachine9.parent,
|
|
click: {
|
|
target: "end",
|
|
action: actionCreate
|
|
},
|
|
drag: {
|
|
target: "end",
|
|
action: actionCreate
|
|
}
|
|
},
|
|
end: {
|
|
hover: actionEndUpdate,
|
|
drag: actionEndUpdate,
|
|
click: {
|
|
target: StateMachine9.parent,
|
|
action: actionEndFinish
|
|
},
|
|
dragEnd: {
|
|
target: StateMachine9.parent,
|
|
action: actionEndFinish
|
|
},
|
|
reset: {
|
|
target: StateMachine9.parent,
|
|
action: actionCancel
|
|
},
|
|
cancel: {
|
|
target: StateMachine9.parent,
|
|
action: actionCancel
|
|
},
|
|
onExit: onExitEnd
|
|
}
|
|
});
|
|
this.debug = Debug9.create(true, "annotations");
|
|
}
|
|
};
|
|
__decorateClass([
|
|
StateMachineProperty9()
|
|
], MeasurerTypeStateMachine.prototype, "datum", 2);
|
|
__decorateClass([
|
|
StateMachineProperty9()
|
|
], MeasurerTypeStateMachine.prototype, "node", 2);
|
|
var DateRangeStateMachine = class extends MeasurerTypeStateMachine {
|
|
createDatum() {
|
|
return new DateRangeProperties();
|
|
}
|
|
};
|
|
var PriceRangeStateMachine = class extends MeasurerTypeStateMachine {
|
|
createDatum() {
|
|
return new PriceRangeProperties();
|
|
}
|
|
};
|
|
var DatePriceRangeStateMachine = class extends MeasurerTypeStateMachine {
|
|
createDatum() {
|
|
return new DatePriceRangeProperties();
|
|
}
|
|
};
|
|
var QuickDatePriceRangeStateMachine = class extends MeasurerTypeStateMachine {
|
|
createDatum() {
|
|
return new QuickDatePriceRangeProperties();
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/measurer/measurerConfig.ts
|
|
var dateRangeConfig = {
|
|
type: "date-range" /* DateRange */,
|
|
datum: DateRangeProperties,
|
|
scene: MeasurerScene,
|
|
isDatum: DateRangeProperties.is,
|
|
translate: (node, datum, translation, context) => {
|
|
if (DateRangeProperties.is(datum) && MeasurerScene.is(node)) {
|
|
node.translate(datum, translation, context);
|
|
}
|
|
},
|
|
copy: (node, datum, copiedDatum, context) => {
|
|
if (DateRangeProperties.is(datum) && DateRangeProperties.is(copiedDatum) && MeasurerScene.is(node)) {
|
|
return node.copy(datum, copiedDatum, context);
|
|
}
|
|
},
|
|
update: (node, datum, context) => {
|
|
if (DateRangeProperties.is(datum) && MeasurerScene.is(node)) {
|
|
node.update(datum, context);
|
|
}
|
|
},
|
|
createState: (ctx, { createDatum }) => new DateRangeStateMachine({
|
|
...ctx,
|
|
create: createDatum("date-range" /* DateRange */)
|
|
}),
|
|
dragState: (ctx) => new DragStateMachine(ctx)
|
|
};
|
|
var priceRangeConfig = {
|
|
type: "price-range" /* PriceRange */,
|
|
datum: PriceRangeProperties,
|
|
scene: MeasurerScene,
|
|
isDatum: PriceRangeProperties.is,
|
|
translate: (node, datum, translation, context) => {
|
|
if (PriceRangeProperties.is(datum) && MeasurerScene.is(node)) {
|
|
node.translate(datum, translation, context);
|
|
}
|
|
},
|
|
copy: (node, datum, copiedDatum, context) => {
|
|
if (PriceRangeProperties.is(datum) && PriceRangeProperties.is(copiedDatum) && MeasurerScene.is(node)) {
|
|
return node.copy(datum, copiedDatum, context);
|
|
}
|
|
},
|
|
update: (node, datum, context) => {
|
|
if (PriceRangeProperties.is(datum) && MeasurerScene.is(node)) {
|
|
node.update(datum, context);
|
|
}
|
|
},
|
|
createState: (ctx, { createDatum }) => new PriceRangeStateMachine({
|
|
...ctx,
|
|
create: createDatum("date-range" /* DateRange */)
|
|
}),
|
|
dragState: (ctx) => new DragStateMachine(ctx)
|
|
};
|
|
var datePriceRangeConfig = {
|
|
type: "date-price-range" /* DatePriceRange */,
|
|
datum: DatePriceRangeProperties,
|
|
scene: MeasurerScene,
|
|
isDatum: DatePriceRangeProperties.is,
|
|
translate: (node, datum, translation, context) => {
|
|
if (DatePriceRangeProperties.is(datum) && MeasurerScene.is(node)) {
|
|
node.translate(datum, translation, context);
|
|
}
|
|
},
|
|
copy: (node, datum, copiedDatum, context) => {
|
|
if (DatePriceRangeProperties.is(datum) && DatePriceRangeProperties.is(copiedDatum) && MeasurerScene.is(node)) {
|
|
return node.copy(datum, copiedDatum, context);
|
|
}
|
|
},
|
|
update: (node, datum, context) => {
|
|
if (DatePriceRangeProperties.is(datum) && MeasurerScene.is(node)) {
|
|
node.update(datum, context);
|
|
}
|
|
},
|
|
createState: (ctx, { createDatum }) => new DatePriceRangeStateMachine({
|
|
...ctx,
|
|
create: createDatum("date-range" /* DateRange */)
|
|
}),
|
|
dragState: (ctx) => new DragStateMachine(ctx)
|
|
};
|
|
var quickDatePriceRangeConfig = {
|
|
type: "quick-date-price-range" /* QuickDatePriceRange */,
|
|
datum: QuickDatePriceRangeProperties,
|
|
scene: QuickMeasurerScene,
|
|
isDatum: QuickDatePriceRangeProperties.is,
|
|
translate: (node, datum, translation, context) => {
|
|
if (QuickDatePriceRangeProperties.is(datum) && QuickMeasurerScene.is(node)) {
|
|
node.translate(datum, translation, context);
|
|
}
|
|
},
|
|
copy: (node, datum, copiedDatum, context) => {
|
|
if (QuickDatePriceRangeProperties.is(datum) && QuickDatePriceRangeProperties.is(copiedDatum) && QuickMeasurerScene.is(node)) {
|
|
return node.copy(datum, copiedDatum, context);
|
|
}
|
|
},
|
|
update: (node, datum, context) => {
|
|
if (QuickDatePriceRangeProperties.is(datum) && QuickMeasurerScene.is(node)) {
|
|
node.update(datum, context);
|
|
}
|
|
},
|
|
createState: (ctx, { createDatum }) => new QuickDatePriceRangeStateMachine({
|
|
...ctx,
|
|
create: createDatum("quick-date-price-range" /* QuickDatePriceRange */)
|
|
}),
|
|
dragState: (ctx) => new DragStateMachine(ctx)
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/note/noteScene.ts
|
|
import { _ModuleSupport as _ModuleSupport58 } from "ag-charts-community";
|
|
import { ZIndexMap as ZIndexMap4, calcLineHeight as calcLineHeight3, clamp as clamp4, wrapText as wrapText2 } from "ag-charts-core";
|
|
var NoteScene = class extends TextualPointScene {
|
|
constructor() {
|
|
super();
|
|
this.type = "note" /* Note */;
|
|
this.shape = new _ModuleSupport58.Rect();
|
|
this.iconBackground = new _ModuleSupport58.TranslatableSvgPath(
|
|
"M22 1.83333C22 0.820811 21.1792 0 20.1667 0H1.83333C0.820811 0 0 0.82081 0 1.83333V13.9868C0 14.9994 0.820811 15.8202 1.83333 15.8202L5.88971 15.8202C6.44575 15.8202 6.97175 16.0725 7.31971 16.5062L9.57006 19.3112C10.304 20.2259 11.6962 20.2259 12.4301 19.3112L14.6804 16.5062C15.0284 16.0725 15.5544 15.8202 16.1104 15.8202L20.1667 15.8202C21.1792 15.8202 22 14.9994 22 13.9868V1.83333Z"
|
|
);
|
|
this.iconLines = new _ModuleSupport58.TranslatableSvgPath(
|
|
"M17.1114 5.75C17.1114 6.16421 16.7756 6.5 16.3614 6.5H5.63916C5.22495 6.5 4.88916 6.16421 4.88916 5.75V5.75C4.88916 5.33579 5.22495 5 5.63916 5H16.3614C16.7756 5 17.1114 5.33579 17.1114 5.75V5.75ZM17.1114 9.25C17.1114 9.66421 16.7756 10 16.3614 10H5.63916C5.22495 10 4.88916 9.66421 4.88916 9.25V9.25C4.88916 8.83579 5.22495 8.5 5.63916 8.5H16.3614C16.7756 8.5 17.1114 8.83579 17.1114 9.25V9.25Z"
|
|
);
|
|
this.active = false;
|
|
this.shape.visible = false;
|
|
this.label.visible = false;
|
|
this.iconBackground.fillShadow = new _ModuleSupport58.DropShadow();
|
|
this.append([this.shape, this.label, this.iconBackground, this.iconLines, this.handle]);
|
|
}
|
|
static is(value) {
|
|
return AnnotationScene.isCheck(value, "note" /* Note */);
|
|
}
|
|
update(datum, context) {
|
|
this.updateIcon(datum, context);
|
|
super.update(datum, context);
|
|
}
|
|
getTextBBox(datum, coords, context) {
|
|
const bbox = super.getTextBBox(datum, coords, context);
|
|
bbox.x -= datum.width / 2;
|
|
bbox.x = clamp4(0, bbox.x, context.seriesRect.width - datum.width);
|
|
const padding2 = datum.getPadding().top;
|
|
const topY = bbox.y - LABEL_OFFSET - padding2 * 2;
|
|
const bottomY = bbox.y + DivariantHandle.HANDLE_SIZE + padding2 * 2;
|
|
if (topY - bbox.height - TOOLBAR_OFFSET < 0) {
|
|
bbox.y = bottomY;
|
|
datum.position = "top";
|
|
} else {
|
|
bbox.y = topY + padding2;
|
|
datum.position = "bottom";
|
|
}
|
|
return bbox;
|
|
}
|
|
updateLabel(datum, bbox) {
|
|
const labelVisibility = datum.visible === false ? false : this.label.visible;
|
|
super.updateLabel(datum, bbox);
|
|
this.label.visible = labelVisibility;
|
|
this.label.text = wrapText2(datum.text, {
|
|
maxWidth: 200,
|
|
font: datum,
|
|
textWrap: "always",
|
|
avoidOrphans: false
|
|
});
|
|
}
|
|
updateShape(datum, bbox) {
|
|
const { shape } = this;
|
|
shape.fill = datum.background.fill;
|
|
shape.fillOpacity = datum.background.fillOpacity ?? 1;
|
|
shape.stroke = datum.background.stroke;
|
|
shape.strokeOpacity = datum.background.strokeOpacity ?? 1;
|
|
shape.strokeWidth = datum.background.strokeWidth ?? 1;
|
|
shape.cornerRadius = 4;
|
|
const padding2 = datum.getPadding().top;
|
|
const isPositionTop = datum.position === "top";
|
|
shape.x = bbox.x - padding2;
|
|
shape.width = datum.width + padding2 * 2;
|
|
shape.height = bbox.height + padding2 * 2;
|
|
shape.y = bbox.y + (isPositionTop ? 0 : -bbox.height) - padding2;
|
|
}
|
|
updateIcon(datum, context) {
|
|
const { active, iconBackground, iconLines } = this;
|
|
const { x, y } = convertPoint(datum, context);
|
|
iconBackground.translationX = x - ICON_WIDTH / 2;
|
|
iconBackground.translationY = y - ICON_HEIGHT;
|
|
iconLines.translationX = iconBackground.translationX;
|
|
iconLines.translationY = iconBackground.translationY;
|
|
iconBackground.fill = datum.fill;
|
|
iconBackground.fillOpacity = datum.fillOpacity ?? 1;
|
|
iconBackground.stroke = datum.stroke;
|
|
iconBackground.strokeOpacity = datum.strokeOpacity ?? 1;
|
|
iconBackground.strokeWidth = datum.strokeWidth ?? 1;
|
|
iconLines.fill = datum.stroke;
|
|
if (active) {
|
|
iconBackground.fillShadow.color = datum.fill ?? "rgba(0, 0, 0, 0.22)";
|
|
} else {
|
|
iconBackground.fillShadow.color = "rgba(0, 0, 0, 0.22)";
|
|
}
|
|
}
|
|
updateAnchor(datum, bbox, context) {
|
|
const padding2 = datum.getPadding().top;
|
|
const isPositionTop = datum.position === "top";
|
|
const direction = isPositionTop ? 1 : -1;
|
|
return {
|
|
x: bbox.x + context.seriesRect.x + datum.width / 2,
|
|
y: bbox.y + context.seriesRect.y + direction * (bbox.height + padding2),
|
|
position: isPositionTop ? "below" : "above"
|
|
};
|
|
}
|
|
getLabelCoords(datum, bbox) {
|
|
const isPositionTop = datum.position === "top";
|
|
const padding2 = datum.getPadding().top + calcLineHeight3(datum.fontSize, ANNOTATION_TEXT_LINE_HEIGHT) / 2;
|
|
return { x: bbox.x, y: bbox.y + (isPositionTop ? padding2 / 2 : 0) };
|
|
}
|
|
getTextBaseline(datum) {
|
|
return datum.position === "top" ? "middle" : datum.position;
|
|
}
|
|
getHandleCoords(_datum, coords, _bbox) {
|
|
return {
|
|
x: coords.x,
|
|
y: coords.y + DivariantHandle.HANDLE_SIZE / 2 + 4
|
|
};
|
|
}
|
|
getHandleStyles(datum) {
|
|
return {
|
|
fill: datum.handle.fill,
|
|
stroke: datum.handle.stroke ?? datum.fill,
|
|
strokeOpacity: datum.handle.strokeOpacity,
|
|
strokeWidth: datum.handle.strokeWidth
|
|
};
|
|
}
|
|
toggleHovered(hovered, active, readOnly) {
|
|
super.toggleHovered(hovered, active, readOnly);
|
|
const visible = hovered || active && !readOnly;
|
|
this.label.visible = visible;
|
|
this.shape.visible = visible;
|
|
this.zIndex = visible ? ZIndexMap4.CHART_ANNOTATION_FOCUSED : ZIndexMap4.CHART_ANNOTATION;
|
|
}
|
|
toggleActive(active) {
|
|
super.toggleActive(active);
|
|
this.label.visible = active;
|
|
this.shape.visible = active;
|
|
this.active = active;
|
|
}
|
|
containsPoint(x, y) {
|
|
if (this.shape.visible && this.shape.containsPoint(x, y))
|
|
return true;
|
|
if (this.iconBackground.containsPoint(x, y))
|
|
return true;
|
|
return super.containsPoint(x, y);
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/note/noteState.ts
|
|
var NoteStateMachine = class extends TextualPointStateMachine {
|
|
createDatum() {
|
|
return new NoteProperties();
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/note/noteConfig.ts
|
|
var noteConfig = {
|
|
type: "note" /* Note */,
|
|
datum: NoteProperties,
|
|
scene: NoteScene,
|
|
isDatum: NoteProperties.is,
|
|
translate: (node, datum, transition, context) => {
|
|
if (NoteProperties.is(datum) && NoteScene.is(node))
|
|
node.translate(datum, transition, context);
|
|
},
|
|
copy: (node, datum, copiedDatum, context) => {
|
|
if (NoteProperties.is(datum) && NoteProperties.is(copiedDatum) && NoteScene.is(node)) {
|
|
return node.copy(datum, copiedDatum, context);
|
|
}
|
|
},
|
|
update: (node, datum, context) => {
|
|
if (NoteProperties.is(datum) && NoteScene.is(node)) {
|
|
node.update(datum, context);
|
|
}
|
|
},
|
|
createState: (ctx, { createDatum }) => new NoteStateMachine({
|
|
...ctx,
|
|
create: createDatum("note" /* Note */)
|
|
}),
|
|
dragState: (ctx) => new DragStateMachine(ctx)
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/parallel-channel/parallelChannelScene.ts
|
|
import { Vec2 as Vec217, Vec4 as Vec413 } from "ag-charts-core";
|
|
var ParallelChannelScene = class extends ChannelScene {
|
|
constructor() {
|
|
super();
|
|
this.type = "parallel-channel";
|
|
this.handles = {
|
|
topLeft: new DivariantHandle(),
|
|
topMiddle: new UnivariantHandle(),
|
|
topRight: new DivariantHandle(),
|
|
bottomLeft: new DivariantHandle(),
|
|
bottomMiddle: new UnivariantHandle(),
|
|
bottomRight: new DivariantHandle()
|
|
};
|
|
this.middleLine = new CollidableLine();
|
|
this.append([this.background, this.topLine, this.middleLine, this.bottomLine, ...Object.values(this.handles)]);
|
|
}
|
|
static is(value) {
|
|
return AnnotationScene.isCheck(value, "parallel-channel");
|
|
}
|
|
dragHandle(datum, target, context, snapping) {
|
|
const { activeHandle, handles } = this;
|
|
if (activeHandle == null)
|
|
return;
|
|
const { offset } = handles[activeHandle].drag(target);
|
|
handles[activeHandle].toggleDragging(true);
|
|
if (activeHandle === "topMiddle" || activeHandle === "bottomMiddle") {
|
|
offset.x = 0;
|
|
}
|
|
let translateVectors = [];
|
|
let allowSnapping = snapping;
|
|
switch (activeHandle) {
|
|
case "topLeft":
|
|
case "bottomLeft":
|
|
translateVectors = ["topLeft", "bottomLeft"];
|
|
break;
|
|
case "topMiddle":
|
|
translateVectors = ["topLeft", "topRight"];
|
|
offset.y -= UnivariantHandle.HANDLE_SIZE / 2;
|
|
allowSnapping = false;
|
|
break;
|
|
case "topRight":
|
|
case "bottomRight":
|
|
translateVectors = ["topRight", "bottomRight"];
|
|
break;
|
|
case "bottomMiddle":
|
|
translateVectors = ["bottomLeft", "bottomRight"];
|
|
offset.y -= UnivariantHandle.HANDLE_SIZE / 2;
|
|
allowSnapping = false;
|
|
break;
|
|
}
|
|
const top = convertLine(datum, context);
|
|
const bottom = convertLine(datum.bottom, context);
|
|
if (!top || !bottom)
|
|
return;
|
|
const vectors = {
|
|
topLeft: Vec413.start(top),
|
|
topRight: Vec413.end(top),
|
|
bottomLeft: Vec413.start(bottom),
|
|
bottomRight: Vec413.end(bottom)
|
|
};
|
|
const snap = {
|
|
vectors: {
|
|
topLeft: vectors.topRight,
|
|
bottomLeft: vectors.bottomRight,
|
|
topRight: vectors.topLeft,
|
|
bottomRight: vectors.bottomLeft
|
|
},
|
|
angle: datum.snapToAngle
|
|
};
|
|
const points = translate(vectors, offset, context, {
|
|
overflowContinuous: this.overflowContinuous,
|
|
translateVectors,
|
|
snap: allowSnapping ? snap : void 0
|
|
});
|
|
datum.start.x = points.topLeft.x;
|
|
datum.start.y = points.topLeft.y;
|
|
datum.end.x = points.topRight.x;
|
|
datum.end.y = points.topRight.y;
|
|
datum.height = points.topLeft.y - points.bottomLeft.y;
|
|
}
|
|
getTranslatePointsVectors(start, end) {
|
|
const { bottomLeft, topLeft } = this.handles;
|
|
const height = bottomLeft.getBBox().y - topLeft.getBBox().y;
|
|
const bottomStart = Vec217.add(start, Vec217.from(0, height));
|
|
const bottomEnd = Vec217.add(end, Vec217.from(0, height));
|
|
return { start, end, bottomStart, bottomEnd };
|
|
}
|
|
containsPoint(x, y) {
|
|
return super.containsPoint(x, y) || this.middleLine.visible && this.middleLine.strokeWidth > 0 && this.middleLine.containsPoint(x, y);
|
|
}
|
|
getNodeAtCoords(x, y) {
|
|
if (this.middleLine.visible && this.middleLine.strokeWidth > 0 && this.middleLine.containsPoint(x, y))
|
|
return "line";
|
|
return super.getNodeAtCoords(x, y);
|
|
}
|
|
updateLines(datum, top, bottom, context, naturalTop, naturalBottom) {
|
|
const { topLine, middleLine, bottomLine } = this;
|
|
const { lineDashOffset, stroke: stroke3, strokeOpacity, strokeWidth } = datum;
|
|
const lineDash = datum.getLineDash();
|
|
const lineStyles = {
|
|
lineCap: datum.getLineCap(),
|
|
lineDash,
|
|
lineDashOffset,
|
|
stroke: stroke3,
|
|
strokeOpacity,
|
|
strokeWidth
|
|
};
|
|
topLine.setProperties({ ...top, ...lineStyles });
|
|
bottomLine.setProperties({ ...bottom, ...lineStyles });
|
|
const middlePoints = this.extendLine(
|
|
{
|
|
x1: naturalTop.x1,
|
|
y1: naturalBottom.y1 + (naturalTop.y1 - naturalBottom.y1) / 2,
|
|
x2: naturalTop.x2,
|
|
y2: naturalBottom.y2 + (naturalTop.y2 - naturalBottom.y2) / 2
|
|
},
|
|
datum,
|
|
context
|
|
);
|
|
middleLine.setProperties({
|
|
...middlePoints,
|
|
lineDash: datum.middle.lineDash ?? lineDash,
|
|
lineDashOffset: datum.middle.lineDashOffset ?? lineDashOffset,
|
|
stroke: datum.middle.stroke ?? stroke3,
|
|
strokeOpacity: datum.middle.strokeOpacity ?? strokeOpacity,
|
|
strokeWidth: datum.middle.strokeWidth ?? strokeWidth,
|
|
visible: datum.middle.visible ?? true
|
|
});
|
|
}
|
|
updateHandles(datum, top, bottom) {
|
|
const {
|
|
handles: { topLeft, topMiddle, topRight, bottomLeft, bottomMiddle, bottomRight }
|
|
} = this;
|
|
const handleStyles = {
|
|
fill: datum.handle.fill,
|
|
stroke: datum.handle.stroke ?? datum.stroke,
|
|
strokeOpacity: datum.handle.strokeOpacity ?? datum.strokeOpacity,
|
|
strokeWidth: datum.handle.strokeWidth ?? datum.strokeWidth
|
|
};
|
|
topLeft.update({ ...handleStyles, ...Vec413.start(top) });
|
|
topRight.update({ ...handleStyles, ...Vec413.end(top) });
|
|
bottomLeft.update({ ...handleStyles, ...Vec413.start(bottom) });
|
|
bottomRight.update({ ...handleStyles, ...Vec413.end(bottom) });
|
|
topMiddle.update({
|
|
...handleStyles,
|
|
...Vec217.sub(Vec413.center(top), Vec217.from(topMiddle.handle.width / 2, topMiddle.handle.height / 2))
|
|
});
|
|
bottomMiddle.update({
|
|
...handleStyles,
|
|
...Vec217.sub(Vec413.center(bottom), Vec217.from(bottomMiddle.handle.width / 2, bottomMiddle.handle.height / 2))
|
|
});
|
|
}
|
|
updateText(datum, top, bottom) {
|
|
this.text = this.updateNode(CollidableText, this.text, !!datum.text.label);
|
|
updateChannelText(true, top, bottom, datum.text, datum.strokeWidth, this.text, datum.text.label);
|
|
}
|
|
getBackgroundPoints(datum, top, bottom, bounds) {
|
|
const isFlippedX = top.x1 > top.x2;
|
|
const isFlippedY = top.y1 > top.y2;
|
|
const outOfBoundsStart = top.x1 !== bottom.x1 && top.y1 !== bottom.y1;
|
|
const outOfBoundsEnd = top.x2 !== bottom.x2 && top.y2 !== bottom.y2;
|
|
const points = Vec217.from(top);
|
|
if (datum.extendEnd && outOfBoundsEnd) {
|
|
points.push(Vec217.from(isFlippedX ? bounds.x1 : bounds.x2, isFlippedY ? bounds.y1 : bounds.y2));
|
|
}
|
|
points.push(...Vec217.from(bottom).reverse());
|
|
if (datum.extendStart && outOfBoundsStart) {
|
|
points.push(Vec217.from(isFlippedX ? bounds.x2 : bounds.x1, isFlippedY ? bounds.y2 : bounds.y1));
|
|
}
|
|
return points;
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/parallel-channel/parallelChannelState.ts
|
|
import { Debug as Debug10, StateMachine as StateMachine10, StateMachineProperty as StateMachineProperty10, isNumber as isNumber4 } from "ag-charts-core";
|
|
var ParallelChannelStateMachine = class extends StateMachine10 {
|
|
constructor(ctx) {
|
|
const actionCreate = ({ point }) => {
|
|
const datum = new ParallelChannelProperties();
|
|
datum.set({ start: point, end: point, height: 0 });
|
|
ctx.create(datum);
|
|
};
|
|
const actionFirstRender = () => {
|
|
const { node } = this;
|
|
node?.toggleActive(true);
|
|
node?.toggleHandles({
|
|
topLeft: true,
|
|
topMiddle: false,
|
|
topRight: false,
|
|
bottomLeft: false,
|
|
bottomMiddle: false,
|
|
bottomRight: false
|
|
});
|
|
};
|
|
const actionEndUpdate = ({ offset, context }) => {
|
|
const { datum, snapping } = this;
|
|
if (!datum)
|
|
return;
|
|
datum.set({ end: snapPoint(offset, context, snapping, datum.start, datum.snapToAngle) });
|
|
ctx.update();
|
|
};
|
|
const actionEndFinish = () => {
|
|
this.node?.toggleHandles({
|
|
topRight: true
|
|
});
|
|
ctx.update();
|
|
};
|
|
const actionHeightUpdate = ({ point }) => {
|
|
const { datum, node } = this;
|
|
const endY = getGroupingValue(datum?.end.y);
|
|
const startY = getGroupingValue(datum?.start.y);
|
|
const { y: pointY } = point;
|
|
if (datum == null || !isNumber4(startY) || !isNumber4(endY) || !isNumber4(pointY))
|
|
return;
|
|
const height = endY - (pointY ?? 0);
|
|
const bottomStartY = startY - height;
|
|
node?.toggleHandles({ bottomLeft: true, bottomRight: true });
|
|
if (!ctx.validatePoint({ x: datum.start.x, y: bottomStartY }, { overflowContinuous: true }) || !ctx.validatePoint({ x: datum.end.x, y: point.y }, { overflowContinuous: true })) {
|
|
return;
|
|
}
|
|
datum.set({ height });
|
|
ctx.update();
|
|
};
|
|
const actionHeightFinish = ({ point }) => {
|
|
const { datum, node } = this;
|
|
const endY = getGroupingValue(datum?.end.y);
|
|
const startY = getGroupingValue(datum?.start.y);
|
|
const { y: pointY } = point;
|
|
if (datum == null || !isNumber4(startY) || !isNumber4(endY) || !isNumber4(pointY))
|
|
return;
|
|
const height = endY - (pointY ?? 0);
|
|
const bottomStartY = startY - height;
|
|
node?.toggleHandles(true);
|
|
if (!ctx.validatePoint({ x: datum.start.x, y: bottomStartY }, { overflowContinuous: true }) || !ctx.validatePoint({ x: datum.end.x, y: point.y }, { overflowContinuous: true })) {
|
|
return;
|
|
}
|
|
datum.set({ height });
|
|
ctx.recordAction(`Create ${"parallel-channel" /* ParallelChannel */} annotation`);
|
|
ctx.showAnnotationOptions();
|
|
ctx.update();
|
|
};
|
|
const actionCancel = () => ctx.delete();
|
|
super("start", {
|
|
start: {
|
|
click: {
|
|
target: "waiting-first-render",
|
|
action: actionCreate
|
|
},
|
|
drag: {
|
|
target: "waiting-first-render",
|
|
action: actionCreate
|
|
},
|
|
reset: StateMachine10.parent
|
|
},
|
|
"waiting-first-render": {
|
|
render: {
|
|
target: "end",
|
|
action: actionFirstRender
|
|
}
|
|
},
|
|
end: {
|
|
hover: actionEndUpdate,
|
|
drag: actionEndUpdate,
|
|
click: {
|
|
target: "height",
|
|
action: actionEndFinish
|
|
},
|
|
dragEnd: {
|
|
target: "height",
|
|
action: actionEndFinish
|
|
},
|
|
reset: {
|
|
target: StateMachine10.parent,
|
|
action: actionCancel
|
|
},
|
|
cancel: {
|
|
target: StateMachine10.parent,
|
|
action: actionCancel
|
|
}
|
|
},
|
|
height: {
|
|
hover: actionHeightUpdate,
|
|
click: {
|
|
target: StateMachine10.parent,
|
|
action: actionHeightFinish
|
|
},
|
|
drag: {
|
|
target: StateMachine10.parent,
|
|
action: actionHeightFinish
|
|
},
|
|
reset: {
|
|
target: StateMachine10.parent,
|
|
action: actionCancel
|
|
},
|
|
cancel: {
|
|
target: StateMachine10.parent,
|
|
action: actionCancel
|
|
}
|
|
}
|
|
});
|
|
this.debug = Debug10.create(true, "annotations");
|
|
this.snapping = false;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
StateMachineProperty10()
|
|
], ParallelChannelStateMachine.prototype, "datum", 2);
|
|
__decorateClass([
|
|
StateMachineProperty10()
|
|
], ParallelChannelStateMachine.prototype, "node", 2);
|
|
__decorateClass([
|
|
StateMachineProperty10()
|
|
], ParallelChannelStateMachine.prototype, "snapping", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/parallel-channel/parallelChannelConfig.ts
|
|
var parallelChannelConfig = {
|
|
type: "parallel-channel" /* ParallelChannel */,
|
|
datum: ParallelChannelProperties,
|
|
scene: ParallelChannelScene,
|
|
isDatum: ParallelChannelProperties.is,
|
|
translate: (node, datum, transition, context) => {
|
|
if (ParallelChannelProperties.is(datum) && ParallelChannelScene.is(node)) {
|
|
node.translate(datum, transition, context);
|
|
}
|
|
},
|
|
copy: (node, datum, copiedDatum, context) => {
|
|
if (ParallelChannelProperties.is(datum) && ParallelChannelProperties.is(copiedDatum) && ParallelChannelScene.is(node)) {
|
|
return node.copy(datum, copiedDatum, context);
|
|
}
|
|
},
|
|
update: (node, datum, context) => {
|
|
if (ParallelChannelProperties.is(datum) && ParallelChannelScene.is(node)) {
|
|
node.update(datum, context);
|
|
}
|
|
},
|
|
createState: (ctx, { createDatum }) => new ParallelChannelStateMachine({
|
|
...ctx,
|
|
create: createDatum("parallel-channel" /* ParallelChannel */)
|
|
}),
|
|
dragState: (ctx) => new DragStateMachine(ctx)
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/text/textScene.ts
|
|
var TextScene = class extends TextualPointScene {
|
|
constructor() {
|
|
super();
|
|
this.type = "text" /* Text */;
|
|
this.append([this.label, this.handle]);
|
|
}
|
|
static is(value) {
|
|
return AnnotationScene.isCheck(value, "text" /* Text */);
|
|
}
|
|
getHandleCoords(_datum, point) {
|
|
const halfSize = DivariantHandle.HANDLE_SIZE / 2;
|
|
return {
|
|
x: point.x + halfSize,
|
|
y: point.y + 2 + halfSize
|
|
};
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/text/textState.ts
|
|
var TextStateMachine = class extends TextualPointStateMachine {
|
|
createDatum() {
|
|
return new TextProperties();
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/text/textConfig.ts
|
|
var textConfig = {
|
|
type: "text" /* Text */,
|
|
datum: TextProperties,
|
|
scene: TextScene,
|
|
isDatum: TextProperties.is,
|
|
translate: (node, datum, transition, context) => {
|
|
if (TextProperties.is(datum) && TextScene.is(node))
|
|
node.translate(datum, transition, context);
|
|
},
|
|
copy: (node, datum, copiedDatum, context) => {
|
|
if (TextProperties.is(datum) && TextProperties.is(copiedDatum) && TextScene.is(node)) {
|
|
return node.copy(datum, copiedDatum, context);
|
|
}
|
|
},
|
|
update: (node, datum, context) => {
|
|
if (TextProperties.is(datum) && TextScene.is(node)) {
|
|
node.update(datum, context);
|
|
}
|
|
},
|
|
createState: (ctx, { createDatum }) => new TextStateMachine({
|
|
...ctx,
|
|
create: createDatum("text" /* Text */)
|
|
}),
|
|
dragState: (ctx) => new DragStateMachine(ctx)
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/annotationsConfig.ts
|
|
var annotationConfigs = {
|
|
// Lines
|
|
[lineConfig.type]: lineConfig,
|
|
[horizontalLineConfig.type]: horizontalLineConfig,
|
|
[verticalLineConfig.type]: verticalLineConfig,
|
|
// Channels
|
|
[parallelChannelConfig.type]: parallelChannelConfig,
|
|
[disjointChannelConfig.type]: disjointChannelConfig,
|
|
// Fibonaccis
|
|
[fibonacciRetracementConfig.type]: fibonacciRetracementConfig,
|
|
[fibonacciRetracementTrendBasedConfig.type]: fibonacciRetracementTrendBasedConfig,
|
|
// Texts
|
|
[calloutConfig.type]: calloutConfig,
|
|
[commentConfig.type]: commentConfig,
|
|
[noteConfig.type]: noteConfig,
|
|
[textConfig.type]: textConfig,
|
|
// Shapes
|
|
[arrowConfig.type]: arrowConfig,
|
|
[arrowUpConfig.type]: arrowUpConfig,
|
|
[arrowDownConfig.type]: arrowDownConfig,
|
|
// Measurers
|
|
[dateRangeConfig.type]: dateRangeConfig,
|
|
[priceRangeConfig.type]: priceRangeConfig,
|
|
[datePriceRangeConfig.type]: datePriceRangeConfig,
|
|
[quickDatePriceRangeConfig.type]: quickDatePriceRangeConfig
|
|
};
|
|
function getTypedDatum(datum) {
|
|
for (const { isDatum } of Object.values(annotationConfigs)) {
|
|
if (isDatum(datum)) {
|
|
return datum;
|
|
}
|
|
}
|
|
}
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/annotationsStateMachine.ts
|
|
import "ag-charts-community";
|
|
import {
|
|
ActionOnSet as ActionOnSet3,
|
|
Debug as Debug11,
|
|
ParallelStateMachine,
|
|
StateMachine as StateMachine11,
|
|
StateMachineProperty as StateMachineProperty11
|
|
} from "ag-charts-core";
|
|
var AnnotationsStateMachine = class extends ParallelStateMachine {
|
|
constructor(ctx) {
|
|
super(
|
|
new SnappingStateMachine((snapping) => {
|
|
this.snapping = snapping;
|
|
}),
|
|
new UpdateMachine(() => {
|
|
this.node = this.active == null ? void 0 : ctx.node(this.active);
|
|
}),
|
|
new AnnotationsMainStateMachine(ctx, (index) => {
|
|
this.active = index;
|
|
this.datum = this.active == null ? void 0 : ctx.datum(this.active);
|
|
this.node = this.active == null ? void 0 : ctx.node(this.active);
|
|
})
|
|
);
|
|
this.snapping = false;
|
|
}
|
|
// TODO: remove this leak
|
|
getActive() {
|
|
return this.active;
|
|
}
|
|
// TODO: remove this leak
|
|
isActive(index) {
|
|
return index === this.active;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
StateMachineProperty11()
|
|
], AnnotationsStateMachine.prototype, "snapping", 2);
|
|
__decorateClass([
|
|
StateMachineProperty11()
|
|
], AnnotationsStateMachine.prototype, "datum", 2);
|
|
__decorateClass([
|
|
StateMachineProperty11()
|
|
], AnnotationsStateMachine.prototype, "node", 2);
|
|
var SnappingStateMachine = class extends StateMachine11 {
|
|
constructor(setSnapping) {
|
|
super("idle" /* Idle */, {
|
|
["idle" /* Idle */]: {
|
|
hover: ({ shiftKey }) => setSnapping(shiftKey),
|
|
keyDown: ({ shiftKey }) => setSnapping(shiftKey),
|
|
keyUp: ({ shiftKey }) => setSnapping(shiftKey),
|
|
click: ({ shiftKey }) => setSnapping(shiftKey),
|
|
drag: ({ shiftKey }) => setSnapping(shiftKey)
|
|
},
|
|
["dragging" /* Dragging */]: {},
|
|
["translating" /* Translating */]: {},
|
|
["text-input" /* TextInput */]: {}
|
|
});
|
|
}
|
|
};
|
|
var UpdateMachine = class extends StateMachine11 {
|
|
constructor(update) {
|
|
super("idle" /* Idle */, {
|
|
["idle" /* Idle */]: {
|
|
onEnter: update,
|
|
render: update
|
|
},
|
|
["dragging" /* Dragging */]: {
|
|
onEnter: update,
|
|
render: update
|
|
},
|
|
["translating" /* Translating */]: {
|
|
onEnter: update,
|
|
render: update
|
|
},
|
|
["text-input" /* TextInput */]: {
|
|
render: update
|
|
}
|
|
});
|
|
}
|
|
};
|
|
var AnnotationsMainStateMachine = class extends StateMachine11 {
|
|
constructor(ctx, setActive) {
|
|
const createDatum = (type) => (datum) => {
|
|
ctx.create(type, datum);
|
|
this.active = ctx.selectLast();
|
|
};
|
|
const deleteDatum = () => {
|
|
if (this.active != null)
|
|
ctx.delete(this.active);
|
|
this.active = void 0;
|
|
ctx.select();
|
|
};
|
|
const stateMachineHelpers = {
|
|
createDatum
|
|
};
|
|
const createStateMachineContext = {
|
|
...ctx,
|
|
delete: deleteDatum,
|
|
showTextInput: () => {
|
|
if (this.active != null)
|
|
ctx.showTextInput(this.active);
|
|
},
|
|
deselect: () => {
|
|
const prevActive = this.active;
|
|
this.active = void 0;
|
|
this.hovered = void 0;
|
|
ctx.select(this.active, prevActive);
|
|
},
|
|
showAnnotationOptions: () => {
|
|
if (this.active != null)
|
|
ctx.showAnnotationOptions(this.active);
|
|
}
|
|
};
|
|
const createStateMachines = Object.fromEntries(
|
|
Object.entries(annotationConfigs).map(([type, config]) => [
|
|
type,
|
|
config.createState(createStateMachineContext, stateMachineHelpers)
|
|
])
|
|
);
|
|
const dragStateMachines = Object.fromEntries(
|
|
Object.entries(annotationConfigs).map(([type, config]) => [
|
|
type,
|
|
config.dragState(ctx, stateMachineHelpers)
|
|
])
|
|
);
|
|
const actionColor = ({
|
|
colorPickerType,
|
|
colorOpacity,
|
|
color: color7,
|
|
opacity,
|
|
isMultiColor
|
|
}) => {
|
|
if (!this.datum)
|
|
return;
|
|
if (colorPickerType === "text-color") {
|
|
ctx.updateTextInputColor(color7);
|
|
}
|
|
setColor(this.datum, colorPickerType, colorOpacity, color7, opacity, isMultiColor);
|
|
ctx.update();
|
|
};
|
|
const actionFontSize = (fontSize) => {
|
|
const { datum, node } = this;
|
|
if (!datum || !node)
|
|
return;
|
|
if (isTextType(datum)) {
|
|
datum.fontSize = fontSize;
|
|
ctx.updateTextInputFontSize(fontSize);
|
|
} else if (hasLineText(datum)) {
|
|
datum.text.fontSize = fontSize;
|
|
}
|
|
ctx.update();
|
|
};
|
|
const actionLineStyle = (lineStyle) => {
|
|
const { datum, node } = this;
|
|
if (!datum || !node || !hasLineStyle(datum))
|
|
return;
|
|
setLineStyle(datum, lineStyle);
|
|
ctx.update();
|
|
};
|
|
const actionUpdateTextInputBBox = (bbox) => {
|
|
const { node } = this;
|
|
if (!node || !("setTextInputBBox" in node))
|
|
return;
|
|
node.setTextInputBBox(bbox);
|
|
ctx.update();
|
|
};
|
|
const actionSaveText = ({ textInputValue, bbox }) => {
|
|
const { datum } = this;
|
|
if (bbox != null && textInputValue != null && textInputValue.length > 0) {
|
|
if (!isTextType(datum)) {
|
|
return;
|
|
}
|
|
const wrappedText = maybeWrapText(datum, textInputValue, bbox.width);
|
|
datum.set({ text: wrappedText });
|
|
ctx.update();
|
|
ctx.recordAction(`Change ${datum.type} annotation text`);
|
|
} else {
|
|
ctx.delete(this.active);
|
|
ctx.recordAction(`Delete ${datum?.type} annotation`);
|
|
}
|
|
};
|
|
const actionCancel = () => {
|
|
ctx.updateTextInputBBox(void 0);
|
|
};
|
|
const guardActive = () => this.active != null;
|
|
const guardCopied = () => this.copied != null;
|
|
const guardActiveHasLineText = () => {
|
|
const { active, datum } = this;
|
|
if (active == null)
|
|
return false;
|
|
if (!datum)
|
|
return false;
|
|
return hasLineText(datum) && datum.isWriteable();
|
|
};
|
|
const guardActiveNotEphemeral = () => this.active != null && !isEphemeralType(this.datum);
|
|
const guardHovered = () => this.hovered != null;
|
|
super("idle" /* Idle */, {
|
|
["idle" /* Idle */]: {
|
|
onEnter: () => {
|
|
ctx.select(this.active, this.active);
|
|
if (this.hoverCoords) {
|
|
this.hovered = ctx.hoverAtCoords(this.hoverCoords, this.active, this.hovered);
|
|
}
|
|
},
|
|
hover: ({ offset }) => {
|
|
this.hovered = ctx.hoverAtCoords(offset, this.active, this.hovered);
|
|
this.hoverCoords = offset;
|
|
},
|
|
translate: {
|
|
guard: guardActive,
|
|
target: "translating" /* Translating */,
|
|
action: ({ translation }) => {
|
|
ctx.startInteracting();
|
|
ctx.translate(this.active, translation);
|
|
ctx.update();
|
|
}
|
|
},
|
|
copy: {
|
|
guard: guardActiveNotEphemeral,
|
|
action: () => {
|
|
this.copied = ctx.copy(this.active);
|
|
}
|
|
},
|
|
cut: {
|
|
guard: guardActiveNotEphemeral,
|
|
action: () => {
|
|
this.copied = ctx.copy(this.active);
|
|
deleteDatum();
|
|
}
|
|
},
|
|
paste: {
|
|
guard: guardCopied,
|
|
action: () => {
|
|
ctx.paste(this.copied);
|
|
}
|
|
},
|
|
selectLast: () => {
|
|
const previousActive = this.active;
|
|
this.active = ctx.selectLast();
|
|
ctx.select(this.active, previousActive);
|
|
},
|
|
click: [
|
|
{
|
|
guard: () => {
|
|
const { active, hovered, datum } = this;
|
|
if (active == null || hovered !== active)
|
|
return false;
|
|
if (!datum)
|
|
return false;
|
|
return isTextType(datum) && datum.isWriteable();
|
|
},
|
|
target: "text-input" /* TextInput */
|
|
},
|
|
{
|
|
action: () => {
|
|
const prevActive = this.active;
|
|
this.active = this.hovered;
|
|
ctx.select(this.active, prevActive);
|
|
}
|
|
}
|
|
],
|
|
dblclick: {
|
|
guard: guardActiveHasLineText,
|
|
action: ({ offset }) => {
|
|
const nodeAtCoords = ctx.getNodeAtCoords(offset, this.active) === "text" ? "text" : "line";
|
|
ctx.showAnnotationSettings(this.active, void 0, nodeAtCoords);
|
|
}
|
|
},
|
|
dragStart: [
|
|
{
|
|
guard: guardHovered,
|
|
target: "dragging" /* Dragging */,
|
|
action: () => {
|
|
const prevActive = this.active;
|
|
this.active = this.hovered;
|
|
ctx.select(this.active, prevActive);
|
|
ctx.startInteracting();
|
|
}
|
|
},
|
|
{
|
|
action: () => {
|
|
const prevActive = this.active;
|
|
this.active = this.hovered;
|
|
ctx.select(this.active, prevActive);
|
|
}
|
|
}
|
|
],
|
|
color: {
|
|
guard: guardActive,
|
|
action: actionColor
|
|
},
|
|
fontSize: {
|
|
guard: guardActive,
|
|
action: actionFontSize
|
|
},
|
|
lineProps: {
|
|
guard: guardActive,
|
|
action: (props) => {
|
|
const datum = getTypedDatum(this.datum);
|
|
datum?.set(props);
|
|
ctx.update();
|
|
ctx.recordAction(
|
|
`Change ${datum?.type} ${Object.entries(props).map(([key, value]) => `${key} to ${value}`).join(", ")}`
|
|
);
|
|
}
|
|
},
|
|
lineStyle: {
|
|
guard: guardActive,
|
|
action: actionLineStyle
|
|
},
|
|
lineText: {
|
|
guard: guardActive,
|
|
action: (props) => {
|
|
const datum = getTypedDatum(this.datum);
|
|
if (!hasLineText(datum))
|
|
return;
|
|
if (isChannelType(datum) && props.position === "center") {
|
|
props.position = "inside";
|
|
}
|
|
datum.text.set(props);
|
|
ctx.update();
|
|
}
|
|
},
|
|
updateTextInputBBox: {
|
|
guard: guardActive,
|
|
action: actionUpdateTextInputBBox
|
|
},
|
|
toolbarPressSettings: {
|
|
guard: guardActiveHasLineText,
|
|
action: (sourceEvent) => {
|
|
ctx.showAnnotationSettings(this.active, sourceEvent);
|
|
}
|
|
},
|
|
reset: () => {
|
|
if (this.active != null) {
|
|
this.node?.toggleActive(false);
|
|
}
|
|
this.hovered = void 0;
|
|
this.active = void 0;
|
|
ctx.select(this.active, this.active);
|
|
ctx.resetToIdle();
|
|
},
|
|
delete: () => {
|
|
if (this.active == null)
|
|
return;
|
|
ctx.delete(this.active);
|
|
if (isEphemeralType(this.datum))
|
|
return;
|
|
ctx.recordAction(`Delete ${this.datum?.type} annotation`);
|
|
},
|
|
deleteAll: () => {
|
|
ctx.deleteAll();
|
|
},
|
|
...createStateMachines
|
|
},
|
|
["dragging" /* Dragging */]: {
|
|
onEnter: (_, data) => {
|
|
if (this.active == null)
|
|
return;
|
|
const type = ctx.getAnnotationType(this.active);
|
|
if (!type)
|
|
return;
|
|
this.transitionRoot(type);
|
|
this.transitionRoot("dragStart", data);
|
|
},
|
|
...dragStateMachines
|
|
},
|
|
["translating" /* Translating */]: {
|
|
onEnter: () => {
|
|
},
|
|
translate: {
|
|
guard: guardActive,
|
|
target: "translating" /* Translating */,
|
|
action: ({ translation }) => {
|
|
ctx.startInteracting();
|
|
ctx.translate(this.active, translation);
|
|
ctx.update();
|
|
}
|
|
},
|
|
translateEnd: {
|
|
guard: guardActive,
|
|
target: "idle" /* Idle */
|
|
},
|
|
onExit: () => {
|
|
ctx.stopInteracting();
|
|
ctx.update();
|
|
ctx.recordAction("Translate annotation");
|
|
}
|
|
},
|
|
["text-input" /* TextInput */]: {
|
|
onEnter: () => {
|
|
if (this.active == null)
|
|
return;
|
|
const datum = getTypedDatum(this.datum);
|
|
if (!datum || !("getTextInputCoords" in datum))
|
|
return;
|
|
ctx.startInteracting();
|
|
ctx.showTextInput(this.active);
|
|
datum.visible = false;
|
|
ctx.update();
|
|
},
|
|
updateTextInputBBox: {
|
|
guard: guardActive,
|
|
action: actionUpdateTextInputBBox
|
|
},
|
|
resize: {
|
|
target: "idle" /* Idle */,
|
|
action: actionSaveText
|
|
},
|
|
click: {
|
|
target: "idle" /* Idle */,
|
|
action: actionSaveText
|
|
},
|
|
drag: {
|
|
target: "idle" /* Idle */,
|
|
action: actionSaveText
|
|
},
|
|
textInput: [
|
|
{
|
|
guard: guardCancelAndExit,
|
|
target: "idle" /* Idle */,
|
|
action: actionCancel
|
|
},
|
|
{
|
|
guard: guardSaveAndExit,
|
|
target: "idle" /* Idle */,
|
|
action: actionSaveText
|
|
}
|
|
],
|
|
color: {
|
|
guard: guardActive,
|
|
action: actionColor
|
|
},
|
|
fontSize: {
|
|
guard: guardActive,
|
|
action: actionFontSize
|
|
},
|
|
cancel: {
|
|
target: "idle" /* Idle */,
|
|
action: actionCancel
|
|
},
|
|
onExit: () => {
|
|
ctx.stopInteracting();
|
|
ctx.hideTextInput();
|
|
const wasActive = this.active;
|
|
this.active = this.hovered = void 0;
|
|
ctx.select(this.active, wasActive);
|
|
if (wasActive == null)
|
|
return;
|
|
const datum = ctx.datum(wasActive);
|
|
const node = ctx.node(wasActive);
|
|
if (!datum || !node)
|
|
return;
|
|
datum.visible = true;
|
|
}
|
|
}
|
|
});
|
|
this.setActive = setActive;
|
|
this.debug = Debug11.create(true, "annotations");
|
|
this.snapping = false;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
ActionOnSet3({
|
|
changeValue(newValue) {
|
|
this.setActive(newValue);
|
|
}
|
|
}),
|
|
StateMachineProperty11()
|
|
], AnnotationsMainStateMachine.prototype, "active", 2);
|
|
__decorateClass([
|
|
StateMachineProperty11()
|
|
], AnnotationsMainStateMachine.prototype, "hovered", 2);
|
|
__decorateClass([
|
|
StateMachineProperty11()
|
|
], AnnotationsMainStateMachine.prototype, "hoverCoords", 2);
|
|
__decorateClass([
|
|
StateMachineProperty11()
|
|
], AnnotationsMainStateMachine.prototype, "copied", 2);
|
|
__decorateClass([
|
|
StateMachineProperty11()
|
|
], AnnotationsMainStateMachine.prototype, "snapping", 2);
|
|
__decorateClass([
|
|
StateMachineProperty11()
|
|
], AnnotationsMainStateMachine.prototype, "datum", 2);
|
|
__decorateClass([
|
|
StateMachineProperty11()
|
|
], AnnotationsMainStateMachine.prototype, "node", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/annotationsToolbar.ts
|
|
import { _ModuleSupport as _ModuleSupport60 } from "ag-charts-community";
|
|
import {
|
|
ActionOnSet as ActionOnSet4,
|
|
BaseProperties as BaseProperties15,
|
|
ChartAxisDirection as ChartAxisDirection7,
|
|
CleanupRegistry as CleanupRegistry3,
|
|
EventEmitter as EventEmitter2,
|
|
PropertiesArray as PropertiesArray2,
|
|
Property as Property35
|
|
} from "ag-charts-core";
|
|
var { LayoutElement, Menu: Menu2 } = _ModuleSupport60;
|
|
var AnnotationsToolbarButtonProperties = class extends ToolbarButtonProperties {
|
|
};
|
|
__decorateClass([
|
|
Property35
|
|
], AnnotationsToolbarButtonProperties.prototype, "value", 2);
|
|
var AnnotationsToolbar = class extends BaseProperties15 {
|
|
constructor(ctx) {
|
|
super();
|
|
this.ctx = ctx;
|
|
this.enabled = true;
|
|
this.padding = 20;
|
|
this.buttons = new PropertiesArray2(AnnotationsToolbarButtonProperties);
|
|
this.events = new EventEmitter2();
|
|
this.annotationMenu = new Menu2(this.ctx, "annotations");
|
|
this.cleanup = new CleanupRegistry3();
|
|
this.toolbar = ctx.sharedToolbar.getSharedToolbar("annotations");
|
|
const onKeyDown = this.onKeyDown.bind(this);
|
|
this.toolbar.addListener("keydown", onKeyDown);
|
|
this.cleanup.register(
|
|
this.toolbar.addToolbarListener("button-pressed", this.onToolbarButtonPress.bind(this)),
|
|
ctx.layoutManager.registerElement(LayoutElement.ToolbarLeft, this.onLayoutStart.bind(this)),
|
|
() => {
|
|
this.toolbar.removeListener("keydown", onKeyDown);
|
|
this.toolbar.destroy();
|
|
}
|
|
);
|
|
}
|
|
destroy() {
|
|
this.cleanup.flush();
|
|
}
|
|
toggleClearButtonEnabled(enabled) {
|
|
const index = this.buttons.findIndex((button) => button.value === "clear");
|
|
this.toolbar.toggleButtonEnabledByIndex(index, enabled);
|
|
}
|
|
resetButtonIcons() {
|
|
for (const [index, button] of this.buttons.entries()) {
|
|
switch (button.value) {
|
|
case "line-menu":
|
|
this.updateButtonByIndex(index, { icon: "trend-line-drawing", value: "line-menu" });
|
|
break;
|
|
case "fibonacci-menu":
|
|
this.updateButtonByIndex(index, { icon: "fibonacci-retracement-drawing", value: "fibonacci-menu" });
|
|
break;
|
|
case "text-menu":
|
|
this.updateButtonByIndex(index, { icon: "text-annotation", value: "text-menu" });
|
|
break;
|
|
case "shape-menu":
|
|
this.updateButtonByIndex(index, { icon: "arrow-drawing", value: "shape-menu" });
|
|
break;
|
|
case "measurer-menu":
|
|
this.updateButtonByIndex(index, { icon: "measurer-drawing", value: "measurer-menu" });
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
hideOverlays() {
|
|
this.annotationMenu.hide();
|
|
}
|
|
clearActiveButton() {
|
|
this.toolbar.clearActiveButton();
|
|
}
|
|
onLayoutStart(ctx) {
|
|
if (!this.enabled)
|
|
return;
|
|
this.toolbar.updateButtons(this.buttons);
|
|
this.toolbar.layout(ctx.layoutBox, this.padding);
|
|
}
|
|
refreshButtonsEnabled(enabled) {
|
|
for (const [index, button] of this.buttons.entries()) {
|
|
if (!button)
|
|
continue;
|
|
this.toolbar.toggleButtonEnabledByIndex(index, enabled);
|
|
}
|
|
}
|
|
onToolbarButtonPress({
|
|
event,
|
|
button,
|
|
buttonBounds,
|
|
buttonWidget
|
|
}) {
|
|
const axisScale = this.ctx.axisManager.getAxisContext(ChartAxisDirection7.Y)[0].scale;
|
|
switch (button.value) {
|
|
case "clear":
|
|
this.events.emit("pressed-clear", null);
|
|
break;
|
|
case "line-menu":
|
|
this.onToolbarButtonPressShowMenu(
|
|
event,
|
|
buttonBounds,
|
|
buttonWidget,
|
|
button.value,
|
|
"toolbarAnnotationsLineAnnotations",
|
|
LINE_ANNOTATION_ITEMS.filter((item) => item.visible ? item.visible(axisScale) : true)
|
|
);
|
|
break;
|
|
case "fibonacci-menu":
|
|
this.onToolbarButtonPressShowMenu(
|
|
event,
|
|
buttonBounds,
|
|
buttonWidget,
|
|
button.value,
|
|
"toolbarAnnotationsFibonacciAnnotations",
|
|
FIBONACCI_ANNOTATION_ITEMS
|
|
);
|
|
break;
|
|
case "text-menu":
|
|
this.onToolbarButtonPressShowMenu(
|
|
event,
|
|
buttonBounds,
|
|
buttonWidget,
|
|
button.value,
|
|
"toolbarAnnotationsTextAnnotations",
|
|
TEXT_ANNOTATION_ITEMS
|
|
);
|
|
break;
|
|
case "shape-menu":
|
|
this.onToolbarButtonPressShowMenu(
|
|
event,
|
|
buttonBounds,
|
|
buttonWidget,
|
|
button.value,
|
|
"toolbarAnnotationsShapeAnnotations",
|
|
SHAPE_ANNOTATION_ITEMS
|
|
);
|
|
break;
|
|
case "measurer-menu":
|
|
this.onToolbarButtonPressShowMenu(
|
|
event,
|
|
buttonBounds,
|
|
buttonWidget,
|
|
button.value,
|
|
"toolbarAnnotationsMeasurerAnnotations",
|
|
MEASURER_ANNOTATION_ITEMS
|
|
);
|
|
break;
|
|
}
|
|
}
|
|
onToolbarButtonPressShowMenu(event, buttonBounds, controller, menu, ariaLabel, items) {
|
|
this.events.emit("pressed-show-menu", null);
|
|
const index = this.buttons.findIndex((button) => button.value === menu);
|
|
this.toolbar.toggleActiveButtonByIndex(index);
|
|
this.annotationMenu.setAnchor({ x: buttonBounds.x + buttonBounds.width + 6, y: buttonBounds.y });
|
|
this.annotationMenu.show(controller, {
|
|
items,
|
|
ariaLabel: this.ctx.localeManager.t(ariaLabel),
|
|
class: "ag-charts-annotations__toolbar-menu",
|
|
sourceEvent: event.sourceEvent,
|
|
onPress: this.onButtonPressMenuCreateAnnotation.bind(this, menu)
|
|
});
|
|
}
|
|
onButtonPressMenuCreateAnnotation(menu, item) {
|
|
const index = this.buttons.findIndex((button) => button.value === menu);
|
|
this.updateButtonByIndex(index, { icon: item.icon });
|
|
this.events.emit("pressed-create-annotation", { annotation: item.value });
|
|
this.annotationMenu.hide();
|
|
}
|
|
onKeyDown({ sourceEvent }) {
|
|
if (sourceEvent.key === "Escape") {
|
|
this.events.emit("cancel-create-annotation", null);
|
|
}
|
|
}
|
|
updateButtonByIndex(index, change) {
|
|
const button = this.buttons.at(index);
|
|
if (!button)
|
|
return;
|
|
button.set({ ...button.toJson(), ...change, value: change.value ?? button.value });
|
|
this.toolbar.updateButtonByIndex(index, { ...button.toJson() });
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property35,
|
|
ActionOnSet4({
|
|
changeValue(enabled) {
|
|
this.toolbar?.setHidden(!enabled);
|
|
}
|
|
})
|
|
], AnnotationsToolbar.prototype, "enabled", 2);
|
|
__decorateClass([
|
|
Property35
|
|
], AnnotationsToolbar.prototype, "padding", 2);
|
|
__decorateClass([
|
|
Property35
|
|
], AnnotationsToolbar.prototype, "buttons", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/axisButton.ts
|
|
import { _ModuleSupport as _ModuleSupport61, _Widget as _Widget2 } from "ag-charts-community";
|
|
import { AbstractModuleInstance as AbstractModuleInstance3, ChartAxisDirection as ChartAxisDirection8, Property as Property36, getIconClassNames } from "ag-charts-core";
|
|
var { InteractionState } = _ModuleSupport61;
|
|
var DEFAULT_ANNOTATION_AXIS_BUTTON_CLASS = `ag-charts-annotations__axis-button`;
|
|
var AxisButton = class extends AbstractModuleInstance3 {
|
|
constructor(ctx, axisCtx, onButtonClick, seriesRect) {
|
|
super();
|
|
this.ctx = ctx;
|
|
this.axisCtx = axisCtx;
|
|
this.onButtonClick = onButtonClick;
|
|
this.seriesRect = seriesRect;
|
|
this.enabled = true;
|
|
this.snap = false;
|
|
this.padding = 0;
|
|
this.button = this.setup();
|
|
this.toggleVisibility(false);
|
|
this.updateButtonElement();
|
|
this.snap = Boolean(axisCtx.scale.bandwidth);
|
|
ctx.domManager.addEventListener("focusin", ({ target }) => {
|
|
const htmlTarget = target instanceof HTMLElement ? target : void 0;
|
|
const isSeriesAreaChild = htmlTarget && ctx.domManager.contains(htmlTarget, "series-area");
|
|
if (!isSeriesAreaChild && htmlTarget !== this.button.getElement())
|
|
this.hide();
|
|
});
|
|
this.cleanup.register(
|
|
ctx.widgets.seriesWidget.addListener("drag-move", (e) => this.onMouseDrag(e)),
|
|
ctx.widgets.seriesWidget.addListener("mousemove", (e) => this.onMouseMove(e)),
|
|
ctx.widgets.seriesWidget.addListener("mouseleave", () => this.onMouseLeave()),
|
|
ctx.widgets.seriesDragInterpreter?.events.on("click", (e) => this.onClick(e)),
|
|
ctx.eventsHub.on("series:focus-change", () => this.onKeyPress()),
|
|
ctx.eventsHub.on("zoom:pan-start", () => this.hide()),
|
|
ctx.eventsHub.on("zoom:change-complete", () => this.hide()),
|
|
() => this.destroyElements(),
|
|
() => this.button.destroy()
|
|
);
|
|
}
|
|
update(seriesRect, padding2) {
|
|
this.seriesRect = seriesRect;
|
|
this.padding = padding2;
|
|
}
|
|
setup() {
|
|
const button = new _Widget2.ButtonWidget();
|
|
button.addClass(DEFAULT_ANNOTATION_AXIS_BUTTON_CLASS);
|
|
button.setTabIndex(-1);
|
|
button.setAriaLabel(this.ctx.localeManager.t("ariaLabelAddHorizontalLine"));
|
|
this.ctx.widgets.seriesWidget.getElement().appendChild(button.getElement());
|
|
return button;
|
|
}
|
|
destroyElements() {
|
|
this.ctx.domManager.removeChild("canvas-overlay", DEFAULT_ANNOTATION_AXIS_BUTTON_CLASS);
|
|
}
|
|
onMouseMove(e) {
|
|
if (this.ctx.interactionManager.isState(InteractionState.Clickable))
|
|
this.show(e);
|
|
}
|
|
onMouseDrag(e) {
|
|
if (this.ctx.interactionManager.isState(InteractionState.AnnotationsMoveable))
|
|
this.show(e);
|
|
}
|
|
onMouseLeave() {
|
|
if (this.ctx.interactionManager.isState(InteractionState.Clickable))
|
|
this.hide();
|
|
}
|
|
onClick(e) {
|
|
if (this.ctx.interactionManager.isState(InteractionState.Clickable) && e.device === "touch")
|
|
this.show(e);
|
|
}
|
|
show(event) {
|
|
const { sourceEvent, currentX: x, currentY: y } = event;
|
|
if (!(this.enabled && this.ctx.widgets.seriesWidget.getElement().contains(sourceEvent.target))) {
|
|
this.hide();
|
|
return;
|
|
}
|
|
this.toggleVisibility(true);
|
|
const buttonCoords = this.getButtonCoordinates({ x, y });
|
|
this.coords = {
|
|
x: buttonCoords.x + this.button.clientWidth / 2,
|
|
y: buttonCoords.y + this.button.clientHeight / 2
|
|
};
|
|
this.updatePosition(buttonCoords);
|
|
}
|
|
hide() {
|
|
this.toggleVisibility(false);
|
|
}
|
|
onKeyPress() {
|
|
if (this.snap && this.ctx.interactionManager.isState(InteractionState.Default))
|
|
return;
|
|
this.hide();
|
|
}
|
|
getButtonCoordinates({ x, y }) {
|
|
const {
|
|
axisCtx: { direction, position },
|
|
seriesRect,
|
|
snap,
|
|
axisCtx,
|
|
padding: padding2
|
|
} = this;
|
|
const { clientWidth: buttonWidth, clientHeight: buttonHeight } = this.button;
|
|
const [minY, maxY] = [0, seriesRect.height];
|
|
const [minX, maxX] = [0, seriesRect.width];
|
|
if (snap) {
|
|
x = convert(invert(x - seriesRect.x, axisCtx), axisCtx) + seriesRect.x;
|
|
y = convert(invert(y - seriesRect.y, axisCtx), axisCtx) + seriesRect.y;
|
|
}
|
|
if (direction === ChartAxisDirection8.X) {
|
|
const crosshairLabelPadding = 5;
|
|
const offset = buttonHeight - Math.max(0, padding2 - crosshairLabelPadding);
|
|
x = x - buttonWidth / 2;
|
|
y = position === "top" ? minY - buttonHeight + offset : maxY - offset;
|
|
} else {
|
|
const crosshairLabelPadding = 9;
|
|
const offset = buttonWidth - Math.max(0, padding2 - crosshairLabelPadding);
|
|
x = position === "left" ? minX - buttonWidth + offset : maxX - offset;
|
|
y = y - buttonHeight / 2;
|
|
}
|
|
return { x, y };
|
|
}
|
|
toggleVisibility(visible) {
|
|
const { button } = this;
|
|
if (button == null)
|
|
return;
|
|
const isVisible = this.enabled && visible;
|
|
this.toggleClass("-hidden", !isVisible);
|
|
}
|
|
toggleClass(name, include) {
|
|
this.button.toggleClass(`${DEFAULT_ANNOTATION_AXIS_BUTTON_CLASS}-${name}`, include);
|
|
}
|
|
updatePosition({ x, y }) {
|
|
this.button.getElement().style.transform = `translate(${Math.round(x)}px, ${Math.round(y)}px)`;
|
|
}
|
|
updateButtonElement() {
|
|
const { button } = this;
|
|
button.addListener("click", () => this.onButtonClick(this.coords));
|
|
button.addListener("touchend", () => this.onButtonClick(this.coords));
|
|
button.addListener("drag-start", () => {
|
|
});
|
|
button.setInnerHTML(
|
|
`<span class="${getIconClassNames("zoom-in")} ${DEFAULT_ANNOTATION_AXIS_BUTTON_CLASS}-icon"></span>`
|
|
);
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property36
|
|
], AxisButton.prototype, "enabled", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/settings-dialog/settingsDialog.ts
|
|
import "ag-charts-community";
|
|
import { EventEmitter as EventEmitter3, focusCursorAtEnd as focusCursorAtEnd2 } from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/components/dialog/dialog.ts
|
|
import { _ModuleSupport as _ModuleSupport62 } from "ag-charts-community";
|
|
import {
|
|
Color as Color5,
|
|
Vec2 as Vec218,
|
|
createButton,
|
|
createCheckbox,
|
|
createElement as createElement4,
|
|
createElementId,
|
|
createSelect,
|
|
createTextArea,
|
|
entries as entries5,
|
|
getIconClassNames as getIconClassNames2,
|
|
getWindow as getWindow2,
|
|
initRovingTabIndex,
|
|
mapValues,
|
|
setAttribute,
|
|
setAttributes as setAttributes2
|
|
} from "ag-charts-core";
|
|
var { DraggablePopover, NativeWidget } = _ModuleSupport62;
|
|
var _Dialog = class _Dialog extends DraggablePopover {
|
|
constructor(ctx, id) {
|
|
super(ctx, id);
|
|
this.dragHandleDraggingClass = "ag-charts-dialog__drag-handle--dragging";
|
|
this.colorPicker = new ColorPicker(this.ctx, { detached: true });
|
|
this.cleanup.register(ctx.eventsHub.on("layout:complete", this.onLayoutComplete.bind(this)));
|
|
}
|
|
showWithChildren(children, options) {
|
|
const popover = super.showWithChildren(children, options);
|
|
popover.classList.add("ag-charts-dialog");
|
|
popover.setAttribute("role", "dialog");
|
|
popover.addEventListener("mousedown", (event) => {
|
|
if (event.target.classList?.contains("ag-charts-dialog__color-picker-button"))
|
|
return;
|
|
this.colorPicker.hide();
|
|
});
|
|
popover.addEventListener("keydown", this.onKeyDown.bind(this));
|
|
getWindow2().requestAnimationFrame(() => this.reposition());
|
|
this.colorPicker.attachTo(this);
|
|
return popover;
|
|
}
|
|
updatePosition(position) {
|
|
super.updatePosition(position);
|
|
const { anchor, fallbackAnchor } = this.getColorPickerAnchors() ?? {};
|
|
if (!anchor)
|
|
return;
|
|
this.colorPicker.setAnchor(anchor, fallbackAnchor);
|
|
}
|
|
/**************
|
|
* Containers *
|
|
**************/
|
|
createTabs(tablistLabel, initial, tabs) {
|
|
const element = createElement4("div", "ag-charts-dialog__tabs");
|
|
const tabButtonIds = mapValues(tabs, () => createElementId());
|
|
const tabPanelIds = mapValues(tabs, () => createElementId());
|
|
for (const [key, tab] of entries5(tabs)) {
|
|
setAttributes2(tab.panel, {
|
|
id: tabPanelIds[key],
|
|
role: "tabpanel",
|
|
"aria-labelledby": tabButtonIds[key]
|
|
});
|
|
}
|
|
const onPressTab = (active) => {
|
|
for (const [key, tab] of entries5(tabs)) {
|
|
tab.panel.classList.toggle("ag-charts-dialog__tab-panel--active", key === active);
|
|
tabButtons[key].classList.toggle("ag-charts-dialog__tab-button--active", key === active);
|
|
setAttribute(tabButtons[key], "aria-selected", key === active);
|
|
if (key === active)
|
|
tab.onShow?.();
|
|
}
|
|
};
|
|
const header = new NativeWidget(createElement4("div", "ag-charts-dialog__header"));
|
|
header.addListener("drag-start", (event) => {
|
|
const { sourceEvent } = event;
|
|
if (sourceEvent.target instanceof Element && sourceEvent.target.classList.contains("ag-charts-dialog__header")) {
|
|
this.onDragStart(event);
|
|
}
|
|
});
|
|
header.addListener("drag-move", (event) => this.onDragMove(event));
|
|
header.addListener("drag-end", () => this.onDragEnd());
|
|
const dragHandle = new DragHandleWidget();
|
|
this.setDragHandle(dragHandle);
|
|
const tabButtons = mapValues(
|
|
tabs,
|
|
(tab, key) => createButton(
|
|
{
|
|
label: this.ctx.localeManager.t(tab.label),
|
|
onPress: () => onPressTab(key)
|
|
},
|
|
{
|
|
id: tabButtonIds[key],
|
|
class: "ag-charts-dialog__tab-button",
|
|
role: "tab",
|
|
"aria-controls": tabPanelIds[key]
|
|
}
|
|
)
|
|
);
|
|
const tabList = createElement4("div", "ag-charts-dialog__tab-list");
|
|
setAttributes2(tabList, { role: "tablist", "aria-label": this.ctx.localeManager.t(tablistLabel) });
|
|
tabList.append(...Object.values(tabButtons));
|
|
const closeButton = this.createHeaderCloseButton();
|
|
header.getElement().append(dragHandle.getElement(), tabList, closeButton);
|
|
element.append(header.getElement(), ...Object.values(tabs).map((t) => t.panel));
|
|
onPressTab(initial);
|
|
initRovingTabIndex({ orientation: "horizontal", buttons: Object.values(tabButtons) });
|
|
return { tabs: element, initialFocus: tabButtons[initial] };
|
|
}
|
|
createTabPanel() {
|
|
return createElement4("div", "ag-charts-dialog__tab-panel");
|
|
}
|
|
/**********
|
|
* Inputs *
|
|
**********/
|
|
createInputGroupLine() {
|
|
return createElement4("div", "ag-charts-dialog__input-group-line");
|
|
}
|
|
createRadioGroup({ label, options, value, onChange }) {
|
|
const group = this.createInputGroup(label);
|
|
setAttributes2(group, {
|
|
role: "radiogroup",
|
|
tabindex: -1,
|
|
"aria-label": this.ctx.localeManager.t(label)
|
|
});
|
|
const activeClass = "ag-charts-dialog__button--active";
|
|
const buttons = [];
|
|
for (const button of options) {
|
|
const { icon, altText: altTextKey } = button;
|
|
const altText = this.ctx.localeManager.t(altTextKey);
|
|
const buttonEl = createButton(
|
|
{
|
|
icon,
|
|
altText,
|
|
onPress: () => {
|
|
for (const b of Array.from(group.children)) {
|
|
b.classList.remove(activeClass);
|
|
b.ariaChecked = "false";
|
|
}
|
|
buttonEl.classList.add(activeClass);
|
|
buttonEl.ariaChecked = "true";
|
|
onChange(button.value);
|
|
}
|
|
},
|
|
{
|
|
"aria-checked": button.value === value,
|
|
class: "ag-charts-dialog__button",
|
|
role: "radio",
|
|
title: altText
|
|
}
|
|
);
|
|
if (button.value === value) {
|
|
buttonEl.classList.add(activeClass);
|
|
}
|
|
group.appendChild(buttonEl);
|
|
buttons.push(buttonEl);
|
|
}
|
|
initRovingTabIndex({ orientation: "horizontal", buttons });
|
|
return group;
|
|
}
|
|
createSelect({ altText, label, options, value, onChange }) {
|
|
const group = this.createInputGroup(label);
|
|
const altTextT = this.ctx.localeManager.t(altText);
|
|
const select = createSelect(
|
|
{ value, options, onChange },
|
|
{ class: "ag-charts-dialog__select", "aria-label": altTextT, title: altTextT }
|
|
);
|
|
group.append(select);
|
|
return group;
|
|
}
|
|
createTextArea({ placeholder, value, onChange }) {
|
|
const placeholderT = placeholder ? this.ctx.localeManager.t(placeholder) : void 0;
|
|
return createTextArea({ value, onChange }, { placeholder: placeholderT });
|
|
}
|
|
createCheckbox({ label, checked, onChange }) {
|
|
const id = createElementId();
|
|
const group = this.createInputGroup(label, { for: id });
|
|
const checkbox = createCheckbox(
|
|
{ checked, onChange },
|
|
{ class: "ag-charts-dialog__checkbox", role: "switch", id }
|
|
);
|
|
group.append(checkbox);
|
|
return group;
|
|
}
|
|
createColorPicker({
|
|
color: color7,
|
|
opacity,
|
|
label,
|
|
altText,
|
|
onChange,
|
|
onChangeHide,
|
|
isMultiColor,
|
|
hasMultiColorOption
|
|
}) {
|
|
const group = this.createInputGroup(label);
|
|
const altTextT = this.ctx.localeManager.t(altText);
|
|
const colorEl = createButton(
|
|
{
|
|
label: altTextT,
|
|
onPress: (event) => {
|
|
const { anchor, fallbackAnchor } = this.getColorPickerAnchors(colorEl) ?? {};
|
|
this.colorPicker.show({
|
|
anchor,
|
|
fallbackAnchor,
|
|
color: color7,
|
|
opacity,
|
|
isMultiColor,
|
|
hasMultiColorOption,
|
|
sourceEvent: event,
|
|
onChange: (newColorOpacity, newColor, newOpacity, newIsMultiColor) => {
|
|
colorEl.style.setProperty("--color", newColorOpacity);
|
|
colorEl.classList.toggle(
|
|
"ag-charts-dialog__color-picker-button--multi-color",
|
|
newIsMultiColor
|
|
);
|
|
onChange(newColorOpacity, newColor, newOpacity, newIsMultiColor);
|
|
},
|
|
onChangeHide
|
|
});
|
|
}
|
|
},
|
|
{
|
|
"aria-label": altTextT,
|
|
tabindex: 0,
|
|
class: "ag-charts-dialog__color-picker-button",
|
|
title: altTextT
|
|
}
|
|
);
|
|
if (isMultiColor) {
|
|
colorEl.classList.toggle("ag-charts-dialog__color-picker-button--multi-color");
|
|
} else if (color7) {
|
|
const hex = Color5.fromString(color7);
|
|
const hexWithOpacity = new Color5(hex.r, hex.g, hex.b, opacity);
|
|
colorEl.style.setProperty("--color", hexWithOpacity.toHexString());
|
|
}
|
|
group.append(colorEl);
|
|
this.hideFns.push(() => {
|
|
this.colorPicker.hide();
|
|
});
|
|
return group;
|
|
}
|
|
/***********
|
|
* Private *
|
|
***********/
|
|
createHeaderCloseButton() {
|
|
return createButton(
|
|
{ icon: "close", altText: this.ctx.localeManager.t("iconAltTextClose"), onPress: () => this.hide() },
|
|
{ class: "ag-charts-dialog__close-button" }
|
|
);
|
|
}
|
|
createInputGroup(label, options) {
|
|
const group = createElement4("div", "ag-charts-dialog__input-group");
|
|
const labelEl = createElement4("label", "ag-charts-dialog__input-group-label");
|
|
labelEl.innerText = this.ctx.localeManager.t(label);
|
|
setAttribute(labelEl, "for", options?.for);
|
|
group.appendChild(labelEl);
|
|
return group;
|
|
}
|
|
onLayoutComplete(event) {
|
|
this.seriesRect = event.series.paddedRect;
|
|
this.reposition();
|
|
}
|
|
onKeyDown(event) {
|
|
if (event.altKey || event.ctrlKey || event.metaKey || event.isComposing || event.key !== "Escape")
|
|
return;
|
|
this.hide();
|
|
}
|
|
reposition() {
|
|
const { seriesRect, ctx } = this;
|
|
const popover = this.getPopoverElement();
|
|
if (!seriesRect || !popover)
|
|
return;
|
|
const clientRect = ctx.domManager.getBoundingClientRect();
|
|
const outerOffset = Vec218.from(0, seriesRect.y);
|
|
const outerSize = Vec218.from(clientRect.width, seriesRect.height);
|
|
const popoverSize = Vec218.from(popover);
|
|
const halfWidth = Vec218.from(0.5, 1);
|
|
let position;
|
|
if (seriesRect.width > 1e3) {
|
|
const bottomCenter = Vec218.sub(
|
|
Vec218.add(outerOffset, Vec218.multiply(outerSize, halfWidth)),
|
|
Vec218.multiply(popoverSize, halfWidth)
|
|
);
|
|
position = Vec218.sub(bottomCenter, Vec218.from(0, _Dialog.offset));
|
|
} else {
|
|
const bottomRight = Vec218.sub(Vec218.add(outerOffset, outerSize), popoverSize);
|
|
position = Vec218.sub(bottomRight, _Dialog.offset);
|
|
}
|
|
this.updatePosition(position);
|
|
}
|
|
getColorPickerAnchors(element) {
|
|
if (element)
|
|
this.colorPickerAnchorElement = element;
|
|
if (!this.colorPickerAnchorElement)
|
|
return;
|
|
const rect = this.colorPickerAnchorElement.getBoundingClientRect();
|
|
const canvasRect = this.ctx.domManager.getBoundingClientRect();
|
|
const topLeft = Vec218.sub(Vec218.from(rect.x, rect.y), Vec218.from(canvasRect.left, canvasRect.top));
|
|
const anchor = Vec218.add(topLeft, Vec218.from(0, rect.height + 5));
|
|
const fallbackAnchor = Vec218.sub(topLeft, Vec218.from(0, 5));
|
|
return { anchor, fallbackAnchor };
|
|
}
|
|
};
|
|
_Dialog.offset = 60;
|
|
var Dialog = _Dialog;
|
|
var DragHandleWidget = class extends NativeWidget {
|
|
constructor() {
|
|
super(createElement4("div", "ag-charts-dialog__drag-handle"));
|
|
const icon = new NativeWidget(createElement4("span", getIconClassNames2("drag-handle")));
|
|
icon.setAriaHidden(true);
|
|
this.addChild(icon);
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/settings-dialog/settingsDialog.ts
|
|
var AnnotationSettingsDialog = class extends Dialog {
|
|
constructor(ctx) {
|
|
super(ctx, "settings");
|
|
this.events = new EventEmitter3();
|
|
this.hideFns.push(() => this.events.emit("hidden", null));
|
|
}
|
|
show(datum, options) {
|
|
const lineTab = this.createLinearLineTab(datum, options);
|
|
const textTab = this.createLinearTextTab(datum, options);
|
|
let lineLabel = "dialogHeaderLine";
|
|
if (isChannelType(datum)) {
|
|
lineLabel = "dialogHeaderChannel";
|
|
} else if (isFibonacciType(datum)) {
|
|
lineLabel = "dialogHeaderFibonacciRange";
|
|
} else if (datum.type === "date-range" /* DateRange */) {
|
|
lineLabel = "dialogHeaderDateRange";
|
|
} else if (datum.type === "price-range" /* PriceRange */) {
|
|
lineLabel = "dialogHeaderPriceRange";
|
|
} else if (datum.type === "date-price-range" /* DatePriceRange */) {
|
|
lineLabel = "dialogHeaderDatePriceRange";
|
|
}
|
|
const { tabs, initialFocus } = this.createTabs("ariaLabelSettingsTabBar", options.initialSelectedTab, {
|
|
line: {
|
|
label: lineLabel,
|
|
panel: lineTab
|
|
},
|
|
text: {
|
|
label: "dialogHeaderText",
|
|
panel: textTab.panel,
|
|
onShow: textTab.onShow
|
|
}
|
|
});
|
|
options.initialFocus = initialFocus;
|
|
const popover = this.showWithChildren([tabs], options);
|
|
popover.classList.add("ag-charts-dialog--annotation-settings");
|
|
}
|
|
createLinearLineTab(datum, options) {
|
|
const panel = this.createTabPanel();
|
|
const groupOne = this.createInputGroupLine();
|
|
const groupTwo = this.createInputGroupLine();
|
|
const hasMultiColorOption = "isMultiColor" in datum;
|
|
const lineColorPicker = this.createColorPickerInput(
|
|
"line-color",
|
|
datum.getDefaultColor("line-color"),
|
|
datum.getDefaultOpacity("line-color"),
|
|
hasMultiColorOption ? datum.isMultiColor : false,
|
|
hasMultiColorOption,
|
|
options.onChangeLineColor,
|
|
options.onChangeHideLineColor
|
|
);
|
|
const strokeWidth = this.createStrokeWidthSelect(datum.strokeWidth ?? 2, options.onChangeLineStyleWidth);
|
|
const lineStyle = this.createLineStyleRadioGroup(datum.lineStyle ?? "solid", options.onChangeLineStyleType);
|
|
groupOne.append(lineColorPicker);
|
|
if ("background" in datum) {
|
|
const fillColorPicker = this.createColorPickerInput(
|
|
"fill-color",
|
|
datum.getDefaultColor("fill-color"),
|
|
datum.getDefaultOpacity("fill-color"),
|
|
false,
|
|
false,
|
|
options.onChangeFillColor,
|
|
options.onChangeHideFillColor
|
|
);
|
|
groupOne.append(fillColorPicker);
|
|
groupTwo.append(strokeWidth);
|
|
} else if ("showFill" in datum) {
|
|
groupOne.append(
|
|
this.createCheckbox({
|
|
label: "dialogInputShowFill",
|
|
checked: datum.showFill ?? true,
|
|
onChange: (showFill) => options.onChangeLine({ showFill })
|
|
})
|
|
);
|
|
groupTwo.append(strokeWidth);
|
|
} else {
|
|
groupOne.append(strokeWidth);
|
|
}
|
|
groupTwo.append(lineStyle);
|
|
panel.append(groupOne, groupTwo);
|
|
if ("bands" in datum) {
|
|
panel.append(
|
|
this.createFibonacciRatioSelect(datum.bands ?? 10, (bands) => options.onChangeLine({ bands }))
|
|
);
|
|
}
|
|
if ("extendStart" in datum && "extendEnd" in datum) {
|
|
panel.append(
|
|
this.createCheckbox({
|
|
label: isChannelType(datum) ? "dialogInputExtendChannelStart" : "dialogInputExtendLineStart",
|
|
checked: datum.extendStart ?? false,
|
|
onChange: (extendStart) => options.onChangeLine({ extendStart })
|
|
}),
|
|
this.createCheckbox({
|
|
label: isChannelType(datum) ? "dialogInputExtendChannelEnd" : "dialogInputExtendLineEnd",
|
|
checked: datum.extendEnd ?? false,
|
|
onChange: (extendEnd) => options.onChangeLine({ extendEnd })
|
|
})
|
|
);
|
|
}
|
|
if ("extendAbove" in datum && "extendBelow" in datum) {
|
|
panel.append(
|
|
this.createCheckbox({
|
|
label: "dialogInputExtendAbove",
|
|
checked: datum.extendAbove ?? false,
|
|
onChange: (extendAbove) => options.onChangeLine({ extendAbove })
|
|
}),
|
|
this.createCheckbox({
|
|
label: "dialogInputExtendBelow",
|
|
checked: datum.extendBelow ?? false,
|
|
onChange: (extendBelow) => options.onChangeLine({ extendBelow })
|
|
})
|
|
);
|
|
}
|
|
if ("extendLeft" in datum && "extendRight" in datum) {
|
|
panel.append(
|
|
this.createCheckbox({
|
|
label: "dialogInputExtendLeft",
|
|
checked: datum.extendLeft ?? false,
|
|
onChange: (extendLeft) => options.onChangeLine({ extendLeft })
|
|
}),
|
|
this.createCheckbox({
|
|
label: "dialogInputExtendRight",
|
|
checked: datum.extendRight ?? false,
|
|
onChange: (extendRight) => options.onChangeLine({ extendRight })
|
|
})
|
|
);
|
|
}
|
|
if ("reverse" in datum && "showFill" in datum) {
|
|
panel.append(
|
|
this.createCheckbox({
|
|
label: "dialogInputReverse",
|
|
checked: datum.reverse ?? false,
|
|
onChange: (reverse) => options.onChangeLine({ reverse })
|
|
})
|
|
);
|
|
}
|
|
return panel;
|
|
}
|
|
createLinearTextTab(datum, options) {
|
|
const panel = this.createTabPanel();
|
|
const textArea = this.createTextArea({
|
|
placeholder: "inputTextareaPlaceholder",
|
|
value: datum.text.label,
|
|
onChange: (value) => options.onChangeText({ label: value })
|
|
});
|
|
const fontSize = this.createFontSizeSelect(datum.text.fontSize, options.onChangeTextFontSize);
|
|
const colorPicker = this.createColorPickerInput(
|
|
"text-color",
|
|
datum.text.color,
|
|
1,
|
|
false,
|
|
false,
|
|
options.onChangeTextColor,
|
|
options.onChangeHideTextColor
|
|
);
|
|
const textPosition = datum.text.position === "inside" ? "center" : datum.text.position;
|
|
const position = this.createPositionRadioGroup(
|
|
textPosition ?? "top",
|
|
(value) => options.onChangeText({ position: value })
|
|
);
|
|
const alignment = this.createAlignmentRadioGroup(
|
|
datum.text.alignment ?? "center",
|
|
(value) => options.onChangeText({ alignment: value })
|
|
);
|
|
const inputGroupLine = this.createInputGroupLine();
|
|
inputGroupLine.append(fontSize, colorPicker, position, alignment);
|
|
panel.append(textArea, inputGroupLine);
|
|
return { panel, onShow: () => focusCursorAtEnd2(textArea) };
|
|
}
|
|
createColorPickerInput(colorType, color7, opacity, isMultiColor, hasMultiColorOption, onChange, onChangeHide) {
|
|
const label = colorType === "fill-color" ? "dialogInputFillColorPicker" : "dialogInputColorPicker";
|
|
const altText = colorType === "fill-color" ? "dialogInputFillColorPickerAltText" : "dialogInputColorPickerAltText";
|
|
return this.createColorPicker({
|
|
label,
|
|
altText,
|
|
color: color7,
|
|
opacity,
|
|
isMultiColor,
|
|
hasMultiColorOption,
|
|
onChange,
|
|
onChangeHide
|
|
});
|
|
}
|
|
createStrokeWidthSelect(strokeWidth, onChange) {
|
|
return this.createSelect({
|
|
label: "dialogInputStrokeWidth",
|
|
altText: "dialogInputStrokeWidthAltText",
|
|
options: LINE_STROKE_WIDTH_ITEMS.map(({ label, value }) => ({ label, value: `${value}` })),
|
|
value: String(strokeWidth),
|
|
onChange: (value) => onChange(Number(value))
|
|
});
|
|
}
|
|
createFibonacciRatioSelect(bands, onChange) {
|
|
return this.createSelect({
|
|
label: "dialogInputFibonacciBands",
|
|
altText: "dialogInputFibonacciBandsAltText",
|
|
options: FIBONACCI_RATIO_ITEMS.map(({ label, value }) => ({ label, value: `${value}` })),
|
|
value: String(bands),
|
|
onChange: (value) => onChange(Number(value))
|
|
});
|
|
}
|
|
createLineStyleRadioGroup(lineStyle, onChange) {
|
|
return this.createRadioGroup({
|
|
label: "dialogInputLineStyle",
|
|
options: [
|
|
{ icon: "line-style-solid", altText: "iconAltTextLineStyleSolid", value: "solid" },
|
|
{ icon: "line-style-dashed", altText: "iconAltTextLineStyleDashed", value: "dashed" },
|
|
{ icon: "line-style-dotted", altText: "iconAltTextLineStyleDotted", value: "dotted" }
|
|
],
|
|
value: lineStyle,
|
|
onChange
|
|
});
|
|
}
|
|
createFontSizeSelect(fontSize, onChange) {
|
|
return this.createSelect({
|
|
label: "dialogInputFontSize",
|
|
altText: "dialogInputFontSizeAltText",
|
|
options: TEXT_SIZE_ITEMS.map(({ label, value }) => ({ label, value: String(value) })),
|
|
value: String(fontSize),
|
|
onChange: (value) => onChange(Number(value))
|
|
});
|
|
}
|
|
createPositionRadioGroup(position, onChange) {
|
|
return this.createRadioGroup({
|
|
label: "dialogInputPosition",
|
|
options: [
|
|
{ icon: "position-top", altText: "iconAltTextPositionTop", value: "top" },
|
|
{ icon: "position-center", altText: "iconAltTextPositionCenter", value: "center" },
|
|
{ icon: "position-bottom", altText: "iconAltTextPositionBottom", value: "bottom" }
|
|
],
|
|
value: position,
|
|
onChange
|
|
});
|
|
}
|
|
createAlignmentRadioGroup(alignment, onChange) {
|
|
return this.createRadioGroup({
|
|
label: "dialogInputAlign",
|
|
options: [
|
|
{ icon: "align-left", altText: "iconAltTextAlignLeft", value: "left" },
|
|
{ icon: "align-center", altText: "iconAltTextAlignCenter", value: "center" },
|
|
{ icon: "align-right", altText: "iconAltTextAlignRight", value: "right" }
|
|
],
|
|
value: alignment,
|
|
onChange
|
|
});
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/utils/axis.ts
|
|
function calculateAxisLabelPadding(axisLayout) {
|
|
return axisLayout.gridPadding + axisLayout.seriesAreaPadding + axisLayout.tickSize + axisLayout.label.spacing;
|
|
}
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/utils/update.ts
|
|
function updateAnnotation(node, datum, context) {
|
|
for (const { update } of Object.values(annotationConfigs)) {
|
|
update(node, datum, context);
|
|
}
|
|
}
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/annotations.ts
|
|
var { InteractionState: InteractionState2, keyProperty, valueProperty, Selection: Selection3, BBox: BBox3 } = _ModuleSupport64;
|
|
var _Annotations = class _Annotations extends AbstractModuleInstance4 {
|
|
constructor(ctx) {
|
|
super();
|
|
this.ctx = ctx;
|
|
this.toolbar = new AnnotationsToolbar(this.ctx);
|
|
this.optionsToolbar = new AnnotationOptionsToolbar(this.ctx, () => {
|
|
const active = this.state.getActive();
|
|
if (active == null)
|
|
return;
|
|
return getTypedDatum(this.annotationData.at(active));
|
|
});
|
|
this.axesButtons = new AxesButtons();
|
|
this.enabled = true;
|
|
this.snap = false;
|
|
// Hidden options for use with measurer statistics
|
|
this.data = void 0;
|
|
this.xKey = void 0;
|
|
this.volumeKey = void 0;
|
|
this.annotationData = new PropertiesArray3(
|
|
_Annotations.createAnnotationDatum
|
|
);
|
|
this.defaults = new AnnotationDefaults();
|
|
this.container = new _ModuleSupport64.Group({ name: "static-annotations" });
|
|
this.annotations = new Selection3(
|
|
this.container,
|
|
this.createAnnotationScene.bind(this)
|
|
);
|
|
this.settingsDialog = new AnnotationSettingsDialog(this.ctx);
|
|
this.textInput = new TextInput(this.ctx);
|
|
this.postUpdateFns = [];
|
|
this.state = this.setupStateMachine();
|
|
this.setupListeners();
|
|
this.setupDOM();
|
|
this.ctx.historyManager.addMementoOriginator(ctx.annotationManager);
|
|
this.ctx.historyManager.addMementoOriginator(this.defaults);
|
|
this.textInput.setKeyDownHandler(this.onTextInput.bind(this));
|
|
this.cleanup.register(() => {
|
|
this.clear();
|
|
this.xAxis?.button?.destroy();
|
|
this.yAxis?.button?.destroy();
|
|
this.textInput.destroy();
|
|
});
|
|
}
|
|
setupStateMachine() {
|
|
const { ctx } = this;
|
|
return new AnnotationsStateMachine({
|
|
resetToIdle: () => {
|
|
ctx.domManager.updateCursor("annotations");
|
|
this.popAnnotationState(InteractionState2.Annotations);
|
|
this.hideOverlays();
|
|
this.optionsToolbar.hide();
|
|
this.deleteEphemeralAnnotations();
|
|
this.update();
|
|
},
|
|
hoverAtCoords: (coords, active, previousHovered) => {
|
|
let hovered;
|
|
this.annotations.each((annotation, datum, index) => {
|
|
if (!datum.isHoverable())
|
|
return;
|
|
const contains = annotation.containsPoint(coords.x, coords.y);
|
|
if (contains)
|
|
hovered ?? (hovered = index);
|
|
annotation.toggleHovered(contains, active === index, datum.readOnly);
|
|
});
|
|
if (hovered != null) {
|
|
ctx.tooltipManager.suppressTooltip("annotations");
|
|
} else if (!this.isAnnotationState()) {
|
|
ctx.tooltipManager.unsuppressTooltip("annotations");
|
|
}
|
|
if (hovered == null || !this.annotationData.at(hovered)?.readOnly) {
|
|
this.ctx.domManager.updateCursor(
|
|
"annotations",
|
|
hovered == null ? void 0 : this.annotations.at(hovered)?.getCursor()
|
|
);
|
|
}
|
|
if (hovered !== previousHovered) {
|
|
this.update();
|
|
}
|
|
return hovered;
|
|
},
|
|
getNodeAtCoords: (coords, active) => {
|
|
const node = this.annotations.at(active);
|
|
if (!node) {
|
|
return;
|
|
}
|
|
return node.getNodeAtCoords(coords.x, coords.y);
|
|
},
|
|
translate: (index, translation) => {
|
|
const node = this.annotations.at(index);
|
|
const datum = getTypedDatum(this.annotationData.at(index));
|
|
if (!node || !datum) {
|
|
return;
|
|
}
|
|
return this.translateNode(node, datum, translation);
|
|
},
|
|
copy: (index) => {
|
|
const node = this.annotations.at(index);
|
|
const datum = getTypedDatum(this.annotationData.at(index));
|
|
if (!node || !datum) {
|
|
return;
|
|
}
|
|
return this.createAnnotationDatumCopy(node, datum);
|
|
},
|
|
paste: (datum) => {
|
|
this.createAnnotation(datum.type, datum, false);
|
|
this.postUpdateFns.push(() => {
|
|
this.state.transitionAsync("selectLast");
|
|
this.state.transitionAsync("copy");
|
|
});
|
|
},
|
|
select: (index, previous) => {
|
|
const { annotations, optionsToolbar: optionsToolbar2, toolbar: toolbar2 } = this;
|
|
this.hideOverlays();
|
|
toolbar2.clearActiveButton();
|
|
toolbar2.resetButtonIcons();
|
|
const selectedNode = index == null ? null : annotations.at(index);
|
|
const previousNode = previous == null ? null : annotations.at(previous);
|
|
const selectedDatum = index == null ? null : this.annotationData.at(index);
|
|
if (previousNode === selectedNode && selectedNode != null) {
|
|
return;
|
|
}
|
|
previousNode?.toggleActive(false);
|
|
optionsToolbar2.hide();
|
|
if (selectedNode && !selectedDatum?.readOnly) {
|
|
this.pushAnnotationState(InteractionState2.AnnotationsSelected);
|
|
selectedNode.toggleActive(true);
|
|
if (!isEphemeralType(selectedDatum)) {
|
|
optionsToolbar2.updateButtons(this.annotationData.at(index));
|
|
this.postUpdateFns.push(() => {
|
|
optionsToolbar2.show();
|
|
optionsToolbar2.setAnchorScene(selectedNode);
|
|
});
|
|
}
|
|
} else {
|
|
this.popAnnotationState(InteractionState2.AnnotationsSelected);
|
|
this.popAnnotationState(InteractionState2.Annotations);
|
|
}
|
|
if (!isEphemeralType(selectedDatum)) {
|
|
this.deleteEphemeralAnnotations();
|
|
}
|
|
this.update();
|
|
},
|
|
selectLast: () => {
|
|
this.pushAnnotationState(InteractionState2.AnnotationsSelected);
|
|
return this.annotationData.length - 1;
|
|
},
|
|
startInteracting: () => {
|
|
this.pushAnnotationState(InteractionState2.Annotations);
|
|
},
|
|
stopInteracting: () => {
|
|
this.popAnnotationState(InteractionState2.Annotations);
|
|
},
|
|
create: (type, datum) => {
|
|
this.createAnnotation(type, datum);
|
|
},
|
|
delete: (index) => {
|
|
this.annotationData.splice(index, 1);
|
|
},
|
|
deleteAll: () => {
|
|
const readOnly = this.annotationData.filter((datum) => {
|
|
if (datum.readOnly === true)
|
|
return datum;
|
|
});
|
|
this.annotationData.splice(0, this.annotationData.length);
|
|
for (const datum of readOnly) {
|
|
this.annotationData.push(datum);
|
|
}
|
|
},
|
|
validatePoint: (point, options) => {
|
|
const context = this.getAnnotationContext();
|
|
return context ? validateDatumPoint(context, point, options) : true;
|
|
},
|
|
getAnnotationType: (index) => {
|
|
return stringToAnnotationType(this.annotationData[index].type);
|
|
},
|
|
datum: (index) => {
|
|
return this.annotationData.at(index);
|
|
},
|
|
node: (index) => {
|
|
return this.annotations.at(index);
|
|
},
|
|
recordAction: (label) => {
|
|
this.recordActionAfterNextUpdate(label);
|
|
},
|
|
update: () => {
|
|
this.postUpdateFns.push(() => {
|
|
const active = this.state.getActive();
|
|
const node = active == null ? null : this.annotations.at(active);
|
|
if (node == null)
|
|
return;
|
|
this.optionsToolbar.setAnchorScene(node);
|
|
});
|
|
this.update();
|
|
},
|
|
showTextInput: (active) => {
|
|
const datum = getTypedDatum(this.annotationData.at(active));
|
|
const node = this.annotations.at(active);
|
|
if (!node || !datum || !("getTextInputCoords" in datum) || !("getTextPosition" in datum))
|
|
return;
|
|
const styles = {
|
|
color: datum.color,
|
|
fontFamily: datum.fontFamily,
|
|
fontSize: datum.fontSize,
|
|
fontStyle: datum.fontStyle,
|
|
fontWeight: datum.fontWeight,
|
|
placeholderColor: datum.getPlaceholderColor()
|
|
};
|
|
const context = this.getAnnotationContext();
|
|
const getTextInputCoords = (height) => Vec219.add(datum.getTextInputCoords(context, height), Vec219.required(this.seriesRect));
|
|
const getTextPosition = () => datum.getTextPosition();
|
|
this.textInput.show({
|
|
styles,
|
|
layout: {
|
|
getTextInputCoords,
|
|
getTextPosition,
|
|
alignment: datum.alignment,
|
|
textAlign: datum.textAlign,
|
|
width: datum.width
|
|
},
|
|
text: datum.text,
|
|
placeholderText: datum.placeholderText,
|
|
onChange: (_text, bbox) => {
|
|
this.state.transition("updateTextInputBBox", bbox);
|
|
}
|
|
});
|
|
this.ctx.domManager.updateCursor("annotations");
|
|
},
|
|
hideTextInput: () => {
|
|
this.textInput.hide();
|
|
},
|
|
updateTextInputColor: (color7) => {
|
|
this.textInput.updateColor(color7);
|
|
},
|
|
updateTextInputFontSize: (fontSize) => {
|
|
const bbox = this.textInput.updateFontSize(fontSize);
|
|
this.state.transition("updateTextInputBBox", bbox);
|
|
},
|
|
updateTextInputBBox: (bbox) => {
|
|
this.state.transition("updateTextInputBBox", bbox);
|
|
},
|
|
showAnnotationOptions: (active) => {
|
|
const node = this.annotations.at(active);
|
|
if (!node || isEphemeralType(this.annotationData.at(active)))
|
|
return;
|
|
this.optionsToolbar.updateButtons(this.annotationData.at(active));
|
|
this.optionsToolbar.show();
|
|
this.optionsToolbar.setAnchorScene(node);
|
|
},
|
|
showAnnotationSettings: (active, sourceEvent, initialTab = "line") => {
|
|
const datum = this.annotationData.at(active);
|
|
if (!isLineType(datum) && !isChannelType(datum) && !isMeasurerType(datum))
|
|
return;
|
|
if (isEphemeralType(datum))
|
|
return;
|
|
const onChangeColor = (colorType) => (colorOpacity, color7, opacity, isMultiColor) => {
|
|
this.setColorAndDefault(datum.type, colorType, colorOpacity, color7, opacity, isMultiColor);
|
|
this.optionsToolbar.updateColorPickerColor(colorType, color7, opacity, isMultiColor);
|
|
};
|
|
const onChangeHideColor = (colorType) => () => {
|
|
this.recordActionAfterNextUpdate(
|
|
`Change ${datum.type} ${colorType} to ${datum.getDefaultColor(colorType)}`,
|
|
["annotations", "defaults"]
|
|
);
|
|
this.update();
|
|
};
|
|
const options = {
|
|
initialSelectedTab: initialTab,
|
|
ariaLabel: this.ctx.localeManager.t("ariaLabelAnnotationSettingsDialog"),
|
|
sourceEvent,
|
|
onChangeLine: (props) => {
|
|
this.state.transition("lineProps", props);
|
|
if (props.bands != null)
|
|
this.defaults.setDefaultFibonacciOptions(datum.type, "bands", props.bands);
|
|
if (props.reverse != null)
|
|
this.defaults.setDefaultFibonacciOptions(datum.type, "reverse", props.reverse);
|
|
if (props.showFill != null)
|
|
this.defaults.setDefaultFibonacciOptions(datum.type, "showFill", props.showFill);
|
|
},
|
|
onChangeText: (props) => {
|
|
this.state.transition("lineText", props);
|
|
if (props.alignment)
|
|
this.defaults.setDefaultLineTextAlignment(datum.type, props.alignment);
|
|
if (props.position)
|
|
this.defaults.setDefaultLineTextPosition(datum.type, props.position);
|
|
this.recordActionAfterNextUpdate(
|
|
`Change ${datum.type} text ${Object.keys(props).map((key) => `${key} to ${props[key]}`).join(", ")}`
|
|
);
|
|
},
|
|
onChangeFillColor: onChangeColor("fill-color"),
|
|
onChangeHideFillColor: onChangeHideColor("fill-color"),
|
|
onChangeLineColor: onChangeColor("line-color"),
|
|
onChangeHideLineColor: onChangeHideColor("line-color"),
|
|
onChangeLineStyleType: (lineStyleType) => {
|
|
this.setLineStyleTypeAndDefault(datum.type, lineStyleType);
|
|
this.optionsToolbar.updateLineStyleType(
|
|
LINE_STYLE_TYPE_ITEMS.find((item) => item.value === lineStyleType) ?? LINE_STYLE_TYPE_ITEMS[0]
|
|
);
|
|
},
|
|
onChangeLineStyleWidth: (strokeWidth) => {
|
|
this.setLineStyleWidthAndDefault(datum.type, strokeWidth);
|
|
this.optionsToolbar.updateStrokeWidth({
|
|
strokeWidth,
|
|
value: strokeWidth,
|
|
label: String(strokeWidth)
|
|
});
|
|
},
|
|
onChangeTextColor: onChangeColor("text-color"),
|
|
onChangeHideTextColor: onChangeHideColor("text-color"),
|
|
onChangeTextFontSize: (fontSize) => {
|
|
this.setFontSizeAndDefault(datum.type, fontSize);
|
|
}
|
|
};
|
|
this.settingsDialog.show(datum, options);
|
|
}
|
|
});
|
|
}
|
|
setupListeners() {
|
|
const { ctx, optionsToolbar: optionsToolbar2, settingsDialog, toolbar: toolbar2 } = this;
|
|
const { seriesWidget, seriesDragInterpreter, chartWidget } = ctx.widgets;
|
|
if (seriesDragInterpreter) {
|
|
this.cleanup.register(
|
|
// Interactions
|
|
seriesDragInterpreter.events.on("click", this.hoverTouchPreHandler.bind(this)),
|
|
seriesDragInterpreter.events.on("drag-start", this.hoverTouchPreHandler.bind(this)),
|
|
seriesDragInterpreter.events.on("drag-move", this.dragMoveTouchPreHandler.bind(this)),
|
|
seriesDragInterpreter.events.on("mousemove", this.onHover.bind(this)),
|
|
seriesDragInterpreter.events.on("click", this.onClick.bind(this)),
|
|
seriesDragInterpreter.events.on("dblclick", this.onDoubleClick.bind(this)),
|
|
seriesDragInterpreter.events.on("drag-start", this.onDragStart.bind(this)),
|
|
seriesDragInterpreter.events.on("drag-move", this.onDrag.bind(this)),
|
|
seriesDragInterpreter.events.on("drag-end", this.onDragEnd.bind(this))
|
|
);
|
|
}
|
|
this.cleanup.register(
|
|
// Interactions
|
|
seriesWidget.addListener("keydown", this.onKeyDown.bind(this)),
|
|
seriesWidget.addListener("keyup", this.onKeyUp.bind(this)),
|
|
chartWidget.addListener("click", this.onCancel.bind(this)),
|
|
// Services
|
|
ctx.eventsHub.on("annotations:restore", this.onRestoreAnnotations.bind(this)),
|
|
ctx.eventsHub.on("layout:complete", this.onLayoutComplete.bind(this)),
|
|
ctx.updateService.addListener("pre-scene-render", this.onPreRender.bind(this)),
|
|
ctx.eventsHub.on("zoom:change-complete", () => this.onResize()),
|
|
ctx.eventsHub.on("dom:resize", () => this.onResize()),
|
|
// Toolbar
|
|
toolbar2.events.on("cancel-create-annotation", () => {
|
|
this.cancel();
|
|
this.reset();
|
|
this.update();
|
|
}),
|
|
toolbar2.events.on("pressed-create-annotation", ({ annotation }) => {
|
|
this.cancel();
|
|
this.pushAnnotationState(InteractionState2.Annotations);
|
|
this.state.transition(annotation);
|
|
this.update();
|
|
}),
|
|
toolbar2.events.on("pressed-clear", () => {
|
|
this.clear();
|
|
this.recordActionAfterNextUpdate("Clear all");
|
|
}),
|
|
toolbar2.events.on("pressed-show-menu", () => {
|
|
this.cancel();
|
|
this.reset();
|
|
}),
|
|
toolbar2.events.on("pressed-unrelated", () => {
|
|
this.reset();
|
|
}),
|
|
// Annotation Options Toolbar
|
|
optionsToolbar2.events.on("pressed-delete", () => {
|
|
this.cancel();
|
|
this.delete();
|
|
this.reset();
|
|
}),
|
|
optionsToolbar2.events.on("pressed-settings", ({ sourceEvent }) => {
|
|
this.state.transition("toolbarPressSettings", sourceEvent);
|
|
}),
|
|
optionsToolbar2.events.on("pressed-lock", ({ locked }) => {
|
|
this.recordActionAfterNextUpdate(locked ? "Locked" : "Unlocked");
|
|
this.update();
|
|
}),
|
|
optionsToolbar2.events.on("hid-overlays", () => {
|
|
this.settingsDialog.hide();
|
|
}),
|
|
optionsToolbar2.events.on("saved-color", ({ type, colorPickerType, color: color7 }) => {
|
|
this.recordActionAfterNextUpdate(`Change ${type} ${colorPickerType} to ${color7}`, [
|
|
"annotations",
|
|
"defaults"
|
|
]);
|
|
}),
|
|
optionsToolbar2.events.on(
|
|
"updated-color",
|
|
({ type, colorPickerType, colorOpacity, color: color7, opacity, isMultiColor }) => {
|
|
this.setColorAndDefault(type, colorPickerType, colorOpacity, color7, opacity, isMultiColor);
|
|
}
|
|
),
|
|
optionsToolbar2.events.on("updated-font-size", ({ type, fontSize }) => {
|
|
this.setFontSizeAndDefault(type, fontSize);
|
|
}),
|
|
optionsToolbar2.events.on("updated-line-style", ({ type, lineStyleType }) => {
|
|
this.setLineStyleTypeAndDefault(type, lineStyleType);
|
|
}),
|
|
optionsToolbar2.events.on("updated-line-width", ({ type, strokeWidth }) => {
|
|
this.setLineStyleWidthAndDefault(type, strokeWidth);
|
|
}),
|
|
// Settings Dialog
|
|
settingsDialog.events.on("hidden", () => {
|
|
this.optionsToolbar.clearActiveButton();
|
|
})
|
|
);
|
|
}
|
|
setupDOM() {
|
|
const { ctx, toolbar: toolbar2, optionsToolbar: optionsToolbar2 } = this;
|
|
this.cleanup.register(ctx.annotationManager.attachNode(this.container), () => {
|
|
ctx.domManager.removeStyles(DEFAULT_ANNOTATION_AXIS_BUTTON_CLASS);
|
|
toolbar2.destroy();
|
|
optionsToolbar2.destroy();
|
|
});
|
|
}
|
|
async processData(dataController) {
|
|
if (!this.enabled || this.data == null || this.xKey == null || this.volumeKey == null)
|
|
return;
|
|
const props = [
|
|
keyProperty(this.xKey, void 0, { id: "date" }),
|
|
valueProperty(this.volumeKey, "number", { id: "volume" })
|
|
];
|
|
const dataSet = _ModuleSupport64.DataSet.wrap(this.data) ?? _ModuleSupport64.DataSet.empty();
|
|
const { dataModel, processedData } = await dataController.request("annotations", dataSet, {
|
|
props
|
|
});
|
|
this.dataModel = dataModel;
|
|
this.processedData = processedData;
|
|
}
|
|
/**
|
|
* Create an annotation scene within the `this.annotations` scene selection. This method is automatically called by
|
|
* the selection when a new scene is required.
|
|
*/
|
|
createAnnotationScene(datum) {
|
|
if (datum.type in annotationConfigs) {
|
|
return new annotationConfigs[datum.type].scene();
|
|
}
|
|
throw new Error(
|
|
`AG Charts - Cannot create annotation scene of type [${datum.type}], expected one of [${Object.keys(annotationConfigs)}], ignoring.`
|
|
);
|
|
}
|
|
/**
|
|
* Create an annotation datum within the `this.annotationData` properties array. It is created as an instance
|
|
* of `AnnotationProperties` from the given config for its type. This method is only called when annotations
|
|
* are added from the initial state.
|
|
*/
|
|
static createAnnotationDatum(params) {
|
|
if (params.type in annotationConfigs) {
|
|
return new annotationConfigs[params.type].datum().set(params);
|
|
}
|
|
throw new Error(
|
|
`AG Charts - Cannot create annotation datum of unknown type [${params.type}], expected one of [${Object.keys(annotationConfigs)}], ignoring.`
|
|
);
|
|
}
|
|
/**
|
|
* Append an annotation datum to `this.annotationData`, applying default styles. This method is called when a user
|
|
* interacts with the chart to draw their own annotations.
|
|
*/
|
|
createAnnotation(type, datum, applyDefaults = true) {
|
|
this.annotationData.push(datum);
|
|
if (applyDefaults) {
|
|
const styles = this.ctx.annotationManager.getAnnotationTypeStyles(type);
|
|
if (styles)
|
|
datum.set(styles);
|
|
this.defaults.applyDefaults(datum);
|
|
}
|
|
this.injectDatumDependencies(datum);
|
|
this.update();
|
|
}
|
|
injectDatumDependencies(datum) {
|
|
if ("setLocaleManager" in datum) {
|
|
datum.setLocaleManager(this.ctx.localeManager);
|
|
}
|
|
if ("getVolume" in datum) {
|
|
datum.getVolume = this.getDatumRangeVolume.bind(this);
|
|
}
|
|
}
|
|
getDatumRangeVolume(fromPoint, toPoint) {
|
|
const { dataModel, processedData } = this;
|
|
let from = getGroupingValue(fromPoint);
|
|
let to = getGroupingValue(toPoint);
|
|
if (!isValidDate(from) || !isValidDate(to) || !dataModel || !processedData || this.volumeKey == null)
|
|
return;
|
|
if (from > to) {
|
|
[from, to] = [to, from];
|
|
}
|
|
const dateValues = dataModel.resolveKeysById({ id: "annotations" }, "date", processedData);
|
|
const volumeValues = dataModel.resolveColumnById({ id: "annotations" }, "volume", processedData);
|
|
let sum = 0;
|
|
for (let datumIndex = 0; datumIndex < processedData.input.count; datumIndex++) {
|
|
const key = dateValues[datumIndex];
|
|
if (isValidDate(key) && key >= from && key <= to) {
|
|
sum += volumeValues[datumIndex];
|
|
}
|
|
}
|
|
return sum;
|
|
}
|
|
translateNode(node, datum, translation) {
|
|
const config = this.getAnnotationConfig(datum);
|
|
const context = this.getAnnotationContext();
|
|
if (!context) {
|
|
return;
|
|
}
|
|
config.translate(node, datum, translation, context);
|
|
}
|
|
createAnnotationDatumCopy(node, datum) {
|
|
const config = this.getAnnotationConfig(datum);
|
|
const newDatum = new config.datum();
|
|
newDatum.set(datum.toJson());
|
|
const context = this.getAnnotationContext();
|
|
if (!context) {
|
|
return;
|
|
}
|
|
return config.copy(node, datum, newDatum, context);
|
|
}
|
|
getAnnotationConfig(datum) {
|
|
if (datum.type in annotationConfigs) {
|
|
return annotationConfigs[datum.type];
|
|
}
|
|
throw new Error(
|
|
`AG Charts - Cannot get annotation config of unknown type [${datum.type}], expected one of [${Object.keys(annotationConfigs)}], ignoring.`
|
|
);
|
|
}
|
|
onRestoreAnnotations(event) {
|
|
if (!this.enabled)
|
|
return;
|
|
this.clear();
|
|
this.annotationData.set(event.annotations);
|
|
this.postUpdateFns.push(() => {
|
|
this.ctx.annotationManager.fireChangedEvent();
|
|
});
|
|
this.update();
|
|
}
|
|
onLayoutComplete(event) {
|
|
if (!this.enabled)
|
|
return;
|
|
const seriesRect = event.series.paddedRect;
|
|
this.seriesRect = seriesRect;
|
|
this.container.setClipRect(seriesRect);
|
|
this.xAxis = this.getAxis(event.axes[ChartAxisDirection9.X], seriesRect, this.xAxis?.button);
|
|
this.yAxis = this.getAxis(event.axes[ChartAxisDirection9.Y], seriesRect, this.yAxis?.button);
|
|
if (this.showAnnotations()) {
|
|
this.animateAnnotations({ from: 0, to: 1, phase: "trailing" });
|
|
} else {
|
|
this.animateAnnotations({ from: 1, to: 0, phase: "remove" });
|
|
}
|
|
}
|
|
showAnnotations() {
|
|
if (!this.yAxis || !this.xAxis) {
|
|
return false;
|
|
}
|
|
const hasData = this.ctx.chartService.series.some((s) => s.hasData);
|
|
const seriesIds = this.yAxis.context.seriesIds();
|
|
const anyBoundSeriesVisible = seriesIds.some((id) => {
|
|
const series = this.ctx.chartService.series.find((s) => s.id === id);
|
|
return series?.visible;
|
|
});
|
|
return hasData && anyBoundSeriesVisible;
|
|
}
|
|
animateAnnotations({ from, to, phase }) {
|
|
const { annotations } = this;
|
|
this.ctx.animationManager?.animate({
|
|
from,
|
|
to,
|
|
id: "chart-annotations",
|
|
phase,
|
|
groupId: "opacity",
|
|
onUpdate(value) {
|
|
annotations.each((node) => {
|
|
node.opacity = value;
|
|
if ("setAxisLabelOpacity" in node) {
|
|
node.setAxisLabelOpacity(value);
|
|
}
|
|
});
|
|
},
|
|
onStop() {
|
|
annotations.each((node) => {
|
|
node.opacity = to;
|
|
if ("setAxisLabelOpacity" in node) {
|
|
node.setAxisLabelOpacity(to);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
}
|
|
onPreRender() {
|
|
if (!this.enabled)
|
|
return;
|
|
this.updateAnnotations();
|
|
this.state.transition("render");
|
|
}
|
|
getAxis(axisLayout, seriesRect, button) {
|
|
const axisCtx = this.ctx.axisManager.getAxisContext(axisLayout.direction)[0];
|
|
const { position: axisPosition = "bottom", direction } = axisCtx;
|
|
const padding2 = axisLayout.gridPadding + axisLayout.seriesAreaPadding;
|
|
const bounds = new BBox3(0, 0, seriesRect.width, seriesRect.height).grow(padding2, axisPosition);
|
|
const lineDirection = direction === ChartAxisDirection9.X ? "vertical" : "horizontal";
|
|
const { axesButtons, snap } = this;
|
|
const buttonEnabled = this.enabled && axesButtons.enabled && (axesButtons.axes === "xy" || axesButtons.axes === direction);
|
|
if (buttonEnabled) {
|
|
button ?? (button = new AxisButton(
|
|
this.ctx,
|
|
{ ...axisCtx, snapToGroup: snap },
|
|
(coords) => this.onAxisButtonClick(coords, lineDirection),
|
|
seriesRect
|
|
));
|
|
const axisLabelPadding = calculateAxisLabelPadding(axisLayout);
|
|
button.update(seriesRect, axisLabelPadding);
|
|
} else {
|
|
button?.destroy();
|
|
button = void 0;
|
|
}
|
|
return { layout: axisLayout, context: axisCtx, bounds, button };
|
|
}
|
|
recordActionAfterNextUpdate(label, types = ["annotations"]) {
|
|
const {
|
|
defaults,
|
|
ctx: { annotationManager, historyManager }
|
|
} = this;
|
|
const originators = types.map((type) => type === "defaults" ? defaults : annotationManager);
|
|
this.postUpdateFns.push(() => {
|
|
historyManager.record(label, ...originators);
|
|
annotationManager.fireChangedEvent();
|
|
});
|
|
}
|
|
setColorAndDefault(datumType, colorPickerType, colorOpacity, color7, opacity, isMultiColor) {
|
|
this.state.transition("color", { colorPickerType, colorOpacity, color: color7, opacity, isMultiColor });
|
|
this.defaults.setDefaultColor(datumType, colorPickerType, colorOpacity, color7, opacity, isMultiColor);
|
|
}
|
|
setFontSizeAndDefault(datumType, fontSize) {
|
|
this.state.transition("fontSize", fontSize);
|
|
this.defaults.setDefaultFontSize(datumType, fontSize);
|
|
this.recordActionAfterNextUpdate(`Change ${datumType} font size to ${fontSize}`, ["annotations", "defaults"]);
|
|
}
|
|
setLineStyleTypeAndDefault(datumType, styleType) {
|
|
this.state.transition("lineStyle", { type: styleType });
|
|
this.defaults.setDefaultLineStyleType(datumType, styleType);
|
|
this.recordActionAfterNextUpdate(`Change ${datumType} line style to ${styleType}`, ["annotations", "defaults"]);
|
|
}
|
|
setLineStyleWidthAndDefault(datumType, strokeWidth) {
|
|
this.state.transition("lineStyle", { strokeWidth });
|
|
this.defaults.setDefaultLineStyleWidth(datumType, strokeWidth);
|
|
this.recordActionAfterNextUpdate(`Change ${datumType} stroke width to ${strokeWidth}`, [
|
|
"annotations",
|
|
"defaults"
|
|
]);
|
|
}
|
|
updateAnnotations() {
|
|
const {
|
|
annotationData,
|
|
annotations,
|
|
seriesRect,
|
|
ctx: { annotationManager }
|
|
} = this;
|
|
const context = this.getAnnotationContext();
|
|
if (!seriesRect || !context)
|
|
return;
|
|
annotationManager.updateData(annotationData.toJson());
|
|
const showAnnotations = this.showAnnotations();
|
|
this.toolbar.refreshButtonsEnabled(showAnnotations);
|
|
this.toolbar.toggleClearButtonEnabled(annotationData.length > 0 && showAnnotations);
|
|
annotations.update(annotationData ?? [], void 0, (datum) => datum.id).each((node, datum) => {
|
|
if (!showAnnotations) {
|
|
node.visible = false;
|
|
if ("setAxisLabelVisible" in node) {
|
|
node.setAxisLabelVisible(false);
|
|
}
|
|
return;
|
|
}
|
|
if ("setAxisLabelVisible" in node) {
|
|
node.setAxisLabelVisible(true);
|
|
}
|
|
this.injectDatumDependencies(datum);
|
|
updateAnnotation(node, datum, context);
|
|
});
|
|
for (const fn of this.postUpdateFns) {
|
|
fn();
|
|
}
|
|
this.postUpdateFns = [];
|
|
}
|
|
getAnnotationContext() {
|
|
const { seriesRect, xAxis, yAxis, snap } = this;
|
|
if (!(seriesRect && xAxis && yAxis)) {
|
|
return;
|
|
}
|
|
return {
|
|
seriesRect,
|
|
xAxis: {
|
|
...xAxis.context,
|
|
bounds: xAxis.bounds,
|
|
labelPadding: calculateAxisLabelPadding(xAxis.layout),
|
|
snapToGroup: snap
|
|
},
|
|
yAxis: {
|
|
...yAxis.context,
|
|
bounds: yAxis.bounds,
|
|
labelPadding: calculateAxisLabelPadding(xAxis.layout),
|
|
snapToGroup: snap
|
|
}
|
|
};
|
|
}
|
|
onHover(event) {
|
|
const { state } = this;
|
|
const context = this.getAnnotationContext();
|
|
if (!context)
|
|
return;
|
|
const shiftKey = event.sourceEvent.shiftKey;
|
|
const offset = Vec219.from(event);
|
|
const point = invertCoords(offset, context);
|
|
state.transition("hover", { offset, point, shiftKey, context });
|
|
}
|
|
onClick(event) {
|
|
const { state } = this;
|
|
const context = this.getAnnotationContext();
|
|
if (!context)
|
|
return;
|
|
const shiftKey = event.sourceEvent.shiftKey;
|
|
const point = invertCoords(Vec219.from(event), context);
|
|
const textInputValue = this.textInput.getValue();
|
|
const bbox = this.textInput.getBBox();
|
|
state.transition("click", { point, shiftKey, textInputValue, bbox });
|
|
}
|
|
onDoubleClick(event) {
|
|
const { state } = this;
|
|
const context = this.getAnnotationContext();
|
|
if (!context)
|
|
return;
|
|
const offset = Vec219.from(event);
|
|
state.transition("dblclick", { offset });
|
|
}
|
|
onAxisButtonClick(coords, direction) {
|
|
this.cancel();
|
|
this.reset();
|
|
const context = this.getAnnotationContext();
|
|
if (!this.annotationData || !context)
|
|
return;
|
|
const { state } = this;
|
|
this.pushAnnotationState(InteractionState2.Annotations);
|
|
const isHorizontal2 = direction === "horizontal";
|
|
state.transition(isHorizontal2 ? "horizontal-line" /* HorizontalLine */ : "vertical-line" /* VerticalLine */);
|
|
this.optionsToolbar.hide();
|
|
if (!coords) {
|
|
return;
|
|
}
|
|
const point = invertCoords(coords, context);
|
|
if (!validateDatumPoint(context, point)) {
|
|
return;
|
|
}
|
|
state.transition("click", { point, shiftKey: false });
|
|
this.update();
|
|
}
|
|
onResize() {
|
|
const textInputValue = this.textInput.getValue();
|
|
const bbox = this.textInput.getBBox();
|
|
this.state.transition("resize", { textInputValue, bbox });
|
|
}
|
|
hoverTouchPreHandler(event) {
|
|
if (event.device === "touch") {
|
|
this.onHover(event);
|
|
}
|
|
}
|
|
dragMoveTouchPreHandler(event) {
|
|
if (event.device === "touch" && this.ctx.interactionManager.isState(InteractionState2.AnnotationsSelected)) {
|
|
event.sourceEvent.preventDefault();
|
|
}
|
|
}
|
|
onDragStart(event) {
|
|
if (!this.ctx.interactionManager.isState(InteractionState2.AnnotationsDraggable))
|
|
return;
|
|
const context = this.getAnnotationContext();
|
|
if (!context)
|
|
return;
|
|
const offset = Vec219.from(event);
|
|
const point = invertCoords(offset, context);
|
|
const textInputValue = this.textInput.getValue();
|
|
const bbox = this.textInput.getBBox();
|
|
this.state.transition("dragStart", { context, offset, point, textInputValue, bbox });
|
|
}
|
|
onDrag(event) {
|
|
if (!this.ctx.interactionManager.isState(InteractionState2.AnnotationsDraggable))
|
|
return;
|
|
const context = this.getAnnotationContext();
|
|
if (!context)
|
|
return;
|
|
const offset = Vec219.from(event);
|
|
const point = invertCoords(offset, context);
|
|
const shiftKey = event.sourceEvent.shiftKey;
|
|
const textInputValue = this.textInput.getValue();
|
|
const bbox = this.textInput.getBBox();
|
|
this.state.transition("drag", { context, offset, point, shiftKey, textInputValue, bbox });
|
|
}
|
|
onDragEnd() {
|
|
this.state.transition("dragEnd");
|
|
}
|
|
onCancel(widgetEvent) {
|
|
const { sourceEvent } = widgetEvent ?? {};
|
|
if (sourceEvent?.currentTarget !== sourceEvent?.target)
|
|
return;
|
|
this.cancel();
|
|
this.reset();
|
|
}
|
|
onDelete() {
|
|
if (this.textInput.isVisible())
|
|
return;
|
|
this.cancel();
|
|
this.delete();
|
|
this.reset();
|
|
this.update();
|
|
}
|
|
onTextInput(event) {
|
|
const { state } = this;
|
|
const context = this.getAnnotationContext();
|
|
if (!context)
|
|
return;
|
|
const { key, shiftKey } = event;
|
|
const textInputValue = this.textInput.getValue();
|
|
const bbox = this.textInput.getBBox();
|
|
state.transition("textInput", { key, shiftKey, textInputValue, bbox, context });
|
|
}
|
|
onKeyDown(event) {
|
|
const { state } = this;
|
|
const context = this.getAnnotationContext();
|
|
if (!context) {
|
|
return;
|
|
}
|
|
const { sourceEvent } = event;
|
|
const { shiftKey, ctrlKey, metaKey } = sourceEvent;
|
|
const ctrlMeta = ctrlKey || metaKey;
|
|
const ctrlShift = ctrlKey || shiftKey;
|
|
state.transition("keyDown", { shiftKey, context });
|
|
const translation = { x: 0, y: 0 };
|
|
const xStep = Math.max(context?.xAxis.scale.bandwidth ?? 0, ctrlShift ? 10 : 1);
|
|
const yStep = Math.max(context?.yAxis.scale.bandwidth ?? 0, ctrlShift ? 10 : 1);
|
|
switch (sourceEvent.key) {
|
|
case "ArrowDown":
|
|
translation.y = yStep;
|
|
break;
|
|
case "ArrowUp":
|
|
translation.y = -yStep;
|
|
break;
|
|
case "ArrowLeft":
|
|
translation.x = -xStep;
|
|
break;
|
|
case "ArrowRight":
|
|
translation.x = xStep;
|
|
break;
|
|
case "Escape":
|
|
this.onCancel();
|
|
return;
|
|
case "Backspace":
|
|
case "Delete":
|
|
this.onDelete();
|
|
return;
|
|
}
|
|
if (translation.x || translation.y) {
|
|
state.transition("translate", { translation });
|
|
sourceEvent.stopPropagation();
|
|
sourceEvent.preventDefault();
|
|
}
|
|
if (!ctrlMeta) {
|
|
return;
|
|
}
|
|
switch (sourceEvent.key) {
|
|
case "c":
|
|
state.transition("copy");
|
|
return;
|
|
case "x":
|
|
state.transition("cut");
|
|
this.recordActionAfterNextUpdate("Cut annotation");
|
|
return;
|
|
case "v":
|
|
state.transition("paste");
|
|
this.recordActionAfterNextUpdate("Paste annotation");
|
|
return;
|
|
}
|
|
}
|
|
onKeyUp(event) {
|
|
const { shiftKey } = event.sourceEvent;
|
|
const context = this.getAnnotationContext();
|
|
if (!context) {
|
|
return;
|
|
}
|
|
this.state.transition("keyUp", { shiftKey, context });
|
|
this.state.transition("translateEnd");
|
|
}
|
|
clear() {
|
|
this.cancel();
|
|
this.deleteAll();
|
|
this.reset();
|
|
}
|
|
reset() {
|
|
this.state.transition("reset");
|
|
}
|
|
cancel() {
|
|
this.state.transition("cancel");
|
|
}
|
|
delete() {
|
|
this.state.transition("delete");
|
|
}
|
|
deleteAll() {
|
|
this.state.transition("deleteAll");
|
|
}
|
|
deleteEphemeralAnnotations() {
|
|
let deletedEphemeral = false;
|
|
for (const [index, datum] of this.annotationData.entries()) {
|
|
if (isEphemeralType(datum)) {
|
|
this.annotationData.splice(index, 1);
|
|
deletedEphemeral = true;
|
|
}
|
|
}
|
|
if (deletedEphemeral) {
|
|
this.recordActionAfterNextUpdate("Delete ephemeral annotations");
|
|
}
|
|
}
|
|
hideOverlays() {
|
|
this.settingsDialog.hide();
|
|
this.toolbar.hideOverlays();
|
|
this.optionsToolbar.hideOverlays();
|
|
}
|
|
pushAnnotationState(state) {
|
|
this.ctx.interactionManager.pushState(state);
|
|
this.ctx.tooltipManager.suppressTooltip("annotations");
|
|
}
|
|
popAnnotationState(state) {
|
|
this.ctx.interactionManager.popState(state);
|
|
this.ctx.tooltipManager.unsuppressTooltip("annotations");
|
|
}
|
|
isAnnotationState() {
|
|
return this.ctx.interactionManager.isState(InteractionState2.Annotations) || this.ctx.interactionManager.isState(InteractionState2.AnnotationsSelected);
|
|
}
|
|
update(status = ChartUpdateType3.PRE_SCENE_RENDER) {
|
|
this.ctx.updateService.update(status);
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property37
|
|
], _Annotations.prototype, "toolbar", 2);
|
|
__decorateClass([
|
|
Property37
|
|
], _Annotations.prototype, "optionsToolbar", 2);
|
|
__decorateClass([
|
|
Property37
|
|
], _Annotations.prototype, "axesButtons", 2);
|
|
__decorateClass([
|
|
Property37,
|
|
ObserveChanges3((target, value) => {
|
|
const enabled = value ?? true;
|
|
target.toolbar.enabled = enabled;
|
|
target.optionsToolbar.enabled = enabled;
|
|
target.axesButtons.enabled = enabled;
|
|
})
|
|
], _Annotations.prototype, "enabled", 2);
|
|
__decorateClass([
|
|
Property37
|
|
], _Annotations.prototype, "snap", 2);
|
|
var Annotations = _Annotations;
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/annotationsTheme.ts
|
|
import "ag-charts-community";
|
|
import * as ThemeSymbols from "ag-charts-core";
|
|
import { FONT_SIZE_RATIO } from "ag-charts-core";
|
|
var stroke = {
|
|
stroke: { $ref: "foregroundColor" },
|
|
strokeOpacity: 1,
|
|
strokeWidth: 2
|
|
};
|
|
var handle = {
|
|
fill: ThemeSymbols.DEFAULT_ANNOTATION_HANDLE_FILL,
|
|
strokeOpacity: 1,
|
|
strokeWidth: 2
|
|
};
|
|
var font = {
|
|
color: { $ref: "chartBackgroundColor" },
|
|
fontSize: { $rem: FONT_SIZE_RATIO.LARGE },
|
|
fontFamily: { $ref: "fontFamily" }
|
|
};
|
|
var axisLabel = {
|
|
...font,
|
|
enabled: true,
|
|
fill: { $ref: "foregroundColor" },
|
|
fontSize: { $ref: "fontSize" }
|
|
};
|
|
var text = {
|
|
...font,
|
|
textAlign: "left"
|
|
};
|
|
var lineText = {
|
|
...font,
|
|
position: "top",
|
|
alignment: "center",
|
|
color: { $ref: "textColor" }
|
|
};
|
|
var channelText = {
|
|
...font,
|
|
position: "top",
|
|
alignment: "center",
|
|
color: { $ref: "textColor" }
|
|
};
|
|
var measurerStatistics = {
|
|
...font,
|
|
fontSize: { $ref: "fontSize" },
|
|
color: ThemeSymbols.DEFAULT_ANNOTATION_STATISTICS_COLOR,
|
|
fill: ThemeSymbols.DEFAULT_ANNOTATION_STATISTICS_FILL,
|
|
stroke: ThemeSymbols.DEFAULT_ANNOTATION_STATISTICS_STROKE,
|
|
strokeWidth: 1,
|
|
divider: {
|
|
stroke: ThemeSymbols.DEFAULT_ANNOTATION_STATISTICS_DIVIDER_STROKE,
|
|
strokeWidth: 1,
|
|
strokeOpacity: 0.5
|
|
}
|
|
};
|
|
var measurer = {
|
|
...stroke,
|
|
background: {
|
|
fill: { $ref: "foregroundColor" },
|
|
fillOpacity: 0.075
|
|
},
|
|
handle: { ...handle },
|
|
text: { ...lineText },
|
|
statistics: { ...measurerStatistics }
|
|
};
|
|
var toolbar = {
|
|
buttons: {
|
|
$shallowSimple: [
|
|
{
|
|
icon: "text-annotation",
|
|
tooltip: "toolbarAnnotationsTextAnnotations",
|
|
value: "text-menu"
|
|
},
|
|
{
|
|
icon: "trend-line-drawing",
|
|
tooltip: "toolbarAnnotationsLineAnnotations",
|
|
value: "line-menu"
|
|
},
|
|
{
|
|
icon: "arrow-drawing",
|
|
tooltip: "toolbarAnnotationsShapeAnnotations",
|
|
value: "shape-menu"
|
|
},
|
|
{
|
|
icon: "delete",
|
|
tooltip: "toolbarAnnotationsClearAll",
|
|
value: "clear"
|
|
}
|
|
]
|
|
},
|
|
padding: { $ref: "chartPadding" }
|
|
};
|
|
var optionsToolbar = {
|
|
buttons: {
|
|
$shallowSimple: [
|
|
{
|
|
icon: "text-annotation",
|
|
tooltip: "toolbarAnnotationsTextColor",
|
|
value: "text-color"
|
|
},
|
|
{
|
|
icon: "line-color",
|
|
tooltip: "toolbarAnnotationsLineColor",
|
|
value: "line-color"
|
|
},
|
|
{
|
|
icon: "fill-color",
|
|
tooltip: "toolbarAnnotationsFillColor",
|
|
value: "fill-color"
|
|
},
|
|
{
|
|
tooltip: "toolbarAnnotationsTextSize",
|
|
value: "text-size"
|
|
},
|
|
{
|
|
tooltip: "toolbarAnnotationsLineStrokeWidth",
|
|
value: "line-stroke-width"
|
|
},
|
|
{
|
|
icon: "line-style-solid",
|
|
tooltip: "toolbarAnnotationsLineStyle",
|
|
value: "line-style-type"
|
|
},
|
|
{
|
|
icon: "settings",
|
|
tooltip: "toolbarAnnotationsSettings",
|
|
value: "settings"
|
|
},
|
|
{
|
|
icon: "unlocked",
|
|
tooltip: "toolbarAnnotationsLock",
|
|
ariaLabel: "toolbarAnnotationsLock",
|
|
checkedOverrides: {
|
|
icon: "locked",
|
|
tooltip: "toolbarAnnotationsUnlock"
|
|
},
|
|
value: "lock"
|
|
},
|
|
{
|
|
icon: "delete",
|
|
tooltip: "toolbarAnnotationsDelete",
|
|
value: "delete"
|
|
}
|
|
]
|
|
}
|
|
};
|
|
var annotationsTheme = {
|
|
enabled: false,
|
|
// Lines
|
|
line: {
|
|
...stroke,
|
|
handle: { ...handle },
|
|
text: { ...lineText }
|
|
},
|
|
"horizontal-line": {
|
|
...stroke,
|
|
handle: { ...handle },
|
|
axisLabel: { ...axisLabel },
|
|
text: { ...lineText }
|
|
},
|
|
"vertical-line": {
|
|
...stroke,
|
|
handle: { ...handle },
|
|
axisLabel: { ...axisLabel },
|
|
text: { ...lineText }
|
|
},
|
|
// Channels
|
|
"disjoint-channel": {
|
|
...stroke,
|
|
background: {
|
|
fill: { $ref: "foregroundColor" },
|
|
fillOpacity: 0.075
|
|
},
|
|
handle: { ...handle },
|
|
text: { ...channelText }
|
|
},
|
|
"parallel-channel": {
|
|
...stroke,
|
|
middle: {
|
|
lineDash: [6, 5],
|
|
strokeWidth: 1
|
|
},
|
|
background: {
|
|
fill: { $ref: "foregroundColor" },
|
|
fillOpacity: 0.075
|
|
},
|
|
handle: { ...handle },
|
|
text: { ...channelText }
|
|
},
|
|
// Fibonnaccis
|
|
"fibonacci-retracement": {
|
|
...stroke,
|
|
strokes: ThemeSymbols.DEFAULT_FIBONACCI_STROKES,
|
|
rangeStroke: { $ref: "foregroundColor" },
|
|
handle: { ...handle },
|
|
text: { ...lineText, position: "center" },
|
|
label: {
|
|
...font,
|
|
color: void 0,
|
|
fontSize: { $rem: FONT_SIZE_RATIO.SMALLER }
|
|
}
|
|
},
|
|
"fibonacci-retracement-trend-based": {
|
|
...stroke,
|
|
strokes: ThemeSymbols.DEFAULT_FIBONACCI_STROKES,
|
|
rangeStroke: { $ref: "foregroundColor" },
|
|
handle: { ...handle },
|
|
text: { ...lineText, position: "center" },
|
|
label: {
|
|
...font,
|
|
color: void 0,
|
|
fontSize: { $rem: FONT_SIZE_RATIO.SMALLER }
|
|
}
|
|
},
|
|
// Texts
|
|
callout: {
|
|
...stroke,
|
|
...text,
|
|
color: { $ref: "textColor" },
|
|
handle: { ...handle },
|
|
fill: { $ref: "foregroundColor" },
|
|
fillOpacity: 0.075
|
|
},
|
|
comment: {
|
|
...text,
|
|
fontWeight: 700,
|
|
handle: { ...handle },
|
|
fill: { $ref: "foregroundColor" }
|
|
},
|
|
note: {
|
|
...text,
|
|
color: ThemeSymbols.DEFAULT_TEXTBOX_COLOR,
|
|
fill: ThemeSymbols.DEFAULT_FINANCIAL_CHARTS_ANNOTATION_COLOR,
|
|
stroke: { $ref: "chartBackgroundColor" },
|
|
strokeWidth: 1,
|
|
strokeOpacity: 1,
|
|
handle: { ...handle },
|
|
background: {
|
|
fill: ThemeSymbols.DEFAULT_TEXTBOX_FILL,
|
|
stroke: ThemeSymbols.DEFAULT_TEXTBOX_STROKE,
|
|
strokeWidth: 1
|
|
}
|
|
},
|
|
text: {
|
|
...text,
|
|
color: { $ref: "textColor" },
|
|
handle: { ...handle }
|
|
},
|
|
// Shapes
|
|
arrow: {
|
|
...stroke,
|
|
handle: { ...handle },
|
|
text: { ...lineText }
|
|
},
|
|
"arrow-up": {
|
|
fill: { $palette: "up.fill" },
|
|
handle: { ...handle, stroke: { $ref: "foregroundColor" } }
|
|
},
|
|
"arrow-down": {
|
|
fill: { $palette: "down.fill" },
|
|
handle: { ...handle, stroke: { $ref: "foregroundColor" } }
|
|
},
|
|
// Measurers
|
|
"date-range": {
|
|
...measurer
|
|
},
|
|
"price-range": {
|
|
...measurer
|
|
},
|
|
"date-price-range": {
|
|
...measurer
|
|
},
|
|
"quick-date-price-range": {
|
|
up: {
|
|
...stroke,
|
|
fill: ThemeSymbols.DEFAULT_FINANCIAL_CHARTS_ANNOTATION_BACKGROUND_FILL,
|
|
fillOpacity: 0.2,
|
|
handle: { ...handle },
|
|
statistics: {
|
|
...measurerStatistics,
|
|
color: "#fff",
|
|
fill: ThemeSymbols.DEFAULT_FINANCIAL_CHARTS_ANNOTATION_BACKGROUND_FILL,
|
|
strokeWidth: 0,
|
|
divider: {
|
|
stroke: "#fff",
|
|
strokeWidth: 1,
|
|
strokeOpacity: 0.5
|
|
}
|
|
}
|
|
},
|
|
down: {
|
|
...stroke,
|
|
stroke: ThemeSymbols.DEFAULT_ANNOTATION_STATISTICS_DOWN_STROKE,
|
|
fill: ThemeSymbols.DEFAULT_ANNOTATION_STATISTICS_DOWN_FILL,
|
|
fillOpacity: 0.2,
|
|
handle: {
|
|
...handle,
|
|
stroke: ThemeSymbols.DEFAULT_ANNOTATION_STATISTICS_DOWN_STROKE
|
|
},
|
|
statistics: {
|
|
...measurerStatistics,
|
|
color: "#fff",
|
|
fill: ThemeSymbols.DEFAULT_ANNOTATION_STATISTICS_DOWN_FILL,
|
|
strokeWidth: 0,
|
|
divider: {
|
|
stroke: "#fff",
|
|
strokeWidth: 1,
|
|
strokeOpacity: 0.5
|
|
}
|
|
}
|
|
}
|
|
},
|
|
axesButtons: {},
|
|
// Toolbars
|
|
toolbar,
|
|
optionsToolbar
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/annotations/annotationsModule.ts
|
|
var AnnotationsModule = {
|
|
type: "plugin",
|
|
name: "annotations",
|
|
chartType: "cartesian",
|
|
enterprise: true,
|
|
version: VERSION7,
|
|
options: _ModuleSupport65.annotationOptionsDef,
|
|
themeTemplate: annotationsTheme,
|
|
create: (ctx) => new Annotations(ctx),
|
|
patchContext: (ctx) => {
|
|
if (ctx.sharedToolbar)
|
|
return;
|
|
ctx.sharedToolbar = new SharedToolbar(ctx);
|
|
ctx.cleanup.register(() => ctx.sharedToolbar.destroy());
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/band-highlight/bandHighlightModule.ts
|
|
import { VERSION as VERSION8 } from "ag-charts-community";
|
|
|
|
// packages/ag-charts-enterprise/src/features/band-highlight/bandHighlight.ts
|
|
import { _ModuleSupport as _ModuleSupport66 } from "ag-charts-community";
|
|
import {
|
|
AbstractModuleInstance as AbstractModuleInstance5,
|
|
ChartAxisDirection as ChartAxisDirection10,
|
|
ChartUpdateType as ChartUpdateType4,
|
|
Property as Property38,
|
|
ZIndexMap as ZIndexMap5,
|
|
createId as createId2
|
|
} from "ag-charts-core";
|
|
var {
|
|
Range,
|
|
TranslatableGroup,
|
|
BBox: BBox4,
|
|
FillGradientDefaults,
|
|
FillImageDefaults,
|
|
FillPatternDefaults,
|
|
getShapeFill,
|
|
InteractionState: InteractionState3
|
|
} = _ModuleSupport66;
|
|
var BandHighlight = class extends AbstractModuleInstance5 {
|
|
constructor(ctx) {
|
|
super();
|
|
this.ctx = ctx;
|
|
this.id = createId2(this);
|
|
this.enabled = false;
|
|
this.stroke = "rgb(195, 195, 195)";
|
|
this.lineDash = [6, 3];
|
|
this.lineDashOffset = 0;
|
|
this.strokeWidth = 1;
|
|
this.strokeOpacity = 1;
|
|
this.fill = "#c16068";
|
|
this.fillOpacity = 1;
|
|
this.fillGradientDefaults = new FillGradientDefaults();
|
|
this.fillPatternDefaults = new FillPatternDefaults();
|
|
this.fillImageDefaults = new FillImageDefaults();
|
|
this.bounds = new BBox4(0, 0, 0, 0);
|
|
this.bandHighlightGroup = new TranslatableGroup({
|
|
name: "bandHighlight",
|
|
zIndex: ZIndexMap5.AXIS_BAND_HIGHLIGHT
|
|
});
|
|
this.rangeNode = this.bandHighlightGroup.appendChild(new Range());
|
|
this.activeAxisHighlight = void 0;
|
|
this.axisCtx = ctx.parent;
|
|
this.hideBand();
|
|
ctx.domManager.addEventListener("focusin", ({ target }) => {
|
|
const isSeriesAreaChild = target instanceof HTMLElement && ctx.domManager.contains(target, "series-area");
|
|
if (this.bandHighlightGroup.visible && !isSeriesAreaChild) {
|
|
this.hideBand();
|
|
this.ctx.updateService.update(ChartUpdateType4.SCENE_RENDER);
|
|
}
|
|
});
|
|
const {
|
|
widgets: { seriesWidget, seriesDragInterpreter },
|
|
animationManager,
|
|
eventsHub
|
|
} = ctx;
|
|
this.cleanup.register(
|
|
ctx.scene.attachNode(this.bandHighlightGroup),
|
|
seriesWidget.addListener("mousemove", (event) => this.onHoverLikeEvent(event)),
|
|
seriesWidget.addListener("mouseleave", () => this.clearAllHighlight()),
|
|
animationManager.addListener("animation-start", () => this.clearAllHighlight()),
|
|
eventsHub.on("layout:complete", (event) => this.layout(event)),
|
|
eventsHub.on("series:focus-change", () => this.onKeyPress()),
|
|
eventsHub.on("zoom:pan-start", () => this.clearAllHighlight()),
|
|
eventsHub.on("zoom:change-complete", () => this.clearAllHighlight()),
|
|
eventsHub.on("dom:resize", () => this.clearAllHighlight()),
|
|
eventsHub.on("axis:change", () => this.axisChange())
|
|
);
|
|
if (seriesDragInterpreter) {
|
|
this.cleanup.register(
|
|
seriesDragInterpreter.events.on("drag-move", (event) => this.onHoverLikeEvent(event)),
|
|
seriesDragInterpreter.events.on("click", (event) => this.onClick(event))
|
|
);
|
|
}
|
|
}
|
|
axisChange() {
|
|
this.onHighlightChange();
|
|
}
|
|
isHover(event) {
|
|
return event.type === "mousemove" || event.type === "click" || event.device === "touch" && this.ctx.chartService.touch.dragAction === "hover";
|
|
}
|
|
onClick(event) {
|
|
if (event.device === "touch") {
|
|
this.onHoverLikeEvent(event);
|
|
}
|
|
}
|
|
clearAllHighlight() {
|
|
if (!this.ctx.interactionManager.isState(InteractionState3.Clickable))
|
|
return;
|
|
this.onHighlightChange();
|
|
}
|
|
onKeyPress() {
|
|
if (this.ctx.interactionManager.isState(InteractionState3.Default)) {
|
|
this.onHighlightChange();
|
|
}
|
|
}
|
|
onHoverLikeEvent(event) {
|
|
const requiredState = this.isHover(event) ? InteractionState3.Clickable : InteractionState3.AnnotationsMoveable;
|
|
if (!this.ctx.interactionManager.isState(requiredState))
|
|
return;
|
|
this.handleHoverHighlight(event);
|
|
}
|
|
handleHoverHighlight(event) {
|
|
if (!event)
|
|
return;
|
|
const { currentX: x, currentY: y } = event;
|
|
this.onHighlightChange(this.axisCtx.pickBand({ x, y }));
|
|
}
|
|
layout({ series: { rect, visible }, axes }) {
|
|
if (!visible || !axes || !this.enabled)
|
|
return;
|
|
const { position: axisPosition = "left", axisId } = this.axisCtx;
|
|
const axisLayout = axes[axisId];
|
|
if (!axisLayout)
|
|
return;
|
|
this.axisLayout = axisLayout;
|
|
this.bounds = rect.clone().grow(axisLayout.gridPadding, axisPosition);
|
|
const { bandHighlightGroup, bounds } = this;
|
|
bandHighlightGroup.translationX = Math.round(bounds.x);
|
|
bandHighlightGroup.translationY = Math.round(bounds.y);
|
|
this.updateBand();
|
|
}
|
|
updateBand() {
|
|
const {
|
|
rangeNode: node,
|
|
stroke: stroke3,
|
|
strokeWidth,
|
|
strokeOpacity,
|
|
lineDash,
|
|
fill,
|
|
fillOpacity,
|
|
fillGradientDefaults: fillGradientDefaults3,
|
|
fillPatternDefaults: fillPatternDefaults3,
|
|
fillImageDefaults: fillImageDefaults3,
|
|
lineDashOffset,
|
|
axisLayout
|
|
} = this;
|
|
if (!axisLayout)
|
|
return;
|
|
node.stroke = stroke3;
|
|
node.strokeWidth = strokeWidth;
|
|
node.strokeOpacity = strokeOpacity;
|
|
node.lineDash = lineDash;
|
|
node.lineDashOffset = lineDashOffset;
|
|
node.fill = getShapeFill(fill, fillGradientDefaults3, fillPatternDefaults3, fillImageDefaults3);
|
|
node.fillOpacity = fillOpacity;
|
|
node.startLine = true;
|
|
node.endLine = true;
|
|
}
|
|
isVertical() {
|
|
return this.axisCtx.direction === ChartAxisDirection10.X;
|
|
}
|
|
onHighlightChange(axisBandDatum) {
|
|
if (!this.enabled)
|
|
return;
|
|
this.activeAxisHighlight = axisBandDatum;
|
|
if (this.activeAxisHighlight) {
|
|
this.showBand();
|
|
} else {
|
|
this.hideBand();
|
|
}
|
|
this.ctx.updateService.update(ChartUpdateType4.SCENE_RENDER);
|
|
}
|
|
updateBandPosition() {
|
|
const { rangeNode, bounds } = this;
|
|
const { band } = this.activeAxisHighlight ?? {};
|
|
if (band == void 0) {
|
|
this.hideBand();
|
|
return;
|
|
}
|
|
let r0 = Math.min(...band);
|
|
let r1 = Math.max(...band);
|
|
if (r1 - r0 < 1) {
|
|
const mid = (r0 + r1) / 2;
|
|
r0 = mid - 0.5;
|
|
r1 = mid + 0.5;
|
|
}
|
|
if (this.isVertical()) {
|
|
rangeNode.y1 = 0;
|
|
rangeNode.y2 = bounds.height;
|
|
rangeNode.x1 = r0;
|
|
rangeNode.x2 = r1;
|
|
rangeNode.horizontal = true;
|
|
} else {
|
|
rangeNode.y1 = r0;
|
|
rangeNode.y2 = r1;
|
|
rangeNode.x1 = 0;
|
|
rangeNode.x2 = bounds.width;
|
|
rangeNode.horizontal = false;
|
|
}
|
|
}
|
|
showBand() {
|
|
this.updateBandPosition();
|
|
this.bandHighlightGroup.visible = true;
|
|
}
|
|
hideBand() {
|
|
this.bandHighlightGroup.visible = false;
|
|
}
|
|
};
|
|
BandHighlight.className = "BandHighlight";
|
|
__decorateClass([
|
|
Property38
|
|
], BandHighlight.prototype, "enabled", 2);
|
|
__decorateClass([
|
|
Property38
|
|
], BandHighlight.prototype, "stroke", 2);
|
|
__decorateClass([
|
|
Property38
|
|
], BandHighlight.prototype, "lineDash", 2);
|
|
__decorateClass([
|
|
Property38
|
|
], BandHighlight.prototype, "lineDashOffset", 2);
|
|
__decorateClass([
|
|
Property38
|
|
], BandHighlight.prototype, "strokeWidth", 2);
|
|
__decorateClass([
|
|
Property38
|
|
], BandHighlight.prototype, "strokeOpacity", 2);
|
|
__decorateClass([
|
|
Property38
|
|
], BandHighlight.prototype, "fill", 2);
|
|
__decorateClass([
|
|
Property38
|
|
], BandHighlight.prototype, "fillOpacity", 2);
|
|
__decorateClass([
|
|
Property38
|
|
], BandHighlight.prototype, "fillGradientDefaults", 2);
|
|
__decorateClass([
|
|
Property38
|
|
], BandHighlight.prototype, "fillPatternDefaults", 2);
|
|
__decorateClass([
|
|
Property38
|
|
], BandHighlight.prototype, "fillImageDefaults", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/features/band-highlight/bandHighlightModule.ts
|
|
var BandHighlightModule = {
|
|
type: "axis:plugin",
|
|
name: "bandHighlight",
|
|
chartType: "cartesian",
|
|
axisTypes: ["category", "ordinal-time", "unit-time", "grouped-category"],
|
|
enterprise: true,
|
|
version: VERSION8,
|
|
themeTemplate: {
|
|
enabled: false,
|
|
strokeWidth: 0,
|
|
lineDash: [],
|
|
fill: { $foregroundBackgroundMix: 0.05 }
|
|
},
|
|
create: (ctx) => new BandHighlight(ctx)
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/chart-toolbar/chartToolbarModule.ts
|
|
import { VERSION as VERSION9 } from "ag-charts-community";
|
|
import { boolean as boolean2 } from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/features/chart-toolbar/chartToolbar.ts
|
|
import { _ModuleSupport as _ModuleSupport67 } from "ag-charts-community";
|
|
import { AbstractModuleInstance as AbstractModuleInstance6, ActionOnSet as ActionOnSet5, Logger as Logger4, Property as Property39 } from "ag-charts-core";
|
|
var { LayoutElement: LayoutElement2, Menu: Menu3 } = _ModuleSupport67;
|
|
var menuItems = [
|
|
{ label: "toolbarSeriesTypeOHLC", icon: "ohlc-series", value: "ohlc" },
|
|
{ label: "toolbarSeriesTypeCandles", icon: "candlestick-series", value: "candlestick" },
|
|
{ label: "toolbarSeriesTypeHollowCandles", icon: "hollow-candlestick-series", value: "hollow-candlestick" },
|
|
{ label: "toolbarSeriesTypeLine", icon: "line-series", value: "line" },
|
|
{ label: "toolbarSeriesTypeStepLine", icon: "step-line-series", value: "step-line" },
|
|
{ label: "toolbarSeriesTypeHLC", icon: "hlc-series", value: "hlc" },
|
|
{ label: "toolbarSeriesTypeHighLow", icon: "high-low-series", value: "high-low" }
|
|
];
|
|
var ChartToolbar = class extends AbstractModuleInstance6 {
|
|
constructor(ctx) {
|
|
super();
|
|
this.ctx = ctx;
|
|
this.enabled = false;
|
|
this.menu = new Menu3(this.ctx, "chart-toolbar");
|
|
this.toolbar = ctx.sharedToolbar.getSharedToolbar("chartToolbar");
|
|
this.cleanup.register(
|
|
this.toolbar.addToolbarListener("button-pressed", this.onButtonPressed.bind(this)),
|
|
ctx.layoutManager.registerElement(LayoutElement2.ToolbarLeft, this.onLayoutStart.bind(this)),
|
|
() => this.toolbar.destroy()
|
|
);
|
|
}
|
|
onLayoutStart(ctx) {
|
|
if (!this.enabled)
|
|
return;
|
|
this.updateButton();
|
|
this.toolbar.layout(ctx.layoutBox);
|
|
}
|
|
onButtonPressed({ event, buttonBounds, buttonWidget }) {
|
|
this.menu.setAnchor({ x: buttonBounds.x + buttonBounds.width + 6, y: buttonBounds.y });
|
|
this.menu.show(buttonWidget, {
|
|
items: menuItems,
|
|
menuItemRole: "menuitemradio",
|
|
ariaLabel: this.ctx.localeManager.t("toolbarSeriesTypeDropdown"),
|
|
class: "ag-charts-chart-toolbar__menu",
|
|
value: this.getChartType(),
|
|
sourceEvent: event.sourceEvent,
|
|
onPress: (item) => {
|
|
this.setChartType(item.value);
|
|
this.hidePopover();
|
|
},
|
|
onHide: () => {
|
|
this.toolbar.clearActiveButton();
|
|
}
|
|
});
|
|
this.toolbar.toggleActiveButtonByIndex(0);
|
|
}
|
|
updateButton() {
|
|
const chartType = this.getChartType();
|
|
const icon = menuItems.find((item) => item.value === chartType)?.icon;
|
|
if (icon != null) {
|
|
this.toolbar.updateButtons([{ icon, tooltip: "toolbarSeriesTypeDropdown", value: "menu" }]);
|
|
}
|
|
}
|
|
hidePopover() {
|
|
this.toolbar.clearActiveButton();
|
|
this.menu.hide();
|
|
}
|
|
setChartType(chartType) {
|
|
const options = { chartType };
|
|
this.ctx.chartService.publicApi?.updateDelta(options).catch((e) => Logger4.error(e));
|
|
}
|
|
getChartType() {
|
|
const chartType = this.ctx.chartService.publicApi?.getOptions()?.chartType;
|
|
if (chartType == null || !menuItems.some((item) => item.value === chartType)) {
|
|
return "candlestick";
|
|
}
|
|
return chartType;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property39,
|
|
ActionOnSet5({
|
|
changeValue(enabled) {
|
|
this.toolbar?.setHidden(!enabled);
|
|
}
|
|
})
|
|
], ChartToolbar.prototype, "enabled", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/features/chart-toolbar/chartToolbarModule.ts
|
|
var ChartToolbarModule = {
|
|
type: "plugin",
|
|
name: "chartToolbar",
|
|
chartType: "cartesian",
|
|
enterprise: true,
|
|
version: VERSION9,
|
|
options: {
|
|
enabled: boolean2
|
|
},
|
|
create: (ctx) => new ChartToolbar(ctx),
|
|
patchContext: (ctx) => {
|
|
if (ctx.sharedToolbar)
|
|
return;
|
|
ctx.sharedToolbar = new SharedToolbar(ctx);
|
|
ctx.cleanup.register(() => ctx.sharedToolbar.destroy());
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/context-menu/contextMenuModule.ts
|
|
import { VERSION as VERSION10 } from "ag-charts-community";
|
|
import {
|
|
IS_DARK_THEME,
|
|
boolean as boolean3,
|
|
callbackOf,
|
|
contextMenuItemsArray,
|
|
undocumented as undocumented2
|
|
} from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/features/context-menu/contextMenu.ts
|
|
import { _ModuleSupport as _ModuleSupport68, _Widget as _Widget4 } from "ag-charts-community";
|
|
import {
|
|
AbstractModuleInstance as AbstractModuleInstance7,
|
|
Logger as Logger5,
|
|
Property as Property40,
|
|
callWithContext,
|
|
clamp as clamp5,
|
|
createElement as createElement5,
|
|
getIconClassNames as getIconClassNames3,
|
|
toPlainText
|
|
} from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/features/context-menu/contextMenuItem.ts
|
|
import { isKeyOf } from "ag-charts-core";
|
|
function showsFor(showOn, showing) {
|
|
if (showOn === "always")
|
|
return true;
|
|
if (showOn === "series-area")
|
|
return showing === "series-area" || showing === "series-node";
|
|
return showOn === showing;
|
|
}
|
|
function appendItem(showing, item, result) {
|
|
let mustShow = true;
|
|
if (item.type === "separator") {
|
|
const last = result.at(-1);
|
|
mustShow = last !== void 0 && last.type !== "separator";
|
|
}
|
|
mustShow && (mustShow = showsFor(item.showOn ?? "always", showing));
|
|
if (mustShow) {
|
|
const menuItem = new ContextMenuItem(item);
|
|
result.push(menuItem);
|
|
return menuItem;
|
|
}
|
|
}
|
|
function appendBuiltinItem(showing, registry, keyword, result) {
|
|
if (registry.isVisible(keyword)) {
|
|
appendItem(showing, registry.builtins.items[keyword], result);
|
|
}
|
|
}
|
|
function expandBuiltin(showing, registry, keyword, result) {
|
|
const { builtins } = registry;
|
|
if (isKeyOf(keyword, builtins.lists)) {
|
|
for (const childKeyword of builtins.lists[keyword]) {
|
|
appendBuiltinItem(showing, registry, childKeyword, result);
|
|
}
|
|
} else {
|
|
appendBuiltinItem(showing, registry, keyword, result);
|
|
}
|
|
}
|
|
function expandBuiltinLists(showing, items, registry) {
|
|
const unfiltered = [];
|
|
const { builtins } = registry;
|
|
for (const it of items) {
|
|
if (typeof it === "string" && isKeyOf(it, builtins.lists)) {
|
|
for (const listItem of builtins.lists[it]) {
|
|
unfiltered.push(listItem);
|
|
}
|
|
} else {
|
|
unfiltered.push(it);
|
|
}
|
|
}
|
|
return unfiltered.filter((it) => {
|
|
if (typeof it === "string") {
|
|
const showOn = registry.builtins.items[it].showOn ?? "always";
|
|
return registry.isVisible(it) && showsFor(showOn, showing);
|
|
} else {
|
|
return showsFor(it.showOn ?? "always", showing);
|
|
}
|
|
});
|
|
}
|
|
function expandItems(showing, registry, items, result) {
|
|
for (const item of items) {
|
|
if (typeof item === "string") {
|
|
expandBuiltin(showing, registry, item, result);
|
|
} else {
|
|
const menuItem = appendItem(showing, item, result);
|
|
if (item.items && menuItem && item.items.length > 0) {
|
|
expandItems(showing, registry, item.items, menuItem.items);
|
|
}
|
|
}
|
|
}
|
|
if (result.at(-1)?.type === "separator") {
|
|
result.pop();
|
|
}
|
|
}
|
|
var ContextMenuItem = class {
|
|
constructor(options) {
|
|
this.type = "action";
|
|
this.showOn = "always";
|
|
this.label = "";
|
|
this.iconUrl = void 0;
|
|
this.enabled = true;
|
|
this.items = [];
|
|
this.action = void 0;
|
|
if (options)
|
|
this.setOptions(options);
|
|
this.items = [];
|
|
}
|
|
setField(key, that, value) {
|
|
that[key] = value;
|
|
}
|
|
setOptions(options) {
|
|
let key;
|
|
for (key in options) {
|
|
if (options[key] !== void 0) {
|
|
this.setField(key, this, options[key]);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/context-menu/contextMenuStyles.ts
|
|
var DEFAULT_CONTEXT_MENU_CLASS = "ag-charts-context-menu";
|
|
|
|
// packages/ag-charts-enterprise/src/features/context-menu/contextMenu.ts
|
|
var { ContextMenuRegistry } = _ModuleSupport68;
|
|
var moduleId2 = "context-menu";
|
|
var DATUM_KEYS = [
|
|
"angleKey",
|
|
"calloutLabelKey",
|
|
"colorKey",
|
|
"labelKey",
|
|
"radiusKey",
|
|
"sectorLabelKey",
|
|
"sizeKey",
|
|
"xKey",
|
|
"yKey"
|
|
];
|
|
var ContextMenu = class extends AbstractModuleInstance7 {
|
|
constructor(ctx) {
|
|
super();
|
|
this.ctx = ctx;
|
|
this.enabled = true;
|
|
this.darkTheme = false;
|
|
this.items = ["defaults"];
|
|
// State
|
|
this.pickedNode = void 0;
|
|
this.showEvent = void 0;
|
|
this.x = 0;
|
|
this.y = 0;
|
|
this.collapsingSubMenus = 0;
|
|
this.menuWidget = new _Widget4.MenuWidget();
|
|
this.interactionManager = ctx.interactionManager;
|
|
this.element = ctx.domManager.addChild("canvas-overlay", moduleId2);
|
|
this.element.classList.add(DEFAULT_CONTEXT_MENU_CLASS);
|
|
this.element.style.display = "none";
|
|
this.element.addEventListener("contextmenu", (event) => event.preventDefault());
|
|
this.element.addEventListener("focusout", ({ relatedTarget }) => {
|
|
if (this.collapsingSubMenus > 0)
|
|
return;
|
|
if (relatedTarget == null || relatedTarget instanceof Node && !this.element.contains(relatedTarget)) {
|
|
this.hide();
|
|
}
|
|
});
|
|
this.cleanup.register(
|
|
() => this.element.remove(),
|
|
() => this.menuWidget.destroy(),
|
|
ctx.eventsHub.on("dom:hidden", () => this.hide()),
|
|
this.menuWidget.addListener("collapse-widget", () => this.onCollapse())
|
|
);
|
|
this.menuWidget.addClass(`${DEFAULT_CONTEXT_MENU_CLASS}__menu`);
|
|
if (typeof MutationObserver !== "undefined") {
|
|
const observer = new MutationObserver(() => {
|
|
if (this.element.contains(this.menuWidget.getElement())) {
|
|
this.reposition();
|
|
}
|
|
});
|
|
observer.observe(this.element, { childList: true });
|
|
this.mutationObserver = observer;
|
|
this.cleanup.register(() => observer.disconnect());
|
|
}
|
|
this.ctx.contextMenuRegistry.builtins.items["download"].action = () => {
|
|
const title = ctx.chartService.title;
|
|
let fileName = "image";
|
|
if (title?.enabled) {
|
|
fileName = title.node.getPlainText().replace(/\.+/, "");
|
|
}
|
|
this.ctx.chartService.publicApi?.download({ fileName }).catch((e) => {
|
|
Logger5.error("Unable to download chart", e);
|
|
});
|
|
};
|
|
this.cleanup.register(this.ctx.eventsHub.on("context-menu:complete", (e) => this.onContext(e)));
|
|
}
|
|
makeGetItemsParams(event) {
|
|
const { showOn } = event;
|
|
const { context } = this.ctx.chartService;
|
|
const defaultItems = expandBuiltinLists(showOn, this.items, this.ctx.contextMenuRegistry);
|
|
switch (showOn) {
|
|
case "always":
|
|
case "series-area":
|
|
return { showOn, context, defaultItems };
|
|
case "series-node": {
|
|
if (this.pickedNode == null)
|
|
throw new Error(`this.pickedNode is null`);
|
|
const params = {
|
|
showOn,
|
|
context,
|
|
seriesId: this.pickedNode.series.id,
|
|
datum: this.pickedNode.datum,
|
|
defaultItems
|
|
};
|
|
for (const k of DATUM_KEYS) {
|
|
if (this.pickedNode[k] !== void 0) {
|
|
params[k] = this.pickedNode[k];
|
|
}
|
|
}
|
|
return params;
|
|
}
|
|
case "legend-item":
|
|
if (this.pickedLegendItem == null)
|
|
throw new Error(`this.pickedLegendItem is null`);
|
|
const { itemId, seriesId, label, enabled } = this.pickedLegendItem;
|
|
const text2 = toPlainText(label.text);
|
|
if (typeof itemId !== "string") {
|
|
throw new Error(`unexpected itemId type: [${typeof itemId}] (expected [string])`);
|
|
}
|
|
return { showOn, context, itemId, seriesId, text: text2, visible: enabled, defaultItems };
|
|
default:
|
|
return showOn;
|
|
}
|
|
}
|
|
expandItemsOptions(event) {
|
|
const result = [];
|
|
let items;
|
|
if (this.getItems) {
|
|
const cbParams = this.makeGetItemsParams(event);
|
|
items = this.getItems(cbParams);
|
|
}
|
|
items ?? (items = this.items);
|
|
expandItems(event.showOn, this.ctx.contextMenuRegistry, items, result);
|
|
return result;
|
|
}
|
|
onContext(event) {
|
|
if (!this.enabled)
|
|
return;
|
|
event.widgetEvent.sourceEvent.preventDefault();
|
|
this.showEvent = event.widgetEvent.sourceEvent;
|
|
this.x = event.x;
|
|
this.y = event.y;
|
|
this.pickedNode = void 0;
|
|
this.pickedLegendItem = void 0;
|
|
if (ContextMenuRegistry.check("series-node", event)) {
|
|
this.pickedNode = event.context.pickedNode;
|
|
} else if (ContextMenuRegistry.check("legend-item", event)) {
|
|
this.pickedLegendItem = event.context.legendItem;
|
|
}
|
|
const expandedItems = this.expandItemsOptions(event);
|
|
if (expandedItems.length === 0)
|
|
return;
|
|
this.show(event.widgetEvent, expandedItems);
|
|
}
|
|
show(widgetEvent, expandedItems) {
|
|
const { sourceEvent } = widgetEvent;
|
|
this.interactionManager.pushState(_ModuleSupport68.InteractionState.ContextMenu);
|
|
this.element.style.display = "block";
|
|
const overrideFocusVisible = sourceEvent.pointerType === "touch" ? false : void 0;
|
|
if (overrideFocusVisible !== void 0) {
|
|
this.ctx.chartService.overrideFocusVisible(overrideFocusVisible);
|
|
}
|
|
this.createMenu(expandedItems);
|
|
this.element.appendChild(this.menuWidget.getElement());
|
|
this.menuWidget.expand({ sourceEvent, overrideFocusVisible });
|
|
}
|
|
hide() {
|
|
this.menuWidget.collapse();
|
|
}
|
|
onCollapse() {
|
|
this.interactionManager.popState(_ModuleSupport68.InteractionState.ContextMenu);
|
|
this.menuWidget.getElement().remove();
|
|
this.element.style.display = "none";
|
|
}
|
|
onSubMenuExpand(button, menu) {
|
|
const bounds = button.getBounds();
|
|
button.setFocusOverride(true);
|
|
button.getElement().insertAdjacentElement("afterend", menu.getElement());
|
|
menu.getElement().style.position = "absolute";
|
|
const canvasRect = this.ctx.domManager.getBoundingClientRect();
|
|
const buttonClientRect = button.getBoundingClientRect();
|
|
const remainingSpaceOnRight = canvasRect.right - buttonClientRect.right;
|
|
const remainingSpaceOnLeft = buttonClientRect.left - canvasRect.left;
|
|
const { offsetWidth: menuOffsetWidth, offsetHeight: menuOffsetHeight } = menu.getElement();
|
|
let y = bounds.y;
|
|
if (canvasRect.height > menuOffsetHeight) {
|
|
const remainingSpaceOnBottom = canvasRect.bottom - buttonClientRect.top;
|
|
if (remainingSpaceOnBottom < menuOffsetHeight) {
|
|
y -= menuOffsetHeight - remainingSpaceOnBottom;
|
|
}
|
|
}
|
|
if (remainingSpaceOnRight >= menuOffsetWidth) {
|
|
menu.setBounds({ x: bounds.x + bounds.width, y });
|
|
} else {
|
|
const x = bounds.x - menuOffsetWidth;
|
|
const leftDelta = remainingSpaceOnLeft + x;
|
|
if (leftDelta >= 0) {
|
|
menu.setBounds({ x, y });
|
|
} else {
|
|
menu.setBounds({ x: x - leftDelta, y });
|
|
}
|
|
}
|
|
}
|
|
onSubMenuCollapse(button, menu) {
|
|
button.setFocusOverride(void 0);
|
|
this.collapsingSubMenus++;
|
|
menu.remove();
|
|
this.collapsingSubMenus--;
|
|
}
|
|
createMenu(expandedItems) {
|
|
const { menuWidget } = this;
|
|
menuWidget.clear();
|
|
menuWidget.setTabIndex(-1);
|
|
this.createMenuItems(menuWidget, expandedItems);
|
|
}
|
|
createMenuItems(menuWidget, expandedItems) {
|
|
for (const item of expandedItems) {
|
|
switch (item.type) {
|
|
case "separator": {
|
|
const sep = menuWidget.addSeparator();
|
|
sep.classList.add(`${DEFAULT_CONTEXT_MENU_CLASS}__divider`);
|
|
break;
|
|
}
|
|
case "action": {
|
|
if (item.items.length === 0) {
|
|
const btn = new _Widget4.MenuItemWidget();
|
|
this.initButtonElement(btn, item);
|
|
menuWidget.addChild(btn);
|
|
} else {
|
|
const { subMenuButton, subMenu } = menuWidget.addSubMenu();
|
|
subMenu.addClass(`${DEFAULT_CONTEXT_MENU_CLASS}__menu`);
|
|
subMenu.addListener("expand-widget", () => this.onSubMenuExpand(subMenuButton, subMenu));
|
|
subMenu.addListener("collapse-widget", () => this.onSubMenuCollapse(subMenuButton, subMenu));
|
|
this.initButtonElement(subMenuButton, item);
|
|
this.createMenuItems(subMenu, item.items);
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
throw new Error("unhandled case");
|
|
}
|
|
}
|
|
}
|
|
createButtonOnClick(showOn, callback4) {
|
|
if (ContextMenuRegistry.checkCallback("legend-item", showOn, callback4)) {
|
|
return (widgetEvent) => {
|
|
const event = widgetEvent.sourceEvent;
|
|
if (this.pickedLegendItem) {
|
|
const { seriesId, itemId, label } = this.pickedLegendItem;
|
|
const { chartService: chart } = this.ctx;
|
|
if (typeof itemId !== "string") {
|
|
Logger5.error(`unexpected itemId type: [${typeof itemId}] (expected [string])`);
|
|
return;
|
|
}
|
|
const series = chart.series.find((s) => s.id === seriesId);
|
|
const callers = [series?.properties, chart];
|
|
const apiEvent = {
|
|
type: "contextmenu",
|
|
seriesId,
|
|
itemId,
|
|
text: toPlainText(label.text),
|
|
event
|
|
};
|
|
callWithContext(callers, callback4, apiEvent);
|
|
this.hide();
|
|
} else {
|
|
Logger5.error("legend item not found");
|
|
}
|
|
};
|
|
} else if (ContextMenuRegistry.checkCallback("series-area", showOn, callback4)) {
|
|
return () => {
|
|
const caller = this.ctx.chartService;
|
|
const apiEvent = { type: "seriesContextMenuAction", event: this.showEvent };
|
|
callWithContext(caller, callback4, apiEvent);
|
|
this.hide();
|
|
};
|
|
} else if (ContextMenuRegistry.checkCallback("series-node", showOn, callback4)) {
|
|
return () => {
|
|
const { showEvent } = this;
|
|
const { chartService: chart } = this.ctx;
|
|
const pickedNode = this.pickedNode;
|
|
const callers = [pickedNode?.series.properties, chart];
|
|
const apiEvent = pickedNode?.series.createNodeContextMenuActionEvent(showEvent, pickedNode);
|
|
if (apiEvent) {
|
|
callWithContext(callers, callback4, apiEvent);
|
|
} else {
|
|
Logger5.error("series node not found");
|
|
}
|
|
this.hide();
|
|
};
|
|
}
|
|
return () => {
|
|
const caller = this.ctx.chartService;
|
|
const apiEvent = { type: "contextMenuEvent", event: this.showEvent };
|
|
callWithContext(caller, callback4, apiEvent);
|
|
this.hide();
|
|
};
|
|
}
|
|
initTableCells(elem) {
|
|
const cellIcon = createElement5("div");
|
|
const cellLabel = createElement5("div");
|
|
const cellArrow = createElement5("div");
|
|
cellIcon.classList.toggle(`${DEFAULT_CONTEXT_MENU_CLASS}__icon`, true);
|
|
cellLabel.classList.toggle(`${DEFAULT_CONTEXT_MENU_CLASS}__cell`, true);
|
|
cellArrow.classList.toggle(`${DEFAULT_CONTEXT_MENU_CLASS}__cell`, true);
|
|
cellIcon.ariaHidden = "true";
|
|
cellLabel.role = "presentation";
|
|
cellArrow.ariaHidden = "true";
|
|
elem.append(cellIcon, cellLabel, cellArrow);
|
|
return { cellIcon, cellLabel, cellArrow };
|
|
}
|
|
initButtonElement(button, item) {
|
|
button.addClass(`${DEFAULT_CONTEXT_MENU_CLASS}__item`);
|
|
button.setEnabled(item.enabled);
|
|
const label = this.ctx.localeManager.t(item.label);
|
|
const cellPaddingClass = `${DEFAULT_CONTEXT_MENU_CLASS}__cellpadding`;
|
|
const { cellIcon, cellLabel, cellArrow } = this.initTableCells(button.getElement());
|
|
cellLabel.textContent = label;
|
|
cellLabel.classList.add(cellPaddingClass);
|
|
if (item.iconUrl != null) {
|
|
const img = createElement5("img");
|
|
img.src = item.iconUrl;
|
|
cellIcon.append(img);
|
|
cellIcon.classList.add(cellPaddingClass);
|
|
}
|
|
if (item.items.length > 0) {
|
|
const span = createElement5("span", getIconClassNames3("chevron-right"));
|
|
cellArrow.append(span);
|
|
cellArrow.classList.add(cellPaddingClass);
|
|
}
|
|
const { showOn, action } = item;
|
|
if (action != null) {
|
|
button.addListener("click", this.createButtonOnClick(showOn, action));
|
|
}
|
|
if (item.items.length === 0) {
|
|
button.addListener("mouseleave", () => button.setFocusOverride(false));
|
|
button.addListener("mouseenter", () => button.setFocusOverride(void 0));
|
|
}
|
|
}
|
|
reposition() {
|
|
let { x, y } = this;
|
|
this.element.style.top = "unset";
|
|
this.element.style.bottom = "unset";
|
|
const canvasRect = this.ctx.domManager.getBoundingClientRect();
|
|
const { offsetWidth: width, offsetHeight: height } = this.element;
|
|
x = clamp5(0, x, canvasRect.width - width);
|
|
y = clamp5(0, y, canvasRect.height - height);
|
|
this.element.style.left = `${x}px`;
|
|
this.element.style.top = `calc(${y}px - 0.5em)`;
|
|
}
|
|
destroy() {
|
|
super.destroy();
|
|
this.mutationObserver?.disconnect();
|
|
this.ctx.domManager.removeStyles(moduleId2);
|
|
this.ctx.domManager.removeChild("canvas-overlay", moduleId2);
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property40
|
|
], ContextMenu.prototype, "enabled", 2);
|
|
__decorateClass([
|
|
Property40
|
|
], ContextMenu.prototype, "darkTheme", 2);
|
|
__decorateClass([
|
|
Property40
|
|
], ContextMenu.prototype, "items", 2);
|
|
__decorateClass([
|
|
Property40
|
|
], ContextMenu.prototype, "getItems", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/features/context-menu/contextMenuModule.ts
|
|
var ContextMenuModule = {
|
|
type: "plugin",
|
|
name: "contextMenu",
|
|
enterprise: true,
|
|
version: VERSION10,
|
|
options: {
|
|
enabled: boolean3,
|
|
items: contextMenuItemsArray,
|
|
getItems: callbackOf(contextMenuItemsArray, "a menu items array")
|
|
},
|
|
themeTemplate: {
|
|
enabled: true,
|
|
darkTheme: IS_DARK_THEME
|
|
},
|
|
create: (ctx) => new ContextMenu(ctx)
|
|
};
|
|
ContextMenuModule.options.darkTheme = undocumented2(boolean3);
|
|
|
|
// packages/ag-charts-enterprise/src/features/crosshair/crosshairModule.ts
|
|
import { VERSION as VERSION11 } from "ag-charts-community";
|
|
|
|
// packages/ag-charts-enterprise/src/features/crosshair/crosshair.ts
|
|
import { _ModuleSupport as _ModuleSupport70 } from "ag-charts-community";
|
|
import {
|
|
AbstractModuleInstance as AbstractModuleInstance8,
|
|
ChartAxisDirection as ChartAxisDirection11,
|
|
ChartUpdateType as ChartUpdateType5,
|
|
Property as Property42,
|
|
ZIndexMap as ZIndexMap6,
|
|
createId as createId4,
|
|
toPlainText as toPlainText2
|
|
} from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/utils/datum.ts
|
|
function readDatum(nodeDatum) {
|
|
if (typeof nodeDatum?.datum === "object") {
|
|
return nodeDatum.datum;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
// packages/ag-charts-enterprise/src/features/crosshair/crosshairLabel.ts
|
|
import { _ModuleSupport as _ModuleSupport69 } from "ag-charts-community";
|
|
import { BaseProperties as BaseProperties16, Property as Property41, createId as createId3, setAttribute as setAttribute2 } from "ag-charts-core";
|
|
var { FormatManager } = _ModuleSupport69;
|
|
var DEFAULT_LABEL_CLASS = "ag-charts-crosshair-label";
|
|
var CrosshairLabelProperties = class extends BaseProperties16 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.enabled = true;
|
|
this.xOffset = 0;
|
|
this.yOffset = 0;
|
|
this.format = void 0;
|
|
this.renderer = void 0;
|
|
this._cachedFormatter = void 0;
|
|
}
|
|
formatValue(callWithContext3, type, value, params) {
|
|
const { formatter, format } = this;
|
|
const { domain, boundSeries } = params;
|
|
let result;
|
|
if (formatter != null) {
|
|
const fractionDigits = params.type === "number" ? params.fractionDigits : void 0;
|
|
const unit = params.type === "date" ? params.unit : void 0;
|
|
const step = params.type === "date" ? params.step : void 0;
|
|
result = callWithContext3(formatter, { value, domain, fractionDigits, unit, step, boundSeries });
|
|
}
|
|
if (format != null) {
|
|
let cachedFormatter = this._cachedFormatter;
|
|
if (cachedFormatter?.type !== type || cachedFormatter?.format !== format) {
|
|
cachedFormatter = {
|
|
type,
|
|
format,
|
|
formatter: FormatManager.getFormatter(type, format)
|
|
};
|
|
this._cachedFormatter = cachedFormatter;
|
|
}
|
|
result ?? (result = cachedFormatter.formatter?.(value));
|
|
}
|
|
return result == null ? void 0 : String(result);
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property41
|
|
], CrosshairLabelProperties.prototype, "enabled", 2);
|
|
__decorateClass([
|
|
Property41
|
|
], CrosshairLabelProperties.prototype, "xOffset", 2);
|
|
__decorateClass([
|
|
Property41
|
|
], CrosshairLabelProperties.prototype, "yOffset", 2);
|
|
__decorateClass([
|
|
Property41
|
|
], CrosshairLabelProperties.prototype, "formatter", 2);
|
|
__decorateClass([
|
|
Property41
|
|
], CrosshairLabelProperties.prototype, "format", 2);
|
|
__decorateClass([
|
|
Property41
|
|
], CrosshairLabelProperties.prototype, "renderer", 2);
|
|
var CrosshairLabel = class extends CrosshairLabelProperties {
|
|
constructor(domManager, key, axisId) {
|
|
super();
|
|
this.domManager = domManager;
|
|
this.id = createId3(this);
|
|
this.element = domManager.addChild("canvas-overlay", `crosshair-label-${this.id}`);
|
|
this.element.classList.add(DEFAULT_LABEL_CLASS);
|
|
setAttribute2(this.element, "aria-hidden", true);
|
|
this.element.dataset.key = key;
|
|
this.element.dataset.axisId = axisId;
|
|
}
|
|
show(meta) {
|
|
const { element } = this;
|
|
const left = meta.x + this.xOffset;
|
|
const top = meta.y + this.yOffset;
|
|
element.style.top = `${Math.round(top)}px`;
|
|
element.style.left = `${Math.round(left)}px`;
|
|
this.toggle(true);
|
|
}
|
|
setLabelHtml({ html, styles }) {
|
|
if (html !== void 0) {
|
|
this.element.innerHTML = html;
|
|
}
|
|
if (styles !== void 0) {
|
|
const styleElement = this.element.children[0] ?? this.element;
|
|
Object.assign(styleElement.style, styles);
|
|
}
|
|
}
|
|
getBBox() {
|
|
const { element } = this;
|
|
return new _ModuleSupport69.BBox(
|
|
element.clientLeft,
|
|
element.clientTop,
|
|
element.clientWidth,
|
|
element.clientHeight
|
|
);
|
|
}
|
|
toggle(visible) {
|
|
this.element.classList.toggle(`ag-charts-crosshair-label--hidden`, !visible);
|
|
}
|
|
destroy() {
|
|
this.domManager.removeChild("canvas-overlay", `crosshair-label-${this.id}`);
|
|
}
|
|
toLabelHtml(input, defaults) {
|
|
if (typeof input === "string") {
|
|
return { html: input, styles: {} };
|
|
}
|
|
defaults = defaults ?? {};
|
|
const {
|
|
text: text2 = defaults.text ?? "",
|
|
color: color7 = defaults.color,
|
|
backgroundColor = defaults.backgroundColor,
|
|
opacity = defaults.opacity ?? 1
|
|
} = input;
|
|
const styles = {
|
|
opacity,
|
|
"background-color": backgroundColor?.toLowerCase(),
|
|
color: color7
|
|
};
|
|
return {
|
|
html: `<div class="ag-charts-crosshair-label-content">
|
|
<span>${text2}</span>
|
|
</div>`,
|
|
styles
|
|
};
|
|
}
|
|
};
|
|
CrosshairLabel.className = "CrosshairLabel";
|
|
|
|
// packages/ag-charts-enterprise/src/features/crosshair/crosshair.ts
|
|
var { Group: Group5, TranslatableGroup: TranslatableGroup2, Line: Line4, BBox: BBox5, InteractionState: InteractionState4 } = _ModuleSupport70;
|
|
var Crosshair = class extends AbstractModuleInstance8 {
|
|
constructor(ctx) {
|
|
super();
|
|
this.ctx = ctx;
|
|
this.id = createId4(this);
|
|
this.enabled = false;
|
|
this.stroke = "rgb(195, 195, 195)";
|
|
this.lineDash = [6, 3];
|
|
this.lineDashOffset = 0;
|
|
this.strokeWidth = 1;
|
|
this.strokeOpacity = 1;
|
|
this.snap = true;
|
|
this.label = new CrosshairLabelProperties();
|
|
this.seriesRect = new BBox5(0, 0, 0, 0);
|
|
this.bounds = new BBox5(0, 0, 0, 0);
|
|
this.crosshairGroup = new TranslatableGroup2({
|
|
name: "crosshairs",
|
|
zIndex: ZIndexMap6.SERIES_CROSSHAIR
|
|
});
|
|
this.lineGroup = this.crosshairGroup.appendChild(
|
|
new Group5({
|
|
name: `${this.id}-crosshair-lines`,
|
|
zIndex: ZIndexMap6.SERIES_CROSSHAIR
|
|
})
|
|
);
|
|
this.lineGroupSelection = _ModuleSupport70.Selection.select(this.lineGroup, Line4, false);
|
|
this.activeHighlight = void 0;
|
|
this.axisCtx = ctx.parent;
|
|
this.labels = {};
|
|
this.hideCrosshairs();
|
|
ctx.domManager.addEventListener("focusin", ({ target }) => {
|
|
if (this.checkInteractionState())
|
|
return;
|
|
const isSeriesAreaChild = target instanceof HTMLElement && ctx.domManager.contains(target, "series-area");
|
|
if (this.crosshairGroup.visible && !isSeriesAreaChild) {
|
|
this.hideCrosshairs();
|
|
this.ctx.updateService.update(ChartUpdateType5.SCENE_RENDER);
|
|
}
|
|
});
|
|
const { seriesDragInterpreter } = ctx.widgets;
|
|
this.cleanup.register(
|
|
ctx.scene.attachNode(this.crosshairGroup),
|
|
ctx.widgets.seriesWidget.addListener("mousemove", (event) => this.onMouseHoverLike(event)),
|
|
ctx.widgets.seriesWidget.addListener("mouseleave", () => this.onMouseOut()),
|
|
ctx.eventsHub.on("series:focus-change", () => this.onKeyPress()),
|
|
ctx.eventsHub.on("zoom:pan-start", () => this.onMouseOut()),
|
|
ctx.eventsHub.on("zoom:change-complete", () => this.onMouseOut()),
|
|
ctx.eventsHub.on("highlight:change", (event) => this.onHighlightChange(event)),
|
|
ctx.eventsHub.on("layout:complete", (event) => this.layout(event)),
|
|
() => {
|
|
for (const label of Object.values(this.labels)) {
|
|
label.destroy();
|
|
}
|
|
}
|
|
);
|
|
if (seriesDragInterpreter) {
|
|
this.cleanup.register(
|
|
seriesDragInterpreter.events.on("drag-move", (event) => this.onMouseHoverLike(event)),
|
|
seriesDragInterpreter.events.on("click", (event) => this.onClick(event))
|
|
);
|
|
}
|
|
}
|
|
checkInteractionState() {
|
|
return this.ctx.interactionManager.isState(InteractionState4.Frozen);
|
|
}
|
|
layout({ series: { rect, visible }, axes }) {
|
|
if (!visible || !axes || !this.enabled)
|
|
return;
|
|
this.seriesRect = rect;
|
|
const { position: axisPosition = "left", axisId } = this.axisCtx;
|
|
const axisLayout = axes[axisId];
|
|
if (!axisLayout)
|
|
return;
|
|
this.axisLayout = axisLayout;
|
|
this.bounds = rect.clone().grow(axisLayout.gridPadding + axisLayout.seriesAreaPadding, axisPosition);
|
|
const { crosshairGroup, bounds } = this;
|
|
crosshairGroup.translationX = Math.round(bounds.x);
|
|
crosshairGroup.translationY = Math.round(bounds.y);
|
|
const crosshairKeys = ["pointer", ...this.axisCtx.seriesKeyProperties()];
|
|
this.updateSelections(crosshairKeys);
|
|
this.updateLines();
|
|
this.updateLabels(crosshairKeys);
|
|
this.refreshPositions();
|
|
}
|
|
updateSelections(data) {
|
|
this.lineGroupSelection.update(data, void 0, (key) => key);
|
|
}
|
|
updateLabels(keys) {
|
|
const { labels, ctx } = this;
|
|
for (const key of keys) {
|
|
if (this.label.enabled) {
|
|
labels[key] ?? (labels[key] = new CrosshairLabel(ctx.domManager, key, this.axisCtx.axisId));
|
|
}
|
|
if (labels[key]) {
|
|
this.updateLabel(labels[key]);
|
|
}
|
|
}
|
|
}
|
|
updateLabel(label) {
|
|
const { enabled, xOffset, yOffset, format, renderer } = this.label;
|
|
label.enabled = enabled;
|
|
label.xOffset = xOffset;
|
|
label.yOffset = yOffset;
|
|
label.format = format;
|
|
label.renderer = renderer;
|
|
}
|
|
updateLines() {
|
|
const { lineGroupSelection, bounds, stroke: stroke3, strokeWidth, strokeOpacity, lineDash, lineDashOffset, axisLayout } = this;
|
|
if (!axisLayout)
|
|
return;
|
|
const isVertical = this.isVertical();
|
|
lineGroupSelection.each((line) => {
|
|
line.stroke = stroke3;
|
|
line.strokeWidth = strokeWidth;
|
|
line.strokeOpacity = strokeOpacity;
|
|
line.lineDash = lineDash;
|
|
line.lineDashOffset = lineDashOffset;
|
|
line.y1 = 0;
|
|
line.y2 = isVertical ? bounds.height : 0;
|
|
line.x1 = 0;
|
|
line.x2 = isVertical ? 0 : bounds.width;
|
|
});
|
|
}
|
|
isVertical() {
|
|
return this.axisCtx.direction === ChartAxisDirection11.X;
|
|
}
|
|
isHover(event) {
|
|
return event.type === "mousemove" || event.type === "click" || event.device === "touch" && this.ctx.chartService.touch.dragAction === "hover";
|
|
}
|
|
formatValue(value) {
|
|
return toPlainText2(this.axisCtx.formatScaleValue(value, "crosshair", this.label));
|
|
}
|
|
onClick(event) {
|
|
if (event.device === "touch") {
|
|
this.onMouseHoverLike(event);
|
|
}
|
|
}
|
|
onMouseHoverLike(event) {
|
|
if (!this.enabled || this.snap)
|
|
return;
|
|
const requiredState = this.isHover(event) ? InteractionState4.Clickable : InteractionState4.AnnotationsMoveable;
|
|
if (!this.ctx.interactionManager.isState(requiredState))
|
|
return;
|
|
this.updatePositions(this.getData(event));
|
|
this.crosshairGroup.visible = true;
|
|
this.ctx.updateService.update(ChartUpdateType5.SCENE_RENDER);
|
|
}
|
|
onMouseOut() {
|
|
if (!this.ctx.interactionManager.isState(InteractionState4.Clickable))
|
|
return;
|
|
this.hideCrosshairs();
|
|
this.ctx.updateService.update(ChartUpdateType5.SCENE_RENDER);
|
|
}
|
|
onKeyPress() {
|
|
if (this.enabled && !this.snap && this.ctx.interactionManager.isState(InteractionState4.Default)) {
|
|
this.hideCrosshairs();
|
|
}
|
|
}
|
|
onHighlightChange(event) {
|
|
if (!this.enabled)
|
|
return;
|
|
const { crosshairGroup, axisCtx } = this;
|
|
const { datum, series } = event.currentHighlight ?? {};
|
|
const hasCrosshair = datum && (series?.axes.x?.id === axisCtx.axisId || series?.axes.y?.id === axisCtx.axisId);
|
|
this.activeHighlight = hasCrosshair ? event.currentHighlight : void 0;
|
|
if (!this.activeHighlight) {
|
|
this.hideCrosshairs();
|
|
} else if (this.snap) {
|
|
const activeHighlightData = this.getActiveHighlightData(this.activeHighlight);
|
|
this.updatePositions(activeHighlightData);
|
|
crosshairGroup.visible = true;
|
|
}
|
|
}
|
|
isInRange(value) {
|
|
return this.axisCtx.inRange(value);
|
|
}
|
|
refreshPositions() {
|
|
if (this.activeHighlight) {
|
|
this.updatePositions(this.getActiveHighlightData(this.activeHighlight));
|
|
}
|
|
}
|
|
updatePositions(data) {
|
|
const { seriesRect, lineGroupSelection } = this;
|
|
lineGroupSelection.each((line, key) => {
|
|
const lineData = data[key];
|
|
if (!lineData) {
|
|
line.visible = false;
|
|
this.hideLabel(key);
|
|
return;
|
|
}
|
|
line.visible = true;
|
|
const { value, position } = lineData;
|
|
let x = 0;
|
|
let y = 0;
|
|
if (this.isVertical()) {
|
|
x = position;
|
|
line.x = Math.round(x);
|
|
} else {
|
|
y = position;
|
|
line.y = Math.round(y);
|
|
}
|
|
if (this.label.enabled) {
|
|
this.showLabel(x + seriesRect.x, y + seriesRect.y, value, key);
|
|
} else {
|
|
this.hideLabel(key);
|
|
}
|
|
});
|
|
}
|
|
getData(event) {
|
|
const { axisCtx } = this;
|
|
const key = "pointer";
|
|
const { xKey = "", yKey = "" } = this.activeHighlight ?? {};
|
|
const { currentX, currentY } = event;
|
|
const datum = readDatum(this.activeHighlight);
|
|
const isVertical = this.isVertical();
|
|
const position = isVertical ? currentX : currentY;
|
|
let value = datum?.[isVertical ? xKey : yKey] ?? "";
|
|
if (axisCtx.continuous) {
|
|
value = axisCtx.scaleInvert(position);
|
|
}
|
|
return { [key]: { position, value } };
|
|
}
|
|
getActiveHighlightData(activeHighlight) {
|
|
const { axisCtx } = this;
|
|
const { series, xKey = "", aggregatedValue, cumulativeValue, midPoint } = activeHighlight;
|
|
const datum = readDatum(activeHighlight);
|
|
const seriesKeyProperties = series.getKeyProperties(axisCtx.direction);
|
|
const halfBandwidth = (axisCtx.scale.bandwidth ?? 0) / 2;
|
|
const matchingAxisId = series.axes[axisCtx.direction]?.id === axisCtx.axisId;
|
|
const isYKey = seriesKeyProperties.includes("yKey") && matchingAxisId;
|
|
const isXKey = seriesKeyProperties.includes("xKey") && matchingAxisId;
|
|
const datumValue = aggregatedValue ?? cumulativeValue;
|
|
if (isYKey && datumValue !== void 0) {
|
|
const position = axisCtx.scale.convert(datumValue) + halfBandwidth;
|
|
const isInRange = this.isInRange(position);
|
|
return isInRange ? {
|
|
yKey: { value: datumValue, position }
|
|
} : {};
|
|
}
|
|
if (isXKey) {
|
|
const position = (this.isVertical() ? midPoint?.x : midPoint?.y) ?? 0;
|
|
const value = axisCtx.continuous ? axisCtx.scaleInvert(position) : datum?.[xKey];
|
|
return this.isInRange(position) ? { xKey: { value, position } } : {};
|
|
}
|
|
const activeHighlightData = {};
|
|
for (const key of seriesKeyProperties) {
|
|
const keyValue = series.properties[key];
|
|
const value = datum?.[keyValue];
|
|
const position = axisCtx.scale.convert(value) + halfBandwidth;
|
|
const isInRange = this.isInRange(position);
|
|
if (isInRange) {
|
|
activeHighlightData[key] = { value, position };
|
|
}
|
|
}
|
|
return activeHighlightData;
|
|
}
|
|
getLabelHtml(value, label) {
|
|
const fractionDigits = this.axisLayout?.label?.fractionDigits ?? 0;
|
|
const defaults = { text: this.formatValue(value) };
|
|
if (this.label.renderer) {
|
|
return label.toLabelHtml(this.label.renderer({ value, fractionDigits }), defaults);
|
|
}
|
|
return label.toLabelHtml(defaults);
|
|
}
|
|
showLabel(x, y, value, key) {
|
|
if (!this.axisLayout)
|
|
return;
|
|
const { bounds } = this;
|
|
const label = this.labels[key];
|
|
const html = this.getLabelHtml(value, label);
|
|
label.setLabelHtml(html);
|
|
const { width, height } = label.getBBox();
|
|
const axisPosition = this.axisCtx.position;
|
|
let padding2 = this.axisLayout.label.spacing + this.axisLayout.tickSize;
|
|
if (this.axisCtx.direction === ChartAxisDirection11.X) {
|
|
padding2 -= 4;
|
|
label.show({
|
|
x: x - width / 2,
|
|
y: axisPosition === "bottom" ? bounds.y + bounds.height + padding2 : bounds.y - height - padding2
|
|
});
|
|
} else {
|
|
padding2 -= 8;
|
|
label.show({
|
|
x: axisPosition === "right" ? bounds.x + bounds.width + padding2 : bounds.x - width - padding2,
|
|
y: y - height / 2
|
|
});
|
|
}
|
|
}
|
|
hideCrosshairs() {
|
|
this.crosshairGroup.visible = false;
|
|
for (const key of Object.keys(this.labels)) {
|
|
this.hideLabel(key);
|
|
}
|
|
}
|
|
hideLabel(key) {
|
|
this.labels[key]?.toggle(false);
|
|
}
|
|
};
|
|
Crosshair.className = "Crosshair";
|
|
__decorateClass([
|
|
Property42
|
|
], Crosshair.prototype, "enabled", 2);
|
|
__decorateClass([
|
|
Property42
|
|
], Crosshair.prototype, "stroke", 2);
|
|
__decorateClass([
|
|
Property42
|
|
], Crosshair.prototype, "lineDash", 2);
|
|
__decorateClass([
|
|
Property42
|
|
], Crosshair.prototype, "lineDashOffset", 2);
|
|
__decorateClass([
|
|
Property42
|
|
], Crosshair.prototype, "strokeWidth", 2);
|
|
__decorateClass([
|
|
Property42
|
|
], Crosshair.prototype, "strokeOpacity", 2);
|
|
__decorateClass([
|
|
Property42
|
|
], Crosshair.prototype, "snap", 2);
|
|
__decorateClass([
|
|
Property42
|
|
], Crosshair.prototype, "label", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/features/crosshair/crosshairModule.ts
|
|
var CrosshairModule = {
|
|
type: "axis:plugin",
|
|
name: "crosshair",
|
|
chartType: "cartesian",
|
|
enterprise: true,
|
|
version: VERSION11,
|
|
themeTemplate: {
|
|
enabled: {
|
|
$if: [
|
|
{
|
|
$or: [
|
|
{ $eq: [{ $path: "../type" }, "number"] },
|
|
{ $eq: [{ $path: "../type" }, "log"] },
|
|
{ $eq: [{ $path: "../type" }, "time"] },
|
|
{ $eq: [{ $path: "../type" }, "unit-time"] },
|
|
{ $eq: [{ $path: "../type" }, "ordinal-time"] }
|
|
]
|
|
},
|
|
true,
|
|
false
|
|
]
|
|
},
|
|
snap: true,
|
|
stroke: { $ref: "subtleTextColor" },
|
|
strokeWidth: 1,
|
|
strokeOpacity: 1,
|
|
lineDash: [5, 6],
|
|
lineDashOffset: 0,
|
|
label: {
|
|
enabled: true
|
|
}
|
|
},
|
|
create: (ctx) => new Crosshair(ctx)
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/data-source/dataSourceModule.ts
|
|
import { VERSION as VERSION12 } from "ag-charts-community";
|
|
import { boolean as boolean4, callback, positiveNumber as positiveNumber2, undocumented as undocumented3 } from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/features/data-source/dataSource.ts
|
|
import "ag-charts-community";
|
|
import { AbstractModuleInstance as AbstractModuleInstance9, ActionOnSet as ActionOnSet6, Property as Property43 } from "ag-charts-core";
|
|
var DataSource = class extends AbstractModuleInstance9 {
|
|
constructor(ctx) {
|
|
super();
|
|
this.enabled = true;
|
|
this.getData = () => Promise.resolve();
|
|
this.dataService = ctx.dataService;
|
|
let dirty = false;
|
|
this.cleanup.register(
|
|
ctx.eventsHub.on("data:load", () => {
|
|
dirty = true;
|
|
}),
|
|
ctx.eventsHub.on("layout:complete", () => {
|
|
if (dirty) {
|
|
ctx.zoomManager.updateZoom({ source: "data-update", sourceDetail: "dataSource" });
|
|
}
|
|
})
|
|
);
|
|
}
|
|
updateCallback(enabled, getData) {
|
|
if (!this.dataService)
|
|
return;
|
|
if (enabled && getData != null) {
|
|
this.dataService.updateCallback(getData);
|
|
} else {
|
|
this.dataService.clearCallback();
|
|
}
|
|
}
|
|
};
|
|
__decorateClass([
|
|
ActionOnSet6({
|
|
newValue(enabled) {
|
|
this.updateCallback(enabled, this.getData);
|
|
}
|
|
}),
|
|
Property43
|
|
], DataSource.prototype, "enabled", 2);
|
|
__decorateClass([
|
|
ActionOnSet6({
|
|
newValue(getData) {
|
|
this.updateCallback(this.enabled, getData);
|
|
}
|
|
}),
|
|
Property43
|
|
], DataSource.prototype, "getData", 2);
|
|
__decorateClass([
|
|
ActionOnSet6({
|
|
newValue(requestThrottle) {
|
|
this.dataService.requestThrottle = requestThrottle;
|
|
}
|
|
})
|
|
], DataSource.prototype, "requestThrottle", 2);
|
|
__decorateClass([
|
|
ActionOnSet6({
|
|
newValue(updateThrottle) {
|
|
this.dataService.dispatchThrottle = updateThrottle;
|
|
}
|
|
})
|
|
], DataSource.prototype, "updateThrottle", 2);
|
|
__decorateClass([
|
|
ActionOnSet6({
|
|
newValue(updateDuringInteraction) {
|
|
this.dataService.dispatchOnlyLatest = !updateDuringInteraction;
|
|
}
|
|
})
|
|
], DataSource.prototype, "updateDuringInteraction", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/features/data-source/dataSourceModule.ts
|
|
var DataSourceModule = {
|
|
type: "plugin",
|
|
name: "dataSource",
|
|
enterprise: true,
|
|
version: VERSION12,
|
|
options: {
|
|
getData: callback,
|
|
requestThrottle: undocumented3(positiveNumber2),
|
|
updateThrottle: undocumented3(positiveNumber2),
|
|
updateDuringInteraction: undocumented3(boolean4)
|
|
},
|
|
create: (ctx) => new DataSource(ctx)
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/error-bar/errorBarModule.ts
|
|
import { VERSION as VERSION13 } from "ag-charts-community";
|
|
import { errorBarOptionsDefs } from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/features/error-bar/errorBar.ts
|
|
import { _ModuleSupport as _ModuleSupport73 } from "ag-charts-community";
|
|
import {
|
|
AbstractModuleInstance as AbstractModuleInstance10,
|
|
ChartAxisDirection as ChartAxisDirection12,
|
|
Logger as Logger6,
|
|
isDefined,
|
|
mergeDefaults as mergeDefaults2
|
|
} from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/features/error-bar/errorBarNode.ts
|
|
import { _ModuleSupport as _ModuleSupport72 } from "ag-charts-community";
|
|
import {
|
|
mergeDefaults,
|
|
nearestSquared,
|
|
nearestSquaredInContainer,
|
|
partialAssign
|
|
} from "ag-charts-core";
|
|
var { BBox: BBox6 } = _ModuleSupport72;
|
|
var HierarchicalBBox = class {
|
|
constructor(components) {
|
|
this.components = components;
|
|
this.union = BBox6.merge(components);
|
|
}
|
|
containsPoint(x, y) {
|
|
if (!this.union.containsPoint(x, y)) {
|
|
return false;
|
|
}
|
|
for (const bbox of this.components) {
|
|
if (bbox.containsPoint(x, y)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
};
|
|
var ErrorBarNode = class extends _ModuleSupport72.Group {
|
|
constructor() {
|
|
super();
|
|
this.capLength = Number.NaN;
|
|
this._datum = void 0;
|
|
this.whiskerPath = new _ModuleSupport72.Path();
|
|
this.capsPath = new _ModuleSupport72.Path();
|
|
this.bboxes = new HierarchicalBBox([]);
|
|
this.append([this.whiskerPath, this.capsPath]);
|
|
}
|
|
get datum() {
|
|
return this._datum;
|
|
}
|
|
set datum(datum) {
|
|
this._datum = datum;
|
|
}
|
|
calculateCapLength(capsTheme, capDefaults) {
|
|
const { lengthRatio = 1, length } = capsTheme;
|
|
const { lengthRatioMultiplier, lengthMax } = capDefaults;
|
|
const desiredLength = length ?? lengthRatio * lengthRatioMultiplier;
|
|
return Math.min(desiredLength, lengthMax);
|
|
}
|
|
getItemStylerParams(options, style, highlighted, highlightState) {
|
|
const { datum } = this;
|
|
if (datum == null || options.itemStyler == null)
|
|
return;
|
|
const { xLowerKey, xUpperKey, yLowerKey, yUpperKey } = options;
|
|
return {
|
|
...style,
|
|
datum: datum.datum,
|
|
seriesId: datum.series.id,
|
|
xKey: datum.xKey,
|
|
yKey: datum.yKey,
|
|
xLowerKey,
|
|
xUpperKey,
|
|
yLowerKey,
|
|
yUpperKey,
|
|
highlighted,
|
|
highlightState
|
|
};
|
|
}
|
|
formatStyles(style, options, caller, highlighted, highlightState) {
|
|
let { cap: capsStyle, ...whiskerStyle } = style;
|
|
const params = this.getItemStylerParams(options, style, highlighted, highlightState);
|
|
if (params != null && options.itemStyler != null) {
|
|
const result = caller.callWithContext(options.itemStyler, params);
|
|
whiskerStyle = mergeDefaults(result, whiskerStyle);
|
|
capsStyle = mergeDefaults(result?.cap, result, capsStyle);
|
|
}
|
|
return { whiskerStyle, capsStyle };
|
|
}
|
|
applyStyling(target, source) {
|
|
partialAssign(
|
|
["visible", "stroke", "strokeWidth", "strokeOpacity", "lineDash", "lineDashOffset"],
|
|
target,
|
|
source
|
|
);
|
|
}
|
|
update(style, formatters, caller, highlighted, highlightState) {
|
|
if (this.datum === void 0) {
|
|
return;
|
|
}
|
|
const { whiskerStyle, capsStyle } = this.formatStyles(style, formatters, caller, highlighted, highlightState);
|
|
const { xBar, yBar, capDefaults } = this.datum;
|
|
const whisker = this.whiskerPath;
|
|
this.applyStyling(whisker, whiskerStyle);
|
|
whisker.path.clear(true);
|
|
if (yBar !== void 0) {
|
|
whisker.path.moveTo(yBar.lowerPoint.x, yBar.lowerPoint.y);
|
|
whisker.path.lineTo(yBar.upperPoint.x, yBar.upperPoint.y);
|
|
}
|
|
if (xBar !== void 0) {
|
|
whisker.path.moveTo(xBar.lowerPoint.x, xBar.lowerPoint.y);
|
|
whisker.path.lineTo(xBar.upperPoint.x, xBar.upperPoint.y);
|
|
}
|
|
whisker.path.closePath();
|
|
this.capLength = this.calculateCapLength(capsStyle ?? {}, capDefaults);
|
|
const capOffset = this.capLength / 2;
|
|
const caps = this.capsPath;
|
|
this.applyStyling(caps, capsStyle);
|
|
caps.path.clear(true);
|
|
if (yBar !== void 0) {
|
|
caps.path.moveTo(yBar.lowerPoint.x - capOffset, yBar.lowerPoint.y);
|
|
caps.path.lineTo(yBar.lowerPoint.x + capOffset, yBar.lowerPoint.y);
|
|
caps.path.moveTo(yBar.upperPoint.x - capOffset, yBar.upperPoint.y);
|
|
caps.path.lineTo(yBar.upperPoint.x + capOffset, yBar.upperPoint.y);
|
|
}
|
|
if (xBar !== void 0) {
|
|
caps.path.moveTo(xBar.lowerPoint.x, xBar.lowerPoint.y - capOffset);
|
|
caps.path.lineTo(xBar.lowerPoint.x, xBar.lowerPoint.y + capOffset);
|
|
caps.path.moveTo(xBar.upperPoint.x, xBar.upperPoint.y - capOffset);
|
|
caps.path.lineTo(xBar.upperPoint.x, xBar.upperPoint.y + capOffset);
|
|
}
|
|
caps.path.closePath();
|
|
}
|
|
updateBBoxes() {
|
|
const { capLength, whiskerPath: whisker, capsPath: caps } = this;
|
|
const { yBar, xBar } = this.datum ?? {};
|
|
const capOffset = capLength / 2;
|
|
const components = [];
|
|
if (yBar !== void 0) {
|
|
const whiskerHeight = yBar.lowerPoint.y - yBar.upperPoint.y;
|
|
components.push(
|
|
new BBox6(yBar.lowerPoint.x, yBar.upperPoint.y, whisker.strokeWidth, whiskerHeight),
|
|
new BBox6(yBar.lowerPoint.x - capOffset, yBar.lowerPoint.y, capLength, caps.strokeWidth),
|
|
new BBox6(yBar.upperPoint.x - capOffset, yBar.upperPoint.y, capLength, caps.strokeWidth)
|
|
);
|
|
}
|
|
if (xBar !== void 0) {
|
|
const whiskerWidth = xBar.upperPoint.x - xBar.lowerPoint.x;
|
|
components.push(
|
|
new BBox6(xBar.lowerPoint.x, xBar.upperPoint.y, whiskerWidth, whisker.strokeWidth),
|
|
new BBox6(xBar.lowerPoint.x, xBar.lowerPoint.y - capOffset, caps.strokeWidth, capLength),
|
|
new BBox6(xBar.upperPoint.x, xBar.upperPoint.y - capOffset, caps.strokeWidth, capLength)
|
|
);
|
|
}
|
|
this.bboxes.components = components;
|
|
this.bboxes.union = BBox6.merge(components);
|
|
}
|
|
containsPoint(x, y) {
|
|
return this.bboxes.containsPoint(x, y);
|
|
}
|
|
pickNode(x, y) {
|
|
return this.containsPoint(x, y) ? this : void 0;
|
|
}
|
|
nearestSquared(x, y, maxDistance) {
|
|
const { bboxes } = this;
|
|
if (bboxes.union.distanceSquared(x, y) > maxDistance) {
|
|
return { nearest: void 0, distanceSquared: Infinity };
|
|
}
|
|
const { distanceSquared } = nearestSquared(x, y, bboxes.components);
|
|
return { nearest: this, distanceSquared };
|
|
}
|
|
};
|
|
var ErrorBarGroup = class extends _ModuleSupport72.Group {
|
|
nearestSquared(x, y) {
|
|
const { nearest, distanceSquared } = nearestSquaredInContainer(x, y, {
|
|
children: this.children()
|
|
});
|
|
if (nearest !== void 0 && !Number.isNaN(distanceSquared)) {
|
|
return { datum: nearest.datum, distanceSquared };
|
|
}
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/error-bar/errorBarProperties.ts
|
|
import "ag-charts-community";
|
|
import { BaseProperties as BaseProperties17, Property as Property44 } from "ag-charts-core";
|
|
var ErrorBarCap = class extends BaseProperties17 {
|
|
};
|
|
__decorateClass([
|
|
Property44
|
|
], ErrorBarCap.prototype, "visible", 2);
|
|
__decorateClass([
|
|
Property44
|
|
], ErrorBarCap.prototype, "stroke", 2);
|
|
__decorateClass([
|
|
Property44
|
|
], ErrorBarCap.prototype, "strokeWidth", 2);
|
|
__decorateClass([
|
|
Property44
|
|
], ErrorBarCap.prototype, "strokeOpacity", 2);
|
|
__decorateClass([
|
|
Property44
|
|
], ErrorBarCap.prototype, "lineDash", 2);
|
|
__decorateClass([
|
|
Property44
|
|
], ErrorBarCap.prototype, "lineDashOffset", 2);
|
|
__decorateClass([
|
|
Property44
|
|
], ErrorBarCap.prototype, "length", 2);
|
|
__decorateClass([
|
|
Property44
|
|
], ErrorBarCap.prototype, "lengthRatio", 2);
|
|
var ErrorBarProperties = class extends BaseProperties17 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.visible = true;
|
|
this.stroke = "black";
|
|
this.strokeWidth = 1;
|
|
this.strokeOpacity = 1;
|
|
this.cap = new ErrorBarCap();
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property44
|
|
], ErrorBarProperties.prototype, "yLowerKey", 2);
|
|
__decorateClass([
|
|
Property44
|
|
], ErrorBarProperties.prototype, "yLowerName", 2);
|
|
__decorateClass([
|
|
Property44
|
|
], ErrorBarProperties.prototype, "yUpperKey", 2);
|
|
__decorateClass([
|
|
Property44
|
|
], ErrorBarProperties.prototype, "yUpperName", 2);
|
|
__decorateClass([
|
|
Property44
|
|
], ErrorBarProperties.prototype, "xLowerKey", 2);
|
|
__decorateClass([
|
|
Property44
|
|
], ErrorBarProperties.prototype, "xLowerName", 2);
|
|
__decorateClass([
|
|
Property44
|
|
], ErrorBarProperties.prototype, "xUpperKey", 2);
|
|
__decorateClass([
|
|
Property44
|
|
], ErrorBarProperties.prototype, "xUpperName", 2);
|
|
__decorateClass([
|
|
Property44
|
|
], ErrorBarProperties.prototype, "visible", 2);
|
|
__decorateClass([
|
|
Property44
|
|
], ErrorBarProperties.prototype, "stroke", 2);
|
|
__decorateClass([
|
|
Property44
|
|
], ErrorBarProperties.prototype, "strokeWidth", 2);
|
|
__decorateClass([
|
|
Property44
|
|
], ErrorBarProperties.prototype, "strokeOpacity", 2);
|
|
__decorateClass([
|
|
Property44
|
|
], ErrorBarProperties.prototype, "lineDash", 2);
|
|
__decorateClass([
|
|
Property44
|
|
], ErrorBarProperties.prototype, "lineDashOffset", 2);
|
|
__decorateClass([
|
|
Property44
|
|
], ErrorBarProperties.prototype, "itemStyler", 2);
|
|
__decorateClass([
|
|
Property44
|
|
], ErrorBarProperties.prototype, "cap", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/features/error-bar/errorBar.ts
|
|
var { fixNumericExtent, groupAccumulativeValueProperty, valueProperty: valueProperty2 } = _ModuleSupport73;
|
|
var ErrorBars = class _ErrorBars extends AbstractModuleInstance10 {
|
|
constructor(ctx) {
|
|
super();
|
|
this.properties = new ErrorBarProperties();
|
|
const series = ctx.series;
|
|
const { annotationGroup, annotationSelections } = series;
|
|
this.cartesianSeries = series;
|
|
this.groupNode = new ErrorBarGroup({
|
|
name: `${annotationGroup.id}-errorBars`
|
|
});
|
|
annotationGroup.appendChild(this.groupNode);
|
|
this.selection = _ModuleSupport73.Selection.select(this.groupNode, () => this.errorBarFactory());
|
|
annotationSelections.add(this.selection);
|
|
series.addEventListener("seriesVisibilityChange", (e) => this.onToggleSeriesItem(e));
|
|
this.cleanup.register(
|
|
series.events.on("data-processed", (e) => this.onDataProcessed(e)),
|
|
series.events.on("data-update", (e) => this.onDataUpdate(e)),
|
|
ctx.eventsHub.on("highlight:change", (event) => this.onHighlightChange(event)),
|
|
() => this.groupNode.remove(),
|
|
() => annotationSelections.delete(this.selection)
|
|
);
|
|
}
|
|
hasErrorBars() {
|
|
const { xLowerKey, xUpperKey, yLowerKey, yUpperKey } = this.properties;
|
|
return isDefined(xLowerKey) && isDefined(xUpperKey) || isDefined(yLowerKey) && isDefined(yUpperKey);
|
|
}
|
|
isStacked() {
|
|
const stackCount = this.cartesianSeries.seriesGrouping?.stackCount;
|
|
return stackCount == null ? false : stackCount > 0;
|
|
}
|
|
getUnstackPropertyDefinition(opts) {
|
|
const props = [];
|
|
const { xLowerKey, xUpperKey, yLowerKey, yUpperKey, xErrorsID, yErrorsID } = this.getMaybeFlippedKeys();
|
|
const { xScaleType, yScaleType } = opts;
|
|
if (yLowerKey != null && yUpperKey != null) {
|
|
props.push(
|
|
valueProperty2(yLowerKey, yScaleType, { id: `${yErrorsID}-lower` }),
|
|
valueProperty2(yUpperKey, yScaleType, { id: `${yErrorsID}-upper` })
|
|
);
|
|
}
|
|
if (xLowerKey != null && xUpperKey != null) {
|
|
props.push(
|
|
valueProperty2(xLowerKey, xScaleType, { id: `${xErrorsID}-lower` }),
|
|
valueProperty2(xUpperKey, xScaleType, { id: `${xErrorsID}-upper` })
|
|
);
|
|
}
|
|
return props;
|
|
}
|
|
getStackPropertyDefinition(opts) {
|
|
const props = [];
|
|
const { cartesianSeries } = this;
|
|
const { xLowerKey, xUpperKey, yLowerKey, yUpperKey, xErrorsID, yErrorsID } = this.getMaybeFlippedKeys();
|
|
const { xScaleType, yScaleType } = opts;
|
|
const groupIndex = cartesianSeries.seriesGrouping?.groupIndex ?? cartesianSeries.id;
|
|
const groupOpts = {
|
|
invalidValue: null,
|
|
missingValue: 0,
|
|
separateNegative: true,
|
|
...cartesianSeries.visible ? {} : { forceValue: 0 }
|
|
};
|
|
const makeErrorProperty = (key, id, type, scaleType) => {
|
|
return groupAccumulativeValueProperty(
|
|
key,
|
|
"normal",
|
|
{
|
|
id: `${id}-${type}`,
|
|
groupId: `errorGroup-${groupIndex}-${type}`,
|
|
...groupOpts
|
|
},
|
|
scaleType
|
|
);
|
|
};
|
|
const pushErrorProperties = (lowerKey, upperKey, id, scaleType) => {
|
|
props.push(
|
|
...makeErrorProperty(lowerKey, id, "lower", scaleType),
|
|
...makeErrorProperty(upperKey, id, "upper", scaleType)
|
|
);
|
|
};
|
|
if (yLowerKey != null && yUpperKey != null) {
|
|
pushErrorProperties(yLowerKey, yUpperKey, yErrorsID, yScaleType);
|
|
}
|
|
if (xLowerKey != null && xUpperKey != null) {
|
|
pushErrorProperties(xLowerKey, xUpperKey, xErrorsID, xScaleType);
|
|
}
|
|
return props;
|
|
}
|
|
getPropertyDefinitions(opts) {
|
|
if (this.isStacked()) {
|
|
return this.getStackPropertyDefinition(opts);
|
|
} else {
|
|
return this.getUnstackPropertyDefinition(opts);
|
|
}
|
|
}
|
|
onDataProcessed(event) {
|
|
this.dataModel = event.dataModel;
|
|
this.processedData = event.processedData;
|
|
}
|
|
getDomain(direction) {
|
|
const { xLowerKey, xUpperKey, xErrorsID, yLowerKey, yUpperKey, yErrorsID } = this.getMaybeFlippedKeys();
|
|
const hasAxisErrors = direction === ChartAxisDirection12.X ? isDefined(xLowerKey) && isDefined(xUpperKey) : isDefined(yLowerKey) && isDefined(yUpperKey);
|
|
if (hasAxisErrors) {
|
|
const { dataModel, processedData, cartesianSeries: series } = this;
|
|
if (dataModel != null && processedData != null) {
|
|
const id = { x: xErrorsID, y: yErrorsID }[direction];
|
|
const lowerDomain = dataModel.getDomain(series, `${id}-lower`, "value", processedData).domain;
|
|
const upperDomain = dataModel.getDomain(series, `${id}-upper`, "value", processedData).domain;
|
|
const domain = [Math.min(...lowerDomain, ...upperDomain), Math.max(...lowerDomain, ...upperDomain)];
|
|
return fixNumericExtent(domain);
|
|
}
|
|
}
|
|
return [];
|
|
}
|
|
onDataUpdate(event) {
|
|
this.dataModel = event.dataModel;
|
|
this.processedData = event.processedData;
|
|
if (isDefined(event.dataModel) && isDefined(event.processedData)) {
|
|
this.createNodeData();
|
|
this.update();
|
|
}
|
|
}
|
|
getNodeData() {
|
|
return this.hasErrorBars() ? this.cartesianSeries.contextNodeData?.nodeData : void 0;
|
|
}
|
|
createNodeData() {
|
|
const nodeData = this.getNodeData();
|
|
const xScale = this.cartesianSeries.axes[ChartAxisDirection12.X]?.scale;
|
|
const yScale = this.cartesianSeries.axes[ChartAxisDirection12.Y]?.scale;
|
|
if (!xScale || !yScale || !nodeData) {
|
|
return;
|
|
}
|
|
for (let i = 0; i < nodeData.length; i++) {
|
|
const { midPoint, xLower, xUpper, yLower, yUpper } = this.getDatum(nodeData, i);
|
|
if (midPoint != null) {
|
|
let xBar, yBar;
|
|
if (isDefined(xLower) && isDefined(xUpper)) {
|
|
xBar = {
|
|
lowerPoint: { x: this.convert(xScale, xLower), y: midPoint.y },
|
|
upperPoint: { x: this.convert(xScale, xUpper), y: midPoint.y }
|
|
};
|
|
}
|
|
if (isDefined(yLower) && isDefined(yUpper)) {
|
|
yBar = {
|
|
lowerPoint: { x: midPoint.x, y: this.convert(yScale, yLower) },
|
|
upperPoint: { x: midPoint.x, y: this.convert(yScale, yUpper) }
|
|
};
|
|
}
|
|
nodeData[i].xBar = xBar;
|
|
nodeData[i].yBar = yBar;
|
|
}
|
|
}
|
|
}
|
|
getMaybeFlippedKeys() {
|
|
let { xLowerKey, xUpperKey, yLowerKey, yUpperKey } = this.properties;
|
|
let [xErrorsID, yErrorsID] = ["xValue-errors", "yValue-errors"];
|
|
if (this.cartesianSeries.shouldFlipXY()) {
|
|
[xLowerKey, yLowerKey] = [yLowerKey, xLowerKey];
|
|
[xUpperKey, yUpperKey] = [yUpperKey, xUpperKey];
|
|
[xErrorsID, yErrorsID] = [yErrorsID, xErrorsID];
|
|
}
|
|
return { xLowerKey, xUpperKey, xErrorsID, yLowerKey, yUpperKey, yErrorsID };
|
|
}
|
|
static getDatumKey(nodeDatum, key, offset) {
|
|
if (key == null) {
|
|
return;
|
|
}
|
|
const datum = readDatum(nodeDatum);
|
|
const value = datum?.[key];
|
|
if (value == null) {
|
|
return;
|
|
}
|
|
if (typeof value !== "number") {
|
|
Logger6.warnOnce(`Found [${key}] error value of type ${typeof value}. Expected number type`);
|
|
return;
|
|
}
|
|
return value + offset;
|
|
}
|
|
getDatum(nodeData, datumIndex) {
|
|
const { xLowerKey, xUpperKey, yLowerKey, yUpperKey } = this.getMaybeFlippedKeys();
|
|
const datum = nodeData[datumIndex];
|
|
const d = datum.cumulativeValue == null || !this.isStacked() ? 0 : datum.cumulativeValue - datum.yValue;
|
|
const [xOffset, yOffset] = this.cartesianSeries.shouldFlipXY() ? [d, 0] : [0, d];
|
|
return {
|
|
midPoint: datum.midPoint,
|
|
xLower: _ErrorBars.getDatumKey(datum, xLowerKey, xOffset),
|
|
xUpper: _ErrorBars.getDatumKey(datum, xUpperKey, xOffset),
|
|
yLower: _ErrorBars.getDatumKey(datum, yLowerKey, yOffset),
|
|
yUpper: _ErrorBars.getDatumKey(datum, yUpperKey, yOffset)
|
|
};
|
|
}
|
|
convert(scale, value) {
|
|
const offset = (scale.bandwidth ?? 0) / 2;
|
|
return scale.convert(value) + offset;
|
|
}
|
|
update() {
|
|
const nodeData = this.getNodeData();
|
|
if (nodeData != null) {
|
|
this.selection.update(nodeData);
|
|
this.selection.each((node, datum, i) => this.updateNode(node, datum, i));
|
|
}
|
|
}
|
|
updateNode(node, datum, _index) {
|
|
node.datum = datum;
|
|
node.update(this.getDefaultStyle(), this.properties, this.cartesianSeries, false, "none");
|
|
node.updateBBoxes();
|
|
}
|
|
pickNodeExact(point) {
|
|
const { x, y } = point;
|
|
const node = this.groupNode.pickNode(x, y);
|
|
if (node != null) {
|
|
return { datum: node.datum, distanceSquared: 0 };
|
|
}
|
|
}
|
|
pickNodeNearest(point) {
|
|
return this.groupNode.nearestSquared(point.x, point.y);
|
|
}
|
|
pickNodeMainAxisFirst(point, majorDirection) {
|
|
let closestDatum;
|
|
let closestDistance = [Infinity, Infinity];
|
|
const referencePoints = [point.x, point.y];
|
|
if (majorDirection === ChartAxisDirection12.Y) {
|
|
referencePoints.reverse();
|
|
}
|
|
for (const child of this.groupNode.children()) {
|
|
const childBBox = child.getBBox();
|
|
const childReferencePoints = [childBBox.x + childBBox.width / 2, childBBox.y + childBBox.height / 2];
|
|
if (majorDirection === ChartAxisDirection12.Y) {
|
|
childReferencePoints.reverse();
|
|
}
|
|
const childDistances = [];
|
|
for (let i = 0; i < referencePoints.length; i++) {
|
|
childDistances.push(Math.abs(referencePoints[i] - childReferencePoints[i]));
|
|
}
|
|
if (childDistances[0] < closestDistance[0] || childDistances[0] == closestDistance[0] && childDistances[1] < closestDistance[1]) {
|
|
closestDatum = child.datum;
|
|
closestDistance = childDistances;
|
|
}
|
|
}
|
|
if (closestDatum) {
|
|
return {
|
|
datum: closestDatum,
|
|
distanceSquared: Math.pow(closestDistance[0], 2) + Math.pow(closestDistance[1], 2)
|
|
};
|
|
}
|
|
}
|
|
getTooltipParams() {
|
|
const {
|
|
xLowerKey,
|
|
xUpperKey,
|
|
yLowerKey,
|
|
yUpperKey,
|
|
xLowerName = xLowerKey,
|
|
xUpperName = xUpperKey,
|
|
yLowerName = yLowerKey,
|
|
yUpperName = yUpperKey
|
|
} = this.properties;
|
|
return { xLowerKey, xLowerName, xUpperKey, xUpperName, yLowerKey, yLowerName, yUpperKey, yUpperName };
|
|
}
|
|
onToggleSeriesItem(event) {
|
|
this.groupNode.visible = event.visible;
|
|
}
|
|
makeStyle(baseStyle) {
|
|
return {
|
|
visible: baseStyle.visible,
|
|
lineDash: baseStyle.lineDash,
|
|
lineDashOffset: baseStyle.lineDashOffset,
|
|
stroke: baseStyle.stroke,
|
|
strokeWidth: baseStyle.strokeWidth,
|
|
strokeOpacity: baseStyle.strokeOpacity,
|
|
cap: mergeDefaults2(this.properties.cap, baseStyle)
|
|
};
|
|
}
|
|
getDefaultStyle() {
|
|
return this.makeStyle(this.getWhiskerProperties());
|
|
}
|
|
getHighlightStyle() {
|
|
return this.makeStyle(this.getWhiskerProperties());
|
|
}
|
|
restyleHighlightChange(highlightChange, style, highlighted) {
|
|
const nodeData = this.getNodeData();
|
|
if (nodeData == null)
|
|
return;
|
|
for (let i = 0; i < nodeData.length; i++) {
|
|
if (highlightChange === nodeData[i]) {
|
|
this.selection.at(i)?.update(
|
|
style,
|
|
this.properties,
|
|
this.cartesianSeries,
|
|
highlighted,
|
|
highlighted ? "highlighted-item" : "unhighlighted-item"
|
|
);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
onHighlightChange(event) {
|
|
const { previousHighlight, currentHighlight } = event;
|
|
if (currentHighlight?.series === this.cartesianSeries) {
|
|
this.restyleHighlightChange(currentHighlight, this.getHighlightStyle(), true);
|
|
}
|
|
if (previousHighlight?.series === this.cartesianSeries) {
|
|
this.restyleHighlightChange(previousHighlight, this.getDefaultStyle(), false);
|
|
}
|
|
this.groupNode.opacity = this.cartesianSeries.getOpacity();
|
|
}
|
|
errorBarFactory() {
|
|
return new ErrorBarNode();
|
|
}
|
|
getWhiskerProperties() {
|
|
const { stroke: stroke3, strokeWidth, visible, strokeOpacity, lineDash, lineDashOffset } = this.properties;
|
|
return { stroke: stroke3, strokeWidth, visible, strokeOpacity, lineDash, lineDashOffset };
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/error-bar/errorBarModule.ts
|
|
var ErrorBarsModule = {
|
|
type: "series:plugin",
|
|
name: "errorBar",
|
|
chartType: "cartesian",
|
|
seriesTypes: ["bar", "line", "scatter"],
|
|
enterprise: true,
|
|
version: VERSION13,
|
|
options: errorBarOptionsDefs,
|
|
themeTemplate: {
|
|
visible: true,
|
|
stroke: { $ref: "foregroundColor" },
|
|
strokeWidth: 1,
|
|
strokeOpacity: 1,
|
|
cap: {
|
|
lengthRatio: {
|
|
$if: [{ $eq: [{ $path: "../../type" }, "bar"] }, 0.3, 1]
|
|
}
|
|
}
|
|
},
|
|
create: (ctx) => new ErrorBars(ctx)
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/flash-on-update/flashOnUpdateModule.ts
|
|
import { VERSION as VERSION14 } from "ag-charts-community";
|
|
import { boolean as boolean5, color, positiveNumber as positiveNumber3, ratio, strictUnion } from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/features/flash-on-update/flashOnUpdate.ts
|
|
import { _ModuleSupport as _ModuleSupport74 } from "ag-charts-community";
|
|
import {
|
|
BaseProperties as BaseProperties18,
|
|
ChartAxisDirection as ChartAxisDirection13,
|
|
CleanupRegistry as CleanupRegistry4,
|
|
Property as Property45,
|
|
createElement as createElement6,
|
|
setAttribute as setAttribute3,
|
|
setElementBBox,
|
|
setElementStyle
|
|
} from "ag-charts-core";
|
|
function findPrimaryCategoryAxisContext(ctx) {
|
|
for (const dir of [ChartAxisDirection13.X, ChartAxisDirection13.Y]) {
|
|
for (const axisCtx of ctx.axisManager.getAxisContext(dir)) {
|
|
if (_ModuleSupport74.BandScale.is(axisCtx.scale)) {
|
|
return axisCtx;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
var FlashOnUpdate = class extends BaseProperties18 {
|
|
constructor(ctx) {
|
|
super();
|
|
this.ctx = ctx;
|
|
this.enabled = false;
|
|
this.item = "chart";
|
|
this.color = "#cfeeff";
|
|
this.opacity = 1;
|
|
this.flashDuration = 100;
|
|
this.fadeDuration = 900;
|
|
this.cleanup = new CleanupRegistry4();
|
|
this.element = this.ctx.domManager.addChild("canvas-background", "flashOnUpdate");
|
|
this.element.role = "presentation";
|
|
let firstUpdate = true;
|
|
const onDataUpdate = (ev) => {
|
|
if (firstUpdate) {
|
|
firstUpdate = false;
|
|
} else {
|
|
this.onDataUpdate(ev);
|
|
}
|
|
};
|
|
this.cleanup.register(
|
|
this.ctx.eventsHub.on("data:update", onDataUpdate),
|
|
this.ctx.eventsHub.on("datamodel:diff", (e) => this.onDataModelDiff(e))
|
|
);
|
|
}
|
|
destroy() {
|
|
this.ctx.domManager.removeChild("canvas-background", "flashOnUpdate");
|
|
this.cleanup.flush();
|
|
}
|
|
clearFlash() {
|
|
this.element.innerHTML = "";
|
|
clearTimeout(this.animationTimeout);
|
|
this.animationTimeout = void 0;
|
|
}
|
|
flashElem(el) {
|
|
const { flashDuration, fadeDuration } = this;
|
|
const duration = flashDuration + fadeDuration;
|
|
el.animate(
|
|
[
|
|
{ background: this.color, offset: 0 },
|
|
{ background: this.color, offset: flashDuration / duration },
|
|
{ background: "transparent", offset: 1 }
|
|
],
|
|
{ duration, easing: "ease-out" }
|
|
);
|
|
}
|
|
flashCategoryBands(diff8) {
|
|
const axisCtx = findPrimaryCategoryAxisContext(this.ctx);
|
|
if (!axisCtx)
|
|
return;
|
|
this.clearFlash();
|
|
const flashBounds = this.computeCategoryFlashBounds(axisCtx, diff8);
|
|
for (const bounds of flashBounds) {
|
|
const e = createElement6("div");
|
|
setAttribute3(e, "role", "presentation");
|
|
setElementStyle(e, "position", "absolute");
|
|
setElementBBox(e, bounds);
|
|
this.element.appendChild(e);
|
|
this.flashElem(e);
|
|
}
|
|
const duration = this.flashDuration + this.fadeDuration;
|
|
this.animationTimeout = setTimeout(() => this.clearFlash(), duration);
|
|
}
|
|
computeCategories(diff8) {
|
|
const result = /* @__PURE__ */ new Set();
|
|
for (const seriesId of Object.keys(diff8)) {
|
|
for (const key of ["updated", "added", "moved"]) {
|
|
for (const value of diff8[seriesId][key]) {
|
|
result.add(value);
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
computeCategoryFlashBounds(axisCtx, diff8) {
|
|
const seriesBounds = this.ctx.widgets.seriesWidget.getBounds();
|
|
const makeBox = axisCtx.direction === ChartAxisDirection13.X ? ([start, end]) => {
|
|
return {
|
|
x: seriesBounds.x + start,
|
|
y: seriesBounds.y,
|
|
width: end - start,
|
|
height: seriesBounds.height
|
|
};
|
|
} : ([start, end]) => {
|
|
return {
|
|
x: seriesBounds.x,
|
|
y: seriesBounds.y + start,
|
|
width: seriesBounds.width,
|
|
height: end - start
|
|
};
|
|
};
|
|
const result = [];
|
|
const categories = this.computeCategories(diff8);
|
|
for (const c of categories) {
|
|
const measurements = axisCtx.measureBand(c);
|
|
if (measurements?.band) {
|
|
result.push(makeBox(measurements.band));
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
onDataUpdate(ev) {
|
|
if (!this.enabled || this.item !== "chart" || !ev)
|
|
return;
|
|
this.flashElem(this.ctx.widgets.containerWidget.getElement());
|
|
}
|
|
onDataModelDiff(ev) {
|
|
if (!this.enabled || this.item !== "category")
|
|
return;
|
|
this.flashCategoryBands(ev.diff);
|
|
}
|
|
};
|
|
FlashOnUpdate.className = "FlashOnUpdate";
|
|
__decorateClass([
|
|
Property45
|
|
], FlashOnUpdate.prototype, "enabled", 2);
|
|
__decorateClass([
|
|
Property45
|
|
], FlashOnUpdate.prototype, "item", 2);
|
|
__decorateClass([
|
|
Property45
|
|
], FlashOnUpdate.prototype, "color", 2);
|
|
__decorateClass([
|
|
Property45
|
|
], FlashOnUpdate.prototype, "opacity", 2);
|
|
__decorateClass([
|
|
Property45
|
|
], FlashOnUpdate.prototype, "flashDuration", 2);
|
|
__decorateClass([
|
|
Property45
|
|
], FlashOnUpdate.prototype, "fadeDuration", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/features/flash-on-update/flashOnUpdateModule.ts
|
|
var FlashOnUpdateModule = {
|
|
type: "plugin",
|
|
name: "flashOnUpdate",
|
|
enterprise: true,
|
|
version: VERSION14,
|
|
options: {
|
|
enabled: boolean5,
|
|
item: strictUnion()("chart", "category"),
|
|
color,
|
|
opacity: ratio,
|
|
flashDuration: positiveNumber3,
|
|
fadeDuration: positiveNumber3
|
|
},
|
|
themeTemplate: {
|
|
enabled: false,
|
|
item: "chart",
|
|
color: "#cfeeff",
|
|
opacity: 1,
|
|
flashDuration: 100,
|
|
fadeDuration: 900
|
|
},
|
|
create: (ctx) => new FlashOnUpdate(ctx)
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/navigator/navigatorModule.ts
|
|
import { VERSION as VERSION22 } from "ag-charts-community";
|
|
|
|
// packages/ag-charts-enterprise/src/features/navigator/navigator.ts
|
|
import { _ModuleSupport as _ModuleSupport81 } from "ag-charts-community";
|
|
import { AbstractModuleInstance as AbstractModuleInstance12, Logger as Logger8, ObserveChanges as ObserveChanges4, Property as Property49, clamp as clamp7 } from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/features/navigator/miniChart.ts
|
|
import { _ModuleSupport as _ModuleSupport76 } from "ag-charts-community";
|
|
import {
|
|
AbstractModuleInstance as AbstractModuleInstance11,
|
|
ActionOnSet as ActionOnSet7,
|
|
Logger as Logger7,
|
|
Padding,
|
|
Property as Property46,
|
|
ProxyProperty as ProxyProperty2,
|
|
ZIndexMap as ZIndexMap7,
|
|
calcLineHeight as calcLineHeight4
|
|
} from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/features/navigator/shapes/miniChartGroup.ts
|
|
import { _ModuleSupport as _ModuleSupport75 } from "ag-charts-community";
|
|
import { SceneChangeDetection, getPath2D } from "ag-charts-core";
|
|
var { TranslatableGroup: TranslatableGroup3 } = _ModuleSupport75;
|
|
var MiniChartGroup = class extends TranslatableGroup3 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.inset = 0;
|
|
this.cornerRadius = 0;
|
|
}
|
|
applyClip(ctx, clipRect) {
|
|
const { cornerRadius, inset } = this;
|
|
const { x, y, width, height } = clipRect;
|
|
const Path2DCtor = getPath2D();
|
|
const path = new Path2DCtor();
|
|
path.roundRect(x + inset, y + inset, width - 2 * inset, height - 2 * inset, cornerRadius);
|
|
ctx.clip(path);
|
|
}
|
|
};
|
|
__decorateClass([
|
|
SceneChangeDetection()
|
|
], MiniChartGroup.prototype, "inset", 2);
|
|
__decorateClass([
|
|
SceneChangeDetection()
|
|
], MiniChartGroup.prototype, "cornerRadius", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/features/navigator/miniChart.ts
|
|
var { CategoryAxis, Group: Group6, BBox: BBox7, stackCartesianSeries } = _ModuleSupport76;
|
|
var MiniChartPadding = class {
|
|
constructor() {
|
|
this.top = 0;
|
|
this.bottom = 0;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property46
|
|
], MiniChartPadding.prototype, "top", 2);
|
|
__decorateClass([
|
|
Property46
|
|
], MiniChartPadding.prototype, "bottom", 2);
|
|
var MiniChart = class extends AbstractModuleInstance11 {
|
|
constructor(ctx) {
|
|
super();
|
|
this.ctx = ctx;
|
|
this.enabled = false;
|
|
this.padding = new MiniChartPadding();
|
|
this.root = new Group6({ name: "root" });
|
|
this.seriesRoot = this.root.appendChild(
|
|
new MiniChartGroup({ name: "Series-root", zIndex: ZIndexMap7.SERIES_LAYER, renderToOffscreenCanvas: true })
|
|
);
|
|
this.axisGridGroup = this.root.appendChild(new Group6({ name: "Axes-Grids", zIndex: ZIndexMap7.AXIS_GRID }));
|
|
this.axisGroup = this.root.appendChild(new Group6({ name: "Axes-Grids", zIndex: ZIndexMap7.AXIS_GRID }));
|
|
this.axisLabelGroup = this.root.appendChild(new Group6({ name: "Axes-Labels", zIndex: ZIndexMap7.SERIES_LABEL }));
|
|
this.axisCrosslineRangeGroup = this.root.appendChild(
|
|
new Group6({ name: "Axes-Crosslines-Range", zIndex: ZIndexMap7.SERIES_CROSSLINE_RANGE })
|
|
);
|
|
this.axisCrosslineLineGroup = this.root.appendChild(
|
|
new Group6({ name: "Axes-Crosslines-Line", zIndex: ZIndexMap7.SERIES_CROSSLINE_LINE })
|
|
);
|
|
this.axisCrosslineLabelGroup = this.root.appendChild(
|
|
new Group6({ name: "Axes-Crosslines-Label", zIndex: ZIndexMap7.SERIES_LABEL })
|
|
);
|
|
this.data = [];
|
|
this._destroyed = false;
|
|
this.miniChartAnimationPhase = "initial";
|
|
// Should be available after the first layout.
|
|
this.seriesRect = void 0;
|
|
this.axes = new _ModuleSupport76.ChartAxes();
|
|
this.series = [];
|
|
this.cleanup.register(this.ctx.eventsHub.on("data:update", (data) => this.updateData(data)));
|
|
}
|
|
destroy() {
|
|
if (this._destroyed) {
|
|
return;
|
|
}
|
|
super.destroy();
|
|
this.destroySeries(this.series);
|
|
this.axes.destroy();
|
|
this._destroyed = true;
|
|
}
|
|
onSeriesChange(newValue, oldValue) {
|
|
const seriesToDestroy = oldValue?.filter((series) => !newValue.includes(series)) ?? [];
|
|
this.destroySeries(seriesToDestroy);
|
|
for (const series of newValue) {
|
|
if (oldValue?.includes(series))
|
|
continue;
|
|
series.attachSeries(this.seriesRoot, this.seriesRoot, void 0);
|
|
series.chart = {};
|
|
Object.defineProperty(series.chart, "mode", {
|
|
get: () => "standalone"
|
|
});
|
|
Object.defineProperty(series.chart, "isMiniChart", {
|
|
get: () => true
|
|
});
|
|
Object.defineProperty(series.chart, "flashOnUpdateEnabled", {
|
|
get: () => false
|
|
});
|
|
Object.defineProperty(series.chart, "seriesRect", {
|
|
get: () => this.seriesRect
|
|
});
|
|
series.resetAnimation(this.miniChartAnimationPhase === "initial" ? "initial" : "disabled");
|
|
}
|
|
this.seriesRect = void 0;
|
|
}
|
|
destroySeries(allSeries) {
|
|
if (allSeries) {
|
|
for (const series of allSeries) {
|
|
series.destroy();
|
|
series.detachSeries(this.seriesRoot, this.seriesRoot, void 0);
|
|
series.chart = void 0;
|
|
}
|
|
}
|
|
}
|
|
assignSeriesToAxes() {
|
|
for (const axis of this.axes) {
|
|
axis.boundSeries = this.series.filter((s) => {
|
|
const seriesAxis = s.axes[axis.direction];
|
|
return seriesAxis === axis;
|
|
});
|
|
}
|
|
}
|
|
assignAxesToSeries() {
|
|
const directionToAxesMap = {};
|
|
for (const axis of this.axes) {
|
|
const direction = axis.direction;
|
|
const directionAxes = directionToAxesMap[direction] ?? (directionToAxesMap[direction] = []);
|
|
directionAxes.push(axis);
|
|
}
|
|
for (const series of this.series) {
|
|
for (const direction of series.directions) {
|
|
const seriesAxisId = series.getKeyAxis(direction) ?? direction;
|
|
const newAxis = this.axes.findById(seriesAxisId);
|
|
if (!newAxis) {
|
|
Logger7.warnOnce(
|
|
`no matching axis for direction [${direction}] and id [${seriesAxisId}]; check series and axes configuration.`
|
|
);
|
|
return;
|
|
}
|
|
series.axes[direction] = newAxis;
|
|
}
|
|
}
|
|
}
|
|
updateData(data) {
|
|
for (const s of this.series) {
|
|
s.setChartData(data);
|
|
}
|
|
if (this.miniChartAnimationPhase === "initial") {
|
|
this.ctx.animationManager.onBatchStop(() => {
|
|
this.miniChartAnimationPhase = "ready";
|
|
for (const s of this.series) {
|
|
s.resetAnimation("disabled");
|
|
}
|
|
});
|
|
}
|
|
}
|
|
async processData(dataController) {
|
|
if (this.series.some((s) => s.canHaveAxes)) {
|
|
this.assignAxesToSeries();
|
|
this.assignSeriesToAxes();
|
|
}
|
|
await Promise.all(
|
|
this.series.map(async (s) => {
|
|
s.resetDatumCallbackCache();
|
|
return s.processData(dataController);
|
|
})
|
|
);
|
|
for (const axis of this.axes) {
|
|
axis.processData();
|
|
}
|
|
}
|
|
computeAxisPadding() {
|
|
const padding2 = new Padding();
|
|
if (!this.enabled) {
|
|
return padding2;
|
|
}
|
|
for (const { position, thickness, line, label } of this.axes) {
|
|
if (position == null)
|
|
continue;
|
|
let size;
|
|
if (thickness) {
|
|
size = thickness;
|
|
} else {
|
|
size = (line.enabled ? line.width : 0) + (label.enabled ? calcLineHeight4(label.fontSize ?? 0) + label.spacing : 0);
|
|
}
|
|
padding2[position] = Math.ceil(size);
|
|
}
|
|
return padding2;
|
|
}
|
|
async layout(width, height) {
|
|
var _a;
|
|
const { padding: padding2 } = this;
|
|
const animated = this.seriesRect != null;
|
|
const seriesRect = new BBox7(0, 0, width, height - (padding2.top + padding2.bottom));
|
|
const resized = this.seriesRect?.width !== width || this.seriesRect?.height !== height;
|
|
this.seriesRect = seriesRect;
|
|
this.seriesRoot.translationY = padding2.top;
|
|
this.seriesRoot.setClipRectCanvasSpace(new BBox7(0, -padding2.top, width, height));
|
|
for (const axis of this.axes) {
|
|
const { position = "left" } = axis;
|
|
switch (position) {
|
|
case "top":
|
|
case "bottom":
|
|
axis.range = [0, seriesRect.width];
|
|
axis.gridLength = seriesRect.height;
|
|
break;
|
|
case "right":
|
|
case "left": {
|
|
const isCategoryAxis = axis instanceof CategoryAxis;
|
|
axis.range = isCategoryAxis ? [0, seriesRect.height] : [seriesRect.height, 0];
|
|
axis.gridLength = seriesRect.width;
|
|
break;
|
|
}
|
|
}
|
|
axis.gridPadding = 0;
|
|
axis.translation.x = 0;
|
|
axis.translation.y = 0;
|
|
if (position === "right") {
|
|
axis.translation.x = width;
|
|
} else if (position === "bottom") {
|
|
axis.translation.y = height;
|
|
}
|
|
if (!animated) {
|
|
axis.resetAnimation("initial");
|
|
}
|
|
if (axis.crossLines) {
|
|
for (const crossLine of axis.crossLines) {
|
|
if (crossLine instanceof _ModuleSupport76.CartesianCrossLine) {
|
|
crossLine.position = axis.position ?? "top";
|
|
(_a = crossLine.label).parallel ?? (_a.parallel = axis.label?.parallel);
|
|
}
|
|
}
|
|
}
|
|
axis.calculateLayout();
|
|
axis.update();
|
|
}
|
|
if (resized) {
|
|
stackCartesianSeries(this.series);
|
|
}
|
|
await Promise.all(this.series.map(async (series) => series.update({ seriesRect })));
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property46
|
|
], MiniChart.prototype, "enabled", 2);
|
|
__decorateClass([
|
|
ProxyProperty2(["seriesRoot", "inset"])
|
|
], MiniChart.prototype, "inset", 2);
|
|
__decorateClass([
|
|
ProxyProperty2(["seriesRoot", "cornerRadius"])
|
|
], MiniChart.prototype, "cornerRadius", 2);
|
|
__decorateClass([
|
|
ActionOnSet7({
|
|
changeValue(newValue, oldValue = new _ModuleSupport76.ChartAxes()) {
|
|
const axisNodes = {
|
|
axisNode: this.axisGroup,
|
|
gridNode: this.axisGridGroup,
|
|
labelNode: this.axisLabelGroup,
|
|
crossLineLineNode: this.axisCrosslineLineGroup,
|
|
crossLineRangeNode: this.axisCrosslineRangeGroup,
|
|
crossLineLabelNode: this.axisCrosslineLabelGroup
|
|
};
|
|
for (const axis of oldValue) {
|
|
if (newValue.includes(axis))
|
|
continue;
|
|
axis.detachAxis();
|
|
axis.destroy();
|
|
}
|
|
for (const axis of newValue) {
|
|
if (oldValue?.includes(axis))
|
|
continue;
|
|
axis.attachAxis(axisNodes);
|
|
}
|
|
}
|
|
})
|
|
], MiniChart.prototype, "axes", 2);
|
|
__decorateClass([
|
|
ActionOnSet7({
|
|
changeValue(newValue, oldValue) {
|
|
this.onSeriesChange(newValue, oldValue);
|
|
}
|
|
})
|
|
], MiniChart.prototype, "series", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/features/navigator/navigatorDOMProxy.ts
|
|
import { _ModuleSupport as _ModuleSupport77 } from "ag-charts-community";
|
|
import { clamp as clamp6 } from "ag-charts-core";
|
|
var { SliderWidget } = _ModuleSupport77;
|
|
var NavigatorDOMProxy = class {
|
|
constructor(ctx, sliderHandlers) {
|
|
this.ctx = ctx;
|
|
this.sliderHandlers = sliderHandlers;
|
|
this._min = 0;
|
|
this._max = 1;
|
|
this.minRange = 1e-3;
|
|
this.dragStartX = 0;
|
|
this.ctx = ctx;
|
|
this.toolbar = ctx.proxyInteractionService.createProxyContainer({
|
|
type: "toolbar",
|
|
domManagerId: `navigator-toolbar`,
|
|
classList: ["ag-charts-proxy-navigator-toolbar"],
|
|
orientation: "vertical",
|
|
ariaLabel: { id: "ariaLabelNavigator" }
|
|
});
|
|
this.sliders = [
|
|
ctx.proxyInteractionService.createProxyElement({
|
|
type: "slider",
|
|
domIndex: 1,
|
|
ariaLabel: { id: "ariaLabelNavigatorMinimum" },
|
|
parent: this.toolbar,
|
|
cursor: "ew-resize"
|
|
}),
|
|
ctx.proxyInteractionService.createProxyElement({
|
|
type: "slider",
|
|
domIndex: -Infinity,
|
|
ariaLabel: { id: "ariaLabelNavigatorRange" },
|
|
parent: this.toolbar,
|
|
cursor: "grab"
|
|
}),
|
|
ctx.proxyInteractionService.createProxyElement({
|
|
type: "slider",
|
|
domIndex: 2,
|
|
ariaLabel: { id: "ariaLabelNavigatorMaximum" },
|
|
parent: this.toolbar,
|
|
cursor: "ew-resize"
|
|
})
|
|
];
|
|
for (const [index, key] of ["min", "pan", "max"].entries()) {
|
|
const slider = this.sliders[index];
|
|
slider.step = SliderWidget.STEP_HUNDRETH;
|
|
slider.keyboardStep = SliderWidget.STEP_ONE;
|
|
slider.orientation = "horizontal";
|
|
slider.setPreventsDefault(false);
|
|
slider.addListener("drag-start", (ev) => this.onDragStart(index, ev, key));
|
|
slider.addListener("drag-move", (ev) => this.onDrag(slider, ev, key));
|
|
slider.addListener("drag-end", () => this.updateSliderRatios());
|
|
slider.addListener("contextmenu", (ev) => this.onContextMenu(slider, ev));
|
|
}
|
|
this.sliders[0].addListener("change", () => this.onMinSliderChange());
|
|
this.sliders[1].addListener("change", () => this.onPanSliderChange());
|
|
this.sliders[2].addListener("change", () => this.onMaxSliderChange());
|
|
this.updateSliderRatios();
|
|
this.updateVisibility(false);
|
|
}
|
|
destroy() {
|
|
this.toolbar.destroy();
|
|
}
|
|
updateVisibility(visible) {
|
|
this.toolbar.setHidden(!visible);
|
|
}
|
|
updateZoom() {
|
|
const { _min: min, _max: max } = this;
|
|
if (min == null || max == null)
|
|
return;
|
|
this.ctx.zoomManager.updateZoom(
|
|
{ source: "user-interaction", sourceDetail: "navigatorDOM" },
|
|
{ x: { min, max } }
|
|
);
|
|
}
|
|
updateBounds(bounds) {
|
|
this.toolbar.setBounds(bounds);
|
|
}
|
|
updateSliderBounds(sliderIndex, bounds) {
|
|
this.sliders[sliderIndex].setBounds(bounds);
|
|
}
|
|
updateMinMax(min, max) {
|
|
this._min = min;
|
|
this._max = max;
|
|
this.updateSliderRatios();
|
|
}
|
|
updateSliderRatios() {
|
|
let { _min: min, _max: max } = this;
|
|
min = Math.round(min * 100) / 100;
|
|
max = Math.round(max * 100) / 100;
|
|
const panAria = this.ctx.localeManager.t("ariaValuePanRange", { min, max });
|
|
this.sliders[0].setValueRatio(min);
|
|
this.sliders[1].setValueRatio(min, { ariaValueText: panAria });
|
|
this.sliders[2].setValueRatio(max);
|
|
}
|
|
toCanvasOffsets(event) {
|
|
return { offsetX: this.dragStartX + event.originDeltaX };
|
|
}
|
|
moveToFront(index) {
|
|
if (index === 1)
|
|
return;
|
|
const frontSlider = this.sliders[index];
|
|
const otherSlider = this.sliders[2 - index];
|
|
this.toolbar.moveChild(otherSlider, frontSlider.domIndex - 1);
|
|
}
|
|
onDragStart(index, event, key) {
|
|
const slider = this.sliders[index];
|
|
const toolbarLeft = this.toolbar.cssLeft();
|
|
const sliderLeft = slider.cssLeft();
|
|
this.dragStartX = toolbarLeft + sliderLeft + event.offsetX;
|
|
this.moveToFront(index);
|
|
event.sourceEvent.preventDefault();
|
|
this.sliderHandlers.onDragStart(key, this.toCanvasOffsets(event));
|
|
}
|
|
onDrag(_slider, event, key) {
|
|
event.sourceEvent.preventDefault();
|
|
this.sliderHandlers.onDrag(key, this.toCanvasOffsets(event));
|
|
}
|
|
onContextMenu(slider, widgetEvent) {
|
|
const { offsetX, offsetY } = widgetEvent;
|
|
const { x: toolbarX, y: toolbarY } = this.toolbar.getBounds();
|
|
const { x: sliderX, y: sliderY } = slider.getBounds();
|
|
const canvasX = offsetX + toolbarX + sliderX;
|
|
const canvasY = offsetY + toolbarY + sliderY;
|
|
this.ctx.contextMenuRegistry.dispatchContext("always", { widgetEvent, canvasX, canvasY }, void 0);
|
|
}
|
|
onPanSliderChange() {
|
|
const ratio8 = this.sliders[1].getValueRatio();
|
|
const span = this._max - this._min;
|
|
this._min = clamp6(0, ratio8, 1 - span);
|
|
this._max = this._min + span;
|
|
this.updateZoom();
|
|
}
|
|
onMinSliderChange() {
|
|
this._min = this.sliders[0].clampValueRatio(0, this._max - this.minRange);
|
|
this.updateZoom();
|
|
}
|
|
onMaxSliderChange() {
|
|
this._max = this.sliders[2].clampValueRatio(this._min + this.minRange, 1);
|
|
this.updateZoom();
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/navigator/shapes/rangeHandle.ts
|
|
import { _ModuleSupport as _ModuleSupport78 } from "ag-charts-community";
|
|
import { Property as Property47, SceneChangeDetection as SceneChangeDetection2 } from "ag-charts-core";
|
|
var { BBox: BBox8, ExtendedPath2D } = _ModuleSupport78;
|
|
var RangeHandle = class extends _ModuleSupport78.Path {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.zIndex = 3;
|
|
this.centerX = 0;
|
|
this.centerY = 0;
|
|
this.width = 8;
|
|
this.height = 16;
|
|
this.cornerRadius = 4;
|
|
this.grip = true;
|
|
this.gripPath = new ExtendedPath2D();
|
|
}
|
|
setCenter(x, y) {
|
|
this.dirtyPath = true;
|
|
if (this.centerX !== x || this.centerY !== y) {
|
|
this.centerX = x;
|
|
this.centerY = y;
|
|
this.markDirty("center");
|
|
}
|
|
}
|
|
static align(minHandle, maxHandle, x, y, width, height, min, max, pixelAlign) {
|
|
const minHandleX = minHandle.align(x + width * min) + pixelAlign;
|
|
const maxHandleX = minHandleX + minHandle.align(x + width * min, width * (max - min)) - 2 * pixelAlign;
|
|
const handleY = minHandle.align(y + height / 2);
|
|
minHandle.setCenter(minHandleX, handleY);
|
|
maxHandle.setCenter(maxHandleX, handleY);
|
|
}
|
|
computeBBox() {
|
|
const { centerX, centerY, width, height } = this;
|
|
const x = centerX - width / 2;
|
|
const y = centerY - height / 2;
|
|
return new BBox8(x, y, width, height);
|
|
}
|
|
isPointInPath(x, y) {
|
|
const bbox = this.getBBox();
|
|
return bbox.containsPoint(x, y);
|
|
}
|
|
updatePath() {
|
|
const { centerX, centerY, path, gripPath, strokeWidth, cornerRadius, grip } = this;
|
|
const pixelAlign = strokeWidth / 2;
|
|
const pixelRatio = this.layerManager?.canvas?.pixelRatio ?? 1;
|
|
path.clear();
|
|
gripPath.clear();
|
|
const halfWidth = Math.floor(this.width / 2 * pixelRatio) / pixelRatio;
|
|
const halfHeight = Math.floor(this.height / 2 * pixelRatio) / pixelRatio;
|
|
path.roundRect(
|
|
centerX - halfWidth + pixelAlign,
|
|
centerY - halfHeight + pixelAlign,
|
|
2 * (halfWidth - pixelAlign),
|
|
2 * (halfHeight - pixelAlign),
|
|
cornerRadius
|
|
);
|
|
const gripSpacing = 3;
|
|
if (grip) {
|
|
for (let x = -0.5; x <= 0.5; x += 1) {
|
|
for (let y = -1; y <= 1; y += 1) {
|
|
gripPath.arc(centerX + x * gripSpacing, centerY + y * gripSpacing, 1, 0, 2 * Math.PI);
|
|
gripPath.closePath();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
renderFill(ctx, path) {
|
|
const { stroke: stroke3 } = this;
|
|
super.renderFill(ctx, path);
|
|
ctx.fillStyle = typeof stroke3 === "string" ? stroke3 : "black";
|
|
ctx.fill(this.gripPath.getPath2D());
|
|
}
|
|
};
|
|
RangeHandle.className = "RangeHandle";
|
|
__decorateClass([
|
|
Property47,
|
|
SceneChangeDetection2()
|
|
], RangeHandle.prototype, "width", 2);
|
|
__decorateClass([
|
|
Property47,
|
|
SceneChangeDetection2()
|
|
], RangeHandle.prototype, "height", 2);
|
|
__decorateClass([
|
|
Property47,
|
|
SceneChangeDetection2()
|
|
], RangeHandle.prototype, "cornerRadius", 2);
|
|
__decorateClass([
|
|
Property47,
|
|
SceneChangeDetection2()
|
|
], RangeHandle.prototype, "grip", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/features/navigator/shapes/rangeMask.ts
|
|
import { _ModuleSupport as _ModuleSupport79 } from "ag-charts-community";
|
|
import { Property as Property48, SceneChangeDetection as SceneChangeDetection3 } from "ag-charts-core";
|
|
var { Path: Path6, BBox: BBox9, ExtendedPath2D: ExtendedPath2D2, clippedRoundRect } = _ModuleSupport79;
|
|
var RangeMask = class extends Path6 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.cornerRadius = 4;
|
|
this.zIndex = 2;
|
|
this.x = 0;
|
|
this.y = 0;
|
|
this.width = 200;
|
|
this.height = 30;
|
|
this.min = 0;
|
|
this.max = 1;
|
|
this.visiblePath = new ExtendedPath2D2();
|
|
}
|
|
layout(x, y, width, height, min, max) {
|
|
min = Number.isNaN(min) ? this.min : min;
|
|
max = Number.isNaN(max) ? this.max : max;
|
|
if (x !== this.x || y !== this.y || width !== this.width || this.height !== height || min !== this.min || max !== this.max) {
|
|
this.x = x;
|
|
this.y = y;
|
|
this.width = width;
|
|
this.height = height;
|
|
this.min = min;
|
|
this.max = max;
|
|
this.dirtyPath = true;
|
|
this.markDirty("RangeMask.layout");
|
|
}
|
|
}
|
|
computeBBox() {
|
|
const { x, y, width, height } = this;
|
|
return new BBox9(x, y, width, height);
|
|
}
|
|
computeVisibleRangeBBox() {
|
|
const { x, y, width, height, min, max } = this;
|
|
const minX = x + width * min;
|
|
const maxX = x + width * max;
|
|
return new BBox9(minX, y, maxX - minX, height);
|
|
}
|
|
updatePath() {
|
|
const { path, visiblePath, x, y, width, height, min, max, strokeWidth, cornerRadius } = this;
|
|
const pixelAlign = strokeWidth / 2;
|
|
path.clear();
|
|
visiblePath.clear();
|
|
const ax = this.align(x) + pixelAlign;
|
|
const ay = this.align(y) + pixelAlign;
|
|
const aw = this.align(x, width) - 2 * pixelAlign;
|
|
const ah = this.align(y, height) - 2 * pixelAlign;
|
|
const minX = this.align(x + width * min) + pixelAlign;
|
|
const maxX = minX + this.align(x + width * min, width * (max - min)) - 2 * pixelAlign;
|
|
const cornerRadiusParams = {
|
|
topLeft: cornerRadius,
|
|
topRight: cornerRadius,
|
|
bottomRight: cornerRadius,
|
|
bottomLeft: cornerRadius
|
|
};
|
|
const drawRect = (p, x0, x1) => {
|
|
if (x1 - x0 < 1)
|
|
return;
|
|
const bbox = new BBox9(x0, ay, x1 - x0, ah);
|
|
clippedRoundRect(p, ax, ay, aw, ah, cornerRadiusParams, bbox);
|
|
};
|
|
drawRect(path, ax, minX);
|
|
drawRect(path, maxX, aw + ax);
|
|
drawRect(visiblePath, minX, maxX);
|
|
}
|
|
renderStroke(ctx, path) {
|
|
super.renderStroke(ctx, path);
|
|
super.renderStroke(ctx, this.visiblePath.getPath2D());
|
|
}
|
|
};
|
|
RangeMask.className = "RangeMask";
|
|
__decorateClass([
|
|
Property48,
|
|
SceneChangeDetection3()
|
|
], RangeMask.prototype, "cornerRadius", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/features/navigator/shapes/rangeSelector.ts
|
|
import { _ModuleSupport as _ModuleSupport80 } from "ag-charts-community";
|
|
import { ZIndexMap as ZIndexMap8 } from "ag-charts-core";
|
|
var RangeSelector = class extends _ModuleSupport80.Group {
|
|
constructor(children) {
|
|
super({ name: "rangeSelectorGroup", zIndex: ZIndexMap8.NAVIGATOR });
|
|
this.x = 0;
|
|
this.y = 0;
|
|
this.width = 200;
|
|
this.height = 30;
|
|
this.lOffset = 0;
|
|
this.rOffset = 0;
|
|
this.background = this.appendChild(
|
|
new _ModuleSupport80.TranslatableGroup({ name: "navigator-background", zIndex: 1 })
|
|
);
|
|
this.append(children);
|
|
}
|
|
layout(x, y, width, height, lOffset, rOffset) {
|
|
this.x = x;
|
|
this.y = y;
|
|
this.width = width;
|
|
this.height = height;
|
|
this.lOffset = lOffset;
|
|
this.rOffset = rOffset;
|
|
this.background.translationX = x;
|
|
this.background.translationY = y;
|
|
this.markDirty("RangeSelector");
|
|
}
|
|
updateBackground(oldGroup, newGroup) {
|
|
if (oldGroup != null) {
|
|
oldGroup.remove();
|
|
}
|
|
if (newGroup != null) {
|
|
this.background.appendChild(newGroup);
|
|
}
|
|
this.markDirty("RangeSelector");
|
|
}
|
|
computeBBox() {
|
|
const { x, y, width, height, lOffset, rOffset } = this;
|
|
return new _ModuleSupport80.BBox(x - lOffset, y, width + (lOffset + rOffset), height);
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/navigator/navigator.ts
|
|
var Navigator = class extends AbstractModuleInstance12 {
|
|
constructor(ctx) {
|
|
super();
|
|
this.ctx = ctx;
|
|
this.enabled = false;
|
|
this.mask = new RangeMask();
|
|
this.minHandle = new RangeHandle();
|
|
this.maxHandle = new RangeHandle();
|
|
this.maskVisibleRange = {
|
|
id: "navigator-mask-visible-range",
|
|
getBBox: () => this.mask.computeVisibleRangeBBox(),
|
|
toCanvasBBox: () => this.mask.computeVisibleRangeBBox(),
|
|
fromCanvasPoint: (x, y) => ({ x, y })
|
|
};
|
|
this.height = 30;
|
|
this.cornerRadius = 0;
|
|
this.spacing = 10;
|
|
this.x = 0;
|
|
this.y = 0;
|
|
this.width = 0;
|
|
this.rangeSelector = new RangeSelector([this.mask, this.minHandle, this.maxHandle]);
|
|
this.cleanup.register(
|
|
ctx.scene.attachNode(this.rangeSelector),
|
|
ctx.eventsHub.on("locale:change", () => this.updateZoom()),
|
|
ctx.layoutManager.registerElement(_ModuleSupport81.LayoutElement.Navigator, (e) => this.onLayoutStart(e)),
|
|
ctx.eventsHub.on("layout:complete", (e) => this.onLayoutComplete(e)),
|
|
ctx.eventsHub.on("zoom:change-complete", (event) => this.onZoomChange(event))
|
|
);
|
|
this.domProxy = new NavigatorDOMProxy(ctx, this);
|
|
this.updateGroupVisibility();
|
|
this.miniChart = new MiniChart(ctx);
|
|
}
|
|
updateBackground(oldGroup, newGroup) {
|
|
this.rangeSelector?.updateBackground(oldGroup, newGroup);
|
|
}
|
|
updateGroupVisibility() {
|
|
const { enabled } = this;
|
|
if (this.rangeSelector == null || enabled === this.rangeSelector.visible)
|
|
return;
|
|
this.rangeSelector.visible = enabled;
|
|
this.domProxy.updateVisibility(enabled);
|
|
if (enabled) {
|
|
this.updateZoom();
|
|
} else {
|
|
this.ctx.zoomManager.updateZoom(
|
|
{ source: "chart-update", sourceDetail: "navigator" },
|
|
{ x: { min: 0, max: 1 } }
|
|
);
|
|
}
|
|
}
|
|
onLayoutStart({ layoutBox }) {
|
|
if (this.enabled) {
|
|
const navigatorTotalHeight = this.height + this.spacing;
|
|
layoutBox.shrink(navigatorTotalHeight, "bottom");
|
|
this.y = layoutBox.y + layoutBox.height + this.spacing;
|
|
} else {
|
|
this.y = 0;
|
|
}
|
|
if (this.enabled && this.miniChart) {
|
|
const { top, bottom } = this.miniChart.computeAxisPadding();
|
|
layoutBox.shrink(top + bottom, "bottom");
|
|
this.y -= bottom;
|
|
this.miniChart.inset = this.mask.strokeWidth / 2;
|
|
this.miniChart.cornerRadius = this.mask.cornerRadius;
|
|
}
|
|
}
|
|
onLayoutComplete(opts) {
|
|
const { x, width } = opts.series.rect;
|
|
const { y, height } = this;
|
|
this.domProxy.updateVisibility(this.enabled);
|
|
if (this.enabled) {
|
|
const { _min: min, _max: max } = this.domProxy;
|
|
this.layoutNodes(x, y, width, height, min, max);
|
|
this.domProxy.updateBounds({ x, y, width, height });
|
|
}
|
|
this.x = x;
|
|
this.width = width;
|
|
this.miniChart?.layout(width, height).catch((e) => Logger8.error(e));
|
|
}
|
|
canDrag() {
|
|
return this.enabled && this.ctx.interactionManager.isState(_ModuleSupport81.InteractionState.ZoomDraggable);
|
|
}
|
|
onDragStart(dragging, { offsetX }) {
|
|
if (!this.canDrag())
|
|
return;
|
|
if (dragging === "pan") {
|
|
this.panStart = (offsetX - this.x) / this.width - this.domProxy._min;
|
|
}
|
|
this.ctx.zoomManager.fireZoomPanStartEvent("navigator");
|
|
}
|
|
onDrag(dragging, { offsetX }) {
|
|
if (!this.canDrag())
|
|
return;
|
|
const { panStart, x, width } = this;
|
|
const { minRange } = this.domProxy;
|
|
let { _min: min, _max: max } = this.domProxy;
|
|
const ratio8 = (offsetX - x) / width;
|
|
if (dragging === "min") {
|
|
min = clamp7(0, ratio8, max - minRange);
|
|
} else if (dragging === "max") {
|
|
max = clamp7(min + minRange, ratio8, 1);
|
|
} else if (dragging === "pan" && panStart != null) {
|
|
const span = max - min;
|
|
min = clamp7(0, ratio8 - panStart, 1 - span);
|
|
max = min + span;
|
|
}
|
|
this.domProxy._min = min;
|
|
this.domProxy._max = max;
|
|
this.updateZoom();
|
|
}
|
|
onZoomChange(event) {
|
|
const { x: xZoom } = event;
|
|
if (!xZoom)
|
|
return;
|
|
const { x, y, width, height } = this;
|
|
const { min, max } = xZoom;
|
|
this.domProxy.updateMinMax(min, max);
|
|
this.layoutNodes(x, y, width, height, min, max);
|
|
}
|
|
layoutNodes(x, y, width, height, min, max) {
|
|
const { rangeSelector, mask, minHandle, maxHandle } = this;
|
|
mask.layout(x, y, width, height, min, max);
|
|
rangeSelector.layout(x, y, width, height, minHandle.width / 2, maxHandle.width / 2);
|
|
RangeHandle.align(minHandle, maxHandle, x, y, width, height, min, max, mask.strokeWidth / 2);
|
|
if (min + (max - min) / 2 < 0.5) {
|
|
minHandle.zIndex = 3;
|
|
maxHandle.zIndex = 4;
|
|
} else {
|
|
minHandle.zIndex = 4;
|
|
maxHandle.zIndex = 3;
|
|
}
|
|
for (const [index, node] of [minHandle, this.maskVisibleRange, maxHandle].entries()) {
|
|
const bbox = node.getBBox();
|
|
const tbox = { x: bbox.x - x, y: bbox.y - y, height: bbox.height, width: bbox.width };
|
|
this.domProxy.updateSliderBounds(index, tbox);
|
|
}
|
|
}
|
|
updateZoom() {
|
|
if (!this.enabled)
|
|
return;
|
|
this.domProxy.updateZoom();
|
|
}
|
|
async processData(dataController) {
|
|
return this.miniChart?.processData(dataController);
|
|
}
|
|
};
|
|
__decorateClass([
|
|
ObserveChanges4((target, value, oldValue) => {
|
|
target.updateBackground(oldValue?.root, value?.root);
|
|
})
|
|
], Navigator.prototype, "miniChart", 2);
|
|
__decorateClass([
|
|
Property49,
|
|
ObserveChanges4((target, value) => {
|
|
target.ctx.zoomManager.setNavigatorEnabled(Boolean(value));
|
|
target.updateGroupVisibility();
|
|
})
|
|
], Navigator.prototype, "enabled", 2);
|
|
__decorateClass([
|
|
Property49
|
|
], Navigator.prototype, "height", 2);
|
|
__decorateClass([
|
|
Property49,
|
|
ObserveChanges4((target, value) => {
|
|
target.mask.cornerRadius = value;
|
|
})
|
|
], Navigator.prototype, "cornerRadius", 2);
|
|
__decorateClass([
|
|
Property49
|
|
], Navigator.prototype, "spacing", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/features/navigator/navigatorOptionsDefs.ts
|
|
import {
|
|
AreaSeriesModule,
|
|
BarSeriesModule,
|
|
BubbleSeriesModule,
|
|
HistogramSeriesModule,
|
|
LineSeriesModule,
|
|
ScatterSeriesModule
|
|
} from "ag-charts-community";
|
|
import {
|
|
array,
|
|
arrayOfDefs as arrayOfDefs2,
|
|
boolean as boolean11,
|
|
callbackOf as callbackOf2,
|
|
color as color3,
|
|
fontOptionsDef,
|
|
number as number5,
|
|
numberFormatValidator,
|
|
positiveNumber as positiveNumber5,
|
|
ratio as ratio4,
|
|
textOrSegments,
|
|
typeUnion,
|
|
without as without2
|
|
} from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/series/box-plot/boxPlotModule.ts
|
|
import { CartesianChartModule, VERSION as VERSION15, _ModuleSupport as _ModuleSupport86 } from "ag-charts-community";
|
|
import { ChartAxisDirection as ChartAxisDirection16, DIRECTION_SWAP_AXES } from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/series/box-plot/boxPlotSeries.ts
|
|
import {
|
|
_ModuleSupport as _ModuleSupport84
|
|
} from "ag-charts-community";
|
|
import { ChartAxisDirection as ChartAxisDirection15, deepClone as deepClone2, mergeDefaults as mergeDefaults4 } from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/series/box-plot/blotPlotUtil.ts
|
|
function prepareBoxPlotFromTo(isVertical) {
|
|
const from = isVertical ? { scalingX: 1, scalingY: 0 } : { scalingX: 0, scalingY: 1 };
|
|
const to = { scalingX: 1, scalingY: 1 };
|
|
return { from, to };
|
|
}
|
|
function resetBoxPlotSelectionsScalingCenterFn(isVertical) {
|
|
return (_node, datum) => {
|
|
if (isVertical) {
|
|
return { scalingCenterY: datum.scaledValues.medianValue };
|
|
}
|
|
return { scalingCenterX: datum.scaledValues.medianValue };
|
|
};
|
|
}
|
|
|
|
// packages/ag-charts-enterprise/src/series/box-plot/boxPlotNode.ts
|
|
import { _ModuleSupport as _ModuleSupport82 } from "ag-charts-community";
|
|
import { SceneArrayChangeDetection, SceneChangeDetection as SceneChangeDetection4 } from "ag-charts-core";
|
|
var { Path: Path7, Scalable, ExtendedPath2D: ExtendedPath2D3, BBox: BBox10, clippedRoundRect: baseClippedRoundRect } = _ModuleSupport82;
|
|
var BoxPlotNode = class extends Scalable(Path7) {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.wickPath = new ExtendedPath2D3();
|
|
this.horizontal = false;
|
|
this.center = 0;
|
|
this.thickness = 0;
|
|
this.min = 0;
|
|
this.q1 = 0;
|
|
this.median = 0;
|
|
this.q3 = 0;
|
|
this.max = 0;
|
|
this.cornerRadius = 0;
|
|
this.crisp = false;
|
|
this.strokeAlignment = 0;
|
|
this.wickStroke = void 0;
|
|
this.wickStrokeWidth = void 0;
|
|
this.wickStrokeOpacity = void 0;
|
|
this.capLengthRatio = 1;
|
|
this.wickStrokeAlignment = 0;
|
|
}
|
|
computeBBox() {
|
|
const { horizontal, center, thickness, min, max } = this;
|
|
return horizontal ? new BBox10(Math.min(min, max), center - thickness / 2, Math.abs(max - min), thickness) : new BBox10(center - thickness / 2, Math.min(min, max), thickness, Math.abs(max - min));
|
|
}
|
|
computeDefaultGradientFillBBox() {
|
|
const { horizontal, center, thickness, q1, q3 } = this;
|
|
return horizontal ? new BBox10(Math.min(q1, q3), center - thickness / 2, Math.abs(q3 - q1), thickness) : new BBox10(center - thickness / 2, Math.min(q1, q3), thickness, Math.abs(q3 - q1));
|
|
}
|
|
isPointInPath(x, y) {
|
|
return this.getBBox().containsPoint(x, y);
|
|
}
|
|
distanceSquared(x, y) {
|
|
return this.getBBox().distanceSquared(x, y);
|
|
}
|
|
get midPoint() {
|
|
return this.horizontal ? { x: (this.min + this.max) / 2, y: this.center } : { x: this.center, y: (this.min + this.max) / 2 };
|
|
}
|
|
alignedCoordinates() {
|
|
const { thickness, crisp } = this;
|
|
let { center, min, q1, median, q3, max } = this;
|
|
let x0 = center - thickness / 2;
|
|
let x1 = center + thickness / 2;
|
|
if (crisp && thickness > 1) {
|
|
min = this.align(min);
|
|
q1 = this.align(q1);
|
|
median = this.align(median);
|
|
q3 = this.align(q3);
|
|
max = min + this.align(min, max - min);
|
|
const halfWidth = this.align(thickness / 2);
|
|
center = this.align(center);
|
|
x0 = center - halfWidth;
|
|
x1 = center + halfWidth;
|
|
}
|
|
return { center, x0, x1, min, max, q1, median, q3 };
|
|
}
|
|
updatePath() {
|
|
const {
|
|
path,
|
|
stroke: stroke3,
|
|
strokeWidth,
|
|
strokeOpacity,
|
|
lineDash,
|
|
lineDashOffset,
|
|
wickStroke,
|
|
wickStrokeWidth,
|
|
wickStrokeOpacity,
|
|
wickLineDash,
|
|
wickLineDashOffset,
|
|
strokeAlignment,
|
|
cornerRadius,
|
|
capLengthRatio,
|
|
horizontal
|
|
} = this;
|
|
const { center, x0, x1, min, max, q1, median, q3 } = this.alignedCoordinates();
|
|
const pixelRatio = this.layerManager?.canvas.pixelRatio ?? 1;
|
|
const wickStrokeAlignment = this.wickStrokeAlignment > 0 ? pixelRatio / this.wickStrokeAlignment / 2 % 1 : 0;
|
|
this.path.clear();
|
|
this.wickPath.clear();
|
|
const needsWickPath = wickStroke != null && wickStroke !== stroke3 || wickStrokeWidth != null && wickStrokeWidth !== strokeWidth || wickStrokeOpacity != null && wickStrokeOpacity !== strokeOpacity || wickLineDash != null && wickLineDash !== lineDash || wickLineDashOffset != null && wickLineDashOffset !== lineDashOffset;
|
|
const wickPath = needsWickPath ? this.wickPath : path;
|
|
if (Math.abs(x1 - x0) <= 3) {
|
|
moveTo(wickPath, horizontal, center, min);
|
|
lineTo(wickPath, horizontal, center, max);
|
|
return;
|
|
}
|
|
const wickTop = Math.min(min, max);
|
|
const wickBottom = Math.max(min, max);
|
|
const boxTop = Math.min(q1, q3);
|
|
const boxBottom = Math.max(q1, q3);
|
|
const capX0 = center - Math.abs((x1 - x0) * capLengthRatio) / 2;
|
|
const capX1 = center + Math.abs((x1 - x0) * capLengthRatio) / 2;
|
|
moveTo(wickPath, horizontal, capX0, wickTop - wickStrokeAlignment);
|
|
lineTo(wickPath, horizontal, capX1, wickTop - wickStrokeAlignment);
|
|
moveTo(wickPath, horizontal, center - wickStrokeAlignment, wickTop - wickStrokeAlignment);
|
|
lineTo(wickPath, horizontal, center - wickStrokeAlignment, boxTop + strokeWidth / 2);
|
|
moveTo(wickPath, horizontal, center - wickStrokeAlignment, wickBottom + wickStrokeAlignment);
|
|
lineTo(wickPath, horizontal, center - wickStrokeAlignment, boxBottom - strokeWidth / 2);
|
|
moveTo(wickPath, horizontal, capX0, wickBottom + wickStrokeAlignment);
|
|
lineTo(wickPath, horizontal, capX1, wickBottom + wickStrokeAlignment);
|
|
const horizontalBoxStrokeAdjustment = strokeWidth / 2 + strokeAlignment;
|
|
const verticalBoxStrokeAdjustment = strokeWidth / 2 - strokeAlignment;
|
|
const rectHeight = boxBottom - boxTop - 2 * verticalBoxStrokeAdjustment;
|
|
if (rectHeight > 0) {
|
|
const rectX = x0 + horizontalBoxStrokeAdjustment;
|
|
const rectY = boxTop + verticalBoxStrokeAdjustment;
|
|
const rectWidth = x1 - x0 - 2 * horizontalBoxStrokeAdjustment;
|
|
const cornerRadii = {
|
|
topLeft: cornerRadius,
|
|
topRight: cornerRadius,
|
|
bottomRight: cornerRadius,
|
|
bottomLeft: cornerRadius
|
|
};
|
|
clippedRoundRect2(
|
|
path,
|
|
horizontal,
|
|
rectX,
|
|
rectY,
|
|
rectWidth,
|
|
rectHeight,
|
|
cornerRadii,
|
|
new BBox10(rectX, rectY, rectWidth, median - rectY)
|
|
);
|
|
clippedRoundRect2(
|
|
path,
|
|
horizontal,
|
|
rectX,
|
|
rectY,
|
|
rectWidth,
|
|
rectHeight,
|
|
cornerRadii,
|
|
new BBox10(rectX, median, rectWidth, rectY + rectHeight - median)
|
|
);
|
|
} else {
|
|
const boxMid = (boxTop + boxBottom) / 2;
|
|
moveTo(path, horizontal, x0, boxMid);
|
|
lineTo(path, horizontal, x1, boxMid);
|
|
}
|
|
}
|
|
drawPath(ctx) {
|
|
super.drawPath(ctx);
|
|
const { wickPath } = this;
|
|
if (wickPath.isEmpty())
|
|
return;
|
|
const {
|
|
stroke: stroke3,
|
|
strokeWidth,
|
|
strokeOpacity,
|
|
lineDash,
|
|
lineDashOffset,
|
|
wickStroke = stroke3,
|
|
wickStrokeWidth = strokeWidth,
|
|
wickStrokeOpacity = strokeOpacity,
|
|
wickLineDash = lineDash,
|
|
wickLineDashOffset = lineDashOffset
|
|
} = this;
|
|
if (wickStrokeWidth === 0)
|
|
return;
|
|
ctx.globalAlpha *= wickStrokeOpacity;
|
|
if (typeof wickStroke === "string") {
|
|
ctx.strokeStyle = wickStroke;
|
|
}
|
|
ctx.lineWidth = wickStrokeWidth;
|
|
if (wickLineDash != null) {
|
|
ctx.setLineDash([...wickLineDash]);
|
|
}
|
|
ctx.lineDashOffset = wickLineDashOffset;
|
|
ctx.stroke(wickPath.getPath2D());
|
|
}
|
|
};
|
|
__decorateClass([
|
|
SceneChangeDetection4()
|
|
], BoxPlotNode.prototype, "horizontal", 2);
|
|
__decorateClass([
|
|
SceneChangeDetection4()
|
|
], BoxPlotNode.prototype, "center", 2);
|
|
__decorateClass([
|
|
SceneChangeDetection4()
|
|
], BoxPlotNode.prototype, "thickness", 2);
|
|
__decorateClass([
|
|
SceneChangeDetection4()
|
|
], BoxPlotNode.prototype, "min", 2);
|
|
__decorateClass([
|
|
SceneChangeDetection4()
|
|
], BoxPlotNode.prototype, "q1", 2);
|
|
__decorateClass([
|
|
SceneChangeDetection4()
|
|
], BoxPlotNode.prototype, "median", 2);
|
|
__decorateClass([
|
|
SceneChangeDetection4()
|
|
], BoxPlotNode.prototype, "q3", 2);
|
|
__decorateClass([
|
|
SceneChangeDetection4()
|
|
], BoxPlotNode.prototype, "max", 2);
|
|
__decorateClass([
|
|
SceneChangeDetection4()
|
|
], BoxPlotNode.prototype, "cornerRadius", 2);
|
|
__decorateClass([
|
|
SceneChangeDetection4()
|
|
], BoxPlotNode.prototype, "crisp", 2);
|
|
__decorateClass([
|
|
SceneChangeDetection4()
|
|
], BoxPlotNode.prototype, "strokeAlignment", 2);
|
|
__decorateClass([
|
|
SceneChangeDetection4()
|
|
], BoxPlotNode.prototype, "wickStroke", 2);
|
|
__decorateClass([
|
|
SceneChangeDetection4()
|
|
], BoxPlotNode.prototype, "wickStrokeWidth", 2);
|
|
__decorateClass([
|
|
SceneChangeDetection4()
|
|
], BoxPlotNode.prototype, "wickStrokeOpacity", 2);
|
|
__decorateClass([
|
|
SceneArrayChangeDetection()
|
|
], BoxPlotNode.prototype, "wickLineDash", 2);
|
|
__decorateClass([
|
|
SceneChangeDetection4()
|
|
], BoxPlotNode.prototype, "wickLineDashOffset", 2);
|
|
__decorateClass([
|
|
SceneChangeDetection4()
|
|
], BoxPlotNode.prototype, "capLengthRatio", 2);
|
|
__decorateClass([
|
|
SceneChangeDetection4()
|
|
], BoxPlotNode.prototype, "wickStrokeAlignment", 2);
|
|
function moveTo(path, horizontal, x, y) {
|
|
if (horizontal) {
|
|
path.moveTo(y, x);
|
|
} else {
|
|
path.moveTo(x, y);
|
|
}
|
|
}
|
|
function lineTo(path, horizontal, x, y) {
|
|
if (horizontal) {
|
|
path.lineTo(y, x);
|
|
} else {
|
|
path.lineTo(x, y);
|
|
}
|
|
}
|
|
function clippedRoundRect2(path, horizontal, x, y, width, height, cornerRadii, clipBBox) {
|
|
if (horizontal) {
|
|
baseClippedRoundRect(
|
|
// eslint-disable-next-line sonarjs/arguments-order
|
|
path,
|
|
y,
|
|
x,
|
|
height,
|
|
width,
|
|
cornerRadii,
|
|
clipBBox == null ? void 0 : new BBox10(clipBBox.y, clipBBox.x, clipBBox.height, clipBBox.width)
|
|
);
|
|
} else {
|
|
baseClippedRoundRect(path, x, y, width, height, cornerRadii, clipBBox);
|
|
}
|
|
}
|
|
|
|
// packages/ag-charts-enterprise/src/series/box-plot/boxPlotSeriesProperties.ts
|
|
import { _ModuleSupport as _ModuleSupport83 } from "ag-charts-community";
|
|
import { BaseProperties as BaseProperties19, Property as Property50, mergeDefaults as mergeDefaults3 } from "ag-charts-core";
|
|
var { AbstractBarSeriesProperties, makeSeriesTooltip } = _ModuleSupport83;
|
|
var BoxPlotSeriesCap = class extends BaseProperties19 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.lengthRatio = 0.5;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property50
|
|
], BoxPlotSeriesCap.prototype, "lengthRatio", 2);
|
|
var BoxPlotSeriesWhisker = class extends BaseProperties19 {
|
|
};
|
|
__decorateClass([
|
|
Property50
|
|
], BoxPlotSeriesWhisker.prototype, "stroke", 2);
|
|
__decorateClass([
|
|
Property50
|
|
], BoxPlotSeriesWhisker.prototype, "strokeWidth", 2);
|
|
__decorateClass([
|
|
Property50
|
|
], BoxPlotSeriesWhisker.prototype, "strokeOpacity", 2);
|
|
__decorateClass([
|
|
Property50
|
|
], BoxPlotSeriesWhisker.prototype, "lineDash", 2);
|
|
__decorateClass([
|
|
Property50
|
|
], BoxPlotSeriesWhisker.prototype, "lineDashOffset", 2);
|
|
var BoxPlotSeriesProperties = class extends AbstractBarSeriesProperties {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.fill = "#c16068";
|
|
this.fillOpacity = 1;
|
|
this.stroke = "#333";
|
|
this.strokeWidth = 1;
|
|
this.strokeOpacity = 1;
|
|
this.lineDash = [0];
|
|
this.lineDashOffset = 0;
|
|
this.cornerRadius = 0;
|
|
this.cap = new BoxPlotSeriesCap();
|
|
this.whisker = new BoxPlotSeriesWhisker();
|
|
this.tooltip = makeSeriesTooltip();
|
|
}
|
|
toJson() {
|
|
const { stroke: stroke3, strokeWidth, strokeOpacity, lineDash, lineDashOffset } = this;
|
|
const properties = super.toJson();
|
|
properties.whisker = mergeDefaults3(properties.whisker, {
|
|
stroke: stroke3,
|
|
strokeWidth,
|
|
strokeOpacity,
|
|
lineDash,
|
|
lineDashOffset
|
|
});
|
|
return properties;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property50
|
|
], BoxPlotSeriesProperties.prototype, "xKey", 2);
|
|
__decorateClass([
|
|
Property50
|
|
], BoxPlotSeriesProperties.prototype, "minKey", 2);
|
|
__decorateClass([
|
|
Property50
|
|
], BoxPlotSeriesProperties.prototype, "q1Key", 2);
|
|
__decorateClass([
|
|
Property50
|
|
], BoxPlotSeriesProperties.prototype, "medianKey", 2);
|
|
__decorateClass([
|
|
Property50
|
|
], BoxPlotSeriesProperties.prototype, "q3Key", 2);
|
|
__decorateClass([
|
|
Property50
|
|
], BoxPlotSeriesProperties.prototype, "maxKey", 2);
|
|
__decorateClass([
|
|
Property50
|
|
], BoxPlotSeriesProperties.prototype, "xName", 2);
|
|
__decorateClass([
|
|
Property50
|
|
], BoxPlotSeriesProperties.prototype, "yName", 2);
|
|
__decorateClass([
|
|
Property50
|
|
], BoxPlotSeriesProperties.prototype, "minName", 2);
|
|
__decorateClass([
|
|
Property50
|
|
], BoxPlotSeriesProperties.prototype, "q1Name", 2);
|
|
__decorateClass([
|
|
Property50
|
|
], BoxPlotSeriesProperties.prototype, "medianName", 2);
|
|
__decorateClass([
|
|
Property50
|
|
], BoxPlotSeriesProperties.prototype, "q3Name", 2);
|
|
__decorateClass([
|
|
Property50
|
|
], BoxPlotSeriesProperties.prototype, "maxName", 2);
|
|
__decorateClass([
|
|
Property50
|
|
], BoxPlotSeriesProperties.prototype, "fill", 2);
|
|
__decorateClass([
|
|
Property50
|
|
], BoxPlotSeriesProperties.prototype, "fillOpacity", 2);
|
|
__decorateClass([
|
|
Property50
|
|
], BoxPlotSeriesProperties.prototype, "stroke", 2);
|
|
__decorateClass([
|
|
Property50
|
|
], BoxPlotSeriesProperties.prototype, "strokeWidth", 2);
|
|
__decorateClass([
|
|
Property50
|
|
], BoxPlotSeriesProperties.prototype, "strokeOpacity", 2);
|
|
__decorateClass([
|
|
Property50
|
|
], BoxPlotSeriesProperties.prototype, "lineDash", 2);
|
|
__decorateClass([
|
|
Property50
|
|
], BoxPlotSeriesProperties.prototype, "lineDashOffset", 2);
|
|
__decorateClass([
|
|
Property50
|
|
], BoxPlotSeriesProperties.prototype, "cornerRadius", 2);
|
|
__decorateClass([
|
|
Property50
|
|
], BoxPlotSeriesProperties.prototype, "styler", 2);
|
|
__decorateClass([
|
|
Property50
|
|
], BoxPlotSeriesProperties.prototype, "itemStyler", 2);
|
|
__decorateClass([
|
|
Property50
|
|
], BoxPlotSeriesProperties.prototype, "cap", 2);
|
|
__decorateClass([
|
|
Property50
|
|
], BoxPlotSeriesProperties.prototype, "whisker", 2);
|
|
__decorateClass([
|
|
Property50
|
|
], BoxPlotSeriesProperties.prototype, "tooltip", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/series/box-plot/boxPlotSeries.ts
|
|
var {
|
|
fixNumericExtent: fixNumericExtent2,
|
|
keyProperty: keyProperty2,
|
|
SeriesNodePickMode,
|
|
SMALLEST_KEY_INTERVAL,
|
|
valueProperty: valueProperty3,
|
|
diff,
|
|
animationValidation,
|
|
computeBarFocusBounds,
|
|
createDatumId,
|
|
HighlightState,
|
|
motion,
|
|
getItemStyles,
|
|
calculateSegments,
|
|
toHighlightString,
|
|
processedDataIsAnimatable,
|
|
upsertNodeDatum
|
|
} = _ModuleSupport84;
|
|
var BoxPlotSeriesNodeEvent = class extends _ModuleSupport84.SeriesNodeEvent {
|
|
constructor(type, nativeEvent, datum, series) {
|
|
super(type, nativeEvent, datum, series);
|
|
this.xKey = series.properties.xKey;
|
|
this.minKey = series.properties.minKey;
|
|
this.q1Key = series.properties.q1Key;
|
|
this.medianKey = series.properties.medianKey;
|
|
this.q3Key = series.properties.q3Key;
|
|
this.maxKey = series.properties.maxKey;
|
|
}
|
|
};
|
|
var BoxPlotSeries = class extends _ModuleSupport84.AbstractBarSeries {
|
|
constructor(moduleCtx) {
|
|
super({
|
|
moduleCtx,
|
|
pickModes: [SeriesNodePickMode.NEAREST_NODE, SeriesNodePickMode.EXACT_SHAPE_MATCH],
|
|
propertyKeys: {
|
|
x: ["xKey"],
|
|
y: ["medianKey", "q1Key", "q3Key", "minKey", "maxKey"]
|
|
},
|
|
propertyNames: {
|
|
x: ["xName"],
|
|
y: ["medianName", "q1Name", "q3Name", "minName", "maxName"]
|
|
},
|
|
categoryKey: "xValue",
|
|
pathsPerSeries: []
|
|
});
|
|
this.properties = new BoxPlotSeriesProperties();
|
|
this.NodeEvent = BoxPlotSeriesNodeEvent;
|
|
}
|
|
async processData(dataController) {
|
|
if (!this.visible)
|
|
return;
|
|
const { xKey, minKey, q1Key, medianKey, q3Key, maxKey } = this.properties;
|
|
const animationEnabled = !this.ctx.animationManager.isSkipped();
|
|
const xScale = this.getCategoryAxis()?.scale;
|
|
const yScale = this.getValueAxis()?.scale;
|
|
const { isContinuousX, xScaleType, yScaleType } = this.getScaleInformation({ xScale, yScale });
|
|
const extraProps = [];
|
|
if (this.needsDataModelDiff() && this.processedData) {
|
|
extraProps.push(diff(this.id, this.processedData));
|
|
}
|
|
if (animationEnabled) {
|
|
extraProps.push(animationValidation());
|
|
}
|
|
const allowNullKey = this.properties.allowNullKeys ?? false;
|
|
const { processedData } = await this.requestDataModel(dataController, this.data, {
|
|
props: [
|
|
keyProperty2(xKey, xScaleType, { id: `xValue`, allowNullKey }),
|
|
valueProperty3(minKey, yScaleType, { id: `minValue` }),
|
|
valueProperty3(q1Key, yScaleType, { id: `q1Value` }),
|
|
valueProperty3(medianKey, yScaleType, { id: `medianValue` }),
|
|
valueProperty3(q3Key, yScaleType, { id: `q3Value` }),
|
|
valueProperty3(maxKey, yScaleType, { id: `maxValue` }),
|
|
...isContinuousX ? [SMALLEST_KEY_INTERVAL] : [],
|
|
...extraProps
|
|
]
|
|
});
|
|
this.smallestDataInterval = processedData.reduced?.smallestKeyInterval;
|
|
this.animationState.transition("updateData");
|
|
}
|
|
getSeriesDomain(direction) {
|
|
const { processedData, dataModel } = this;
|
|
if (!(processedData && dataModel))
|
|
return { domain: [] };
|
|
if (direction !== this.getBarDirection()) {
|
|
const { index, def } = dataModel.resolveProcessedDataDefById(this, `xValue`);
|
|
const keys = processedData.domain.keys[index];
|
|
if (def.type === "key" && def.valueType === "category") {
|
|
const sortMetadata = dataModel.getKeySortMetadata(this, "xValue", processedData);
|
|
return { domain: keys, sortMetadata };
|
|
}
|
|
return { domain: this.padBandExtent(keys) };
|
|
}
|
|
const yExtent = this.domainForClippedRange(direction, ["minValue", "maxValue"], "xValue");
|
|
return { domain: fixNumericExtent2(yExtent) };
|
|
}
|
|
getSeriesRange(_direction, visibleRange) {
|
|
return this.domainForVisibleRange(ChartAxisDirection15.Y, ["maxValue", "minValue"], "xValue", visibleRange);
|
|
}
|
|
/**
|
|
* Creates the shared context for datum creation.
|
|
* Caches expensive lookups and computations that are constant across all datums.
|
|
*/
|
|
createNodeDatumContext(xAxis, yAxis) {
|
|
const { dataModel, processedData, contextNodeData } = this;
|
|
if (!dataModel || !processedData)
|
|
return void 0;
|
|
const canIncrementallyUpdate = contextNodeData?.nodeData != null && processedData.changeDescription != null;
|
|
const animationEnabled = !this.ctx.animationManager.isSkipped();
|
|
const { groupOffset, barOffset, barWidth } = this.getBarDimensions();
|
|
return {
|
|
xAxis,
|
|
yAxis,
|
|
rawData: processedData.dataSources.get(this.id)?.data ?? [],
|
|
xValues: dataModel.resolveKeysById(this, "xValue", processedData),
|
|
minValues: dataModel.resolveColumnById(this, "minValue", processedData),
|
|
q1Values: dataModel.resolveColumnById(this, "q1Value", processedData),
|
|
medianValues: dataModel.resolveColumnById(this, "medianValue", processedData),
|
|
q3Values: dataModel.resolveColumnById(this, "q3Value", processedData),
|
|
maxValues: dataModel.resolveColumnById(this, "maxValue", processedData),
|
|
xScale: xAxis.scale,
|
|
yScale: yAxis.scale,
|
|
groupOffset,
|
|
barOffset,
|
|
barWidth,
|
|
isVertical: this.isVertical(),
|
|
xKey: this.properties.xKey,
|
|
animationEnabled,
|
|
canIncrementallyUpdate,
|
|
nodes: canIncrementallyUpdate ? contextNodeData.nodeData : [],
|
|
nodeIndex: 0
|
|
};
|
|
}
|
|
/**
|
|
* Validates box plot values and checks ordering constraints.
|
|
* Returns true if values are valid (all numbers, min <= q1 <= median <= q3 <= max).
|
|
*/
|
|
validateBoxPlotValues(minValue, q1Value, medianValue, q3Value, maxValue) {
|
|
return [minValue, q1Value, medianValue, q3Value, maxValue].every((value) => typeof value === "number") && minValue <= q1Value && q1Value <= medianValue && medianValue <= q3Value && q3Value <= maxValue;
|
|
}
|
|
/**
|
|
* Computes scaled values for a single datum.
|
|
* Populates the scratch object to avoid allocations.
|
|
*/
|
|
computeScaledValues(ctx, scratch, datumIndex) {
|
|
const x = ctx.xScale.convert(ctx.xValues[datumIndex]);
|
|
if (!Number.isFinite(x))
|
|
return false;
|
|
scratch.xValue = x + ctx.groupOffset + ctx.barOffset + ctx.barWidth / 2;
|
|
scratch.minValue = ctx.yScale.convert(ctx.minValues[datumIndex]);
|
|
scratch.q1Value = ctx.yScale.convert(ctx.q1Values[datumIndex]);
|
|
scratch.medianValue = ctx.yScale.convert(ctx.medianValues[datumIndex]);
|
|
scratch.q3Value = ctx.yScale.convert(ctx.q3Values[datumIndex]);
|
|
scratch.maxValue = ctx.yScale.convert(ctx.maxValues[datumIndex]);
|
|
return true;
|
|
}
|
|
/**
|
|
* Creates a skeleton BoxPlotNodeDatum with minimal required fields.
|
|
* The node will be populated by updateNodeDatum.
|
|
*/
|
|
createSkeletonNodeDatum(ctx, params) {
|
|
return {
|
|
series: this,
|
|
datum: params.datum,
|
|
datumIndex: params.datumIndex,
|
|
xKey: ctx.xKey,
|
|
bandwidth: ctx.barWidth,
|
|
scaledValues: {
|
|
xValue: 0,
|
|
minValue: 0,
|
|
q1Value: 0,
|
|
medianValue: 0,
|
|
q3Value: 0,
|
|
maxValue: 0
|
|
},
|
|
midPoint: { x: 0, y: 0 },
|
|
focusRect: { x: 0, y: 0, width: 0, height: 0 }
|
|
};
|
|
}
|
|
/**
|
|
* Updates an existing BoxPlotNodeDatum in-place.
|
|
* This is more efficient than recreating the entire node when only data values change.
|
|
*/
|
|
updateNodeDatum(ctx, node, params) {
|
|
const { isVertical, barWidth } = ctx;
|
|
const scaledValues = params.scaledValues;
|
|
const mutableNode = node;
|
|
mutableNode.datum = params.datum;
|
|
mutableNode.datumIndex = params.datumIndex;
|
|
mutableNode.bandwidth = barWidth;
|
|
const mutableScaledValues = mutableNode.scaledValues;
|
|
mutableScaledValues.xValue = scaledValues.xValue;
|
|
mutableScaledValues.minValue = scaledValues.minValue;
|
|
mutableScaledValues.q1Value = scaledValues.q1Value;
|
|
mutableScaledValues.medianValue = scaledValues.medianValue;
|
|
mutableScaledValues.q3Value = scaledValues.q3Value;
|
|
mutableScaledValues.maxValue = scaledValues.maxValue;
|
|
const height = Math.abs(scaledValues.q3Value - scaledValues.q1Value);
|
|
const midX = scaledValues.xValue;
|
|
const midY = Math.min(scaledValues.q3Value, scaledValues.q1Value) + height / 2;
|
|
const midPointX = isVertical ? midX : midY;
|
|
const midPointY = isVertical ? midY : midX;
|
|
if (mutableNode.midPoint) {
|
|
mutableNode.midPoint.x = midPointX;
|
|
mutableNode.midPoint.y = midPointY;
|
|
} else {
|
|
mutableNode.midPoint = { x: midPointX, y: midPointY };
|
|
}
|
|
const focusRect = mutableNode.focusRect;
|
|
if (isVertical) {
|
|
focusRect.x = midPointX - barWidth / 2;
|
|
focusRect.y = scaledValues.minValue;
|
|
focusRect.width = barWidth;
|
|
focusRect.height = scaledValues.maxValue - scaledValues.minValue;
|
|
} else {
|
|
focusRect.x = scaledValues.minValue;
|
|
focusRect.y = midPointY - barWidth / 2;
|
|
focusRect.width = scaledValues.maxValue - scaledValues.minValue;
|
|
focusRect.height = barWidth;
|
|
}
|
|
}
|
|
/**
|
|
* Creates a BoxPlotNodeDatum for a single data point.
|
|
* Creates a skeleton node and uses updateNodeDatum to populate it.
|
|
*/
|
|
createNodeDatum(ctx, params) {
|
|
const node = this.createSkeletonNodeDatum(ctx, params);
|
|
this.updateNodeDatum(ctx, node, params);
|
|
return node;
|
|
}
|
|
/**
|
|
* Initialize the result object shell before populating node data.
|
|
*/
|
|
initializeResult(ctx) {
|
|
return {
|
|
itemId: this.properties.xKey,
|
|
nodeData: ctx.nodes,
|
|
labelData: [],
|
|
scales: this.calculateScaling(),
|
|
visible: this.visible,
|
|
// Set by assembleResult()
|
|
groupScale: void 0,
|
|
styles: void 0,
|
|
segments: void 0
|
|
};
|
|
}
|
|
/**
|
|
* Populate node data by iterating over raw data.
|
|
*/
|
|
populateNodeData(ctx) {
|
|
const scaledValuesScratch = {
|
|
xValue: 0,
|
|
minValue: 0,
|
|
q1Value: 0,
|
|
medianValue: 0,
|
|
q3Value: 0,
|
|
maxValue: 0
|
|
};
|
|
const paramsScratch = {
|
|
datumIndex: 0,
|
|
datum: void 0,
|
|
scaledValues: scaledValuesScratch
|
|
};
|
|
for (let datumIndex = 0; datumIndex < ctx.rawData.length; datumIndex++) {
|
|
const datum = ctx.rawData[datumIndex];
|
|
const xValue = ctx.xValues[datumIndex];
|
|
if (xValue === void 0 && !this.properties.allowNullKeys)
|
|
continue;
|
|
const minValue = ctx.minValues[datumIndex];
|
|
const q1Value = ctx.q1Values[datumIndex];
|
|
const medianValue = ctx.medianValues[datumIndex];
|
|
const q3Value = ctx.q3Values[datumIndex];
|
|
const maxValue = ctx.maxValues[datumIndex];
|
|
if (!this.validateBoxPlotValues(minValue, q1Value, medianValue, q3Value, maxValue)) {
|
|
continue;
|
|
}
|
|
if (!this.computeScaledValues(ctx, scaledValuesScratch, datumIndex)) {
|
|
continue;
|
|
}
|
|
paramsScratch.datumIndex = datumIndex;
|
|
paramsScratch.datum = datum;
|
|
upsertNodeDatum(
|
|
ctx,
|
|
paramsScratch,
|
|
(c, p) => this.createNodeDatum(c, p),
|
|
(c, n, p) => this.updateNodeDatum(c, n, p)
|
|
);
|
|
}
|
|
}
|
|
/**
|
|
* Finalize node data by trimming excess nodes.
|
|
*/
|
|
finalizeNodeData(ctx) {
|
|
if (ctx.canIncrementallyUpdate && ctx.nodeIndex < ctx.nodes.length) {
|
|
ctx.nodes.length = ctx.nodeIndex;
|
|
}
|
|
}
|
|
/**
|
|
* Assemble the final result with computed fields.
|
|
*/
|
|
assembleResult(ctx, result) {
|
|
const segments = calculateSegments(
|
|
this.properties.segmentation,
|
|
ctx.xAxis,
|
|
ctx.yAxis,
|
|
this.chart.seriesRect,
|
|
this.ctx.scene
|
|
);
|
|
result.groupScale = this.getScaling(this.ctx.seriesStateManager.getGroupScale(this));
|
|
result.styles = getItemStyles(this.getItemStyle.bind(this));
|
|
result.segments = segments;
|
|
return result;
|
|
}
|
|
legendItemSymbol() {
|
|
const { fill, stroke: stroke3, strokeWidth, fillOpacity, strokeOpacity, lineDash, lineDashOffset } = this.getStyle(
|
|
false,
|
|
HighlightState.None
|
|
);
|
|
return {
|
|
marker: {
|
|
fill: deepClone2(fill),
|
|
fillOpacity,
|
|
stroke: stroke3,
|
|
strokeOpacity,
|
|
strokeWidth,
|
|
lineDash,
|
|
lineDashOffset
|
|
}
|
|
};
|
|
}
|
|
getLegendData(legendType) {
|
|
const {
|
|
id: seriesId,
|
|
ctx: { legendManager },
|
|
visible
|
|
} = this;
|
|
const { xKey, yName, showInLegend, legendItemName } = this.properties;
|
|
if (!xKey || legendType !== "category") {
|
|
return [];
|
|
}
|
|
return [
|
|
{
|
|
legendType: "category",
|
|
id: seriesId,
|
|
itemId: seriesId,
|
|
seriesId,
|
|
enabled: visible && legendManager.getItemEnabled({ seriesId, itemId: seriesId }),
|
|
label: {
|
|
text: legendItemName ?? yName ?? seriesId
|
|
},
|
|
symbol: this.legendItemSymbol(),
|
|
legendItemName,
|
|
hideInLegend: !showInLegend
|
|
}
|
|
];
|
|
}
|
|
getTooltipContent(datumIndex) {
|
|
const { id: seriesId, dataModel, processedData, properties } = this;
|
|
const {
|
|
xKey,
|
|
xName,
|
|
yName,
|
|
medianKey,
|
|
medianName,
|
|
q1Key,
|
|
q1Name,
|
|
q3Key,
|
|
q3Name,
|
|
minKey,
|
|
minName,
|
|
maxKey,
|
|
maxName,
|
|
legendItemName,
|
|
tooltip
|
|
} = properties;
|
|
const xAxis = this.getCategoryAxis();
|
|
const yAxis = this.getValueAxis();
|
|
if (!dataModel || !processedData || !xAxis || !yAxis)
|
|
return;
|
|
const datum = processedData.dataSources.get(this.id)?.data[datumIndex];
|
|
const xValue = dataModel.resolveKeysById(this, `xValue`, processedData)[datumIndex];
|
|
const minValue = dataModel.resolveColumnById(this, `minValue`, processedData)[datumIndex];
|
|
const q1Value = dataModel.resolveColumnById(this, `q1Value`, processedData)[datumIndex];
|
|
const medianValue = dataModel.resolveColumnById(this, `medianValue`, processedData)[datumIndex];
|
|
const q3Value = dataModel.resolveColumnById(this, `q3Value`, processedData)[datumIndex];
|
|
const maxValue = dataModel.resolveColumnById(this, `maxValue`, processedData)[datumIndex];
|
|
const allowNullKeys = this.properties.allowNullKeys ?? false;
|
|
if (xValue === void 0 && !allowNullKeys)
|
|
return;
|
|
const format = this.getItemStyle(datumIndex, false);
|
|
const data = [
|
|
{
|
|
label: minName,
|
|
fallbackLabel: minKey,
|
|
value: this.getAxisValueText(yAxis, "tooltip", minValue, datum, minKey, legendItemName),
|
|
missing: _ModuleSupport84.isTooltipValueMissing(minValue)
|
|
},
|
|
{
|
|
label: q1Name,
|
|
fallbackLabel: q1Key,
|
|
value: this.getAxisValueText(yAxis, "tooltip", q1Value, datum, q1Key, legendItemName),
|
|
missing: _ModuleSupport84.isTooltipValueMissing(q1Value)
|
|
},
|
|
{
|
|
label: medianName,
|
|
fallbackLabel: medianKey,
|
|
value: this.getAxisValueText(yAxis, "tooltip", medianValue, datum, medianKey, legendItemName),
|
|
missing: _ModuleSupport84.isTooltipValueMissing(medianValue)
|
|
},
|
|
{
|
|
label: q3Name,
|
|
fallbackLabel: q3Key,
|
|
value: this.getAxisValueText(yAxis, "tooltip", q3Value, datum, q3Key, legendItemName),
|
|
missing: _ModuleSupport84.isTooltipValueMissing(q3Value)
|
|
},
|
|
{
|
|
label: maxName,
|
|
fallbackLabel: maxKey,
|
|
value: this.getAxisValueText(yAxis, "tooltip", maxValue, datum, maxKey, legendItemName),
|
|
missing: _ModuleSupport84.isTooltipValueMissing(maxValue)
|
|
}
|
|
];
|
|
return this.formatTooltipWithContext(
|
|
tooltip,
|
|
{
|
|
heading: this.getAxisValueText(xAxis, "tooltip", xValue, datum, xKey, legendItemName),
|
|
title: legendItemName ?? yName,
|
|
symbol: this.legendItemSymbol(),
|
|
data
|
|
},
|
|
{
|
|
seriesId,
|
|
datum,
|
|
title: yName,
|
|
xKey,
|
|
xName,
|
|
yName,
|
|
medianKey,
|
|
medianName,
|
|
q1Key,
|
|
q1Name,
|
|
q3Key,
|
|
q3Name,
|
|
minKey,
|
|
minName,
|
|
maxKey,
|
|
maxName,
|
|
...format
|
|
}
|
|
);
|
|
}
|
|
animateEmptyUpdateReady({
|
|
datumSelection
|
|
}) {
|
|
const isVertical = this.isVertical();
|
|
const { from, to } = prepareBoxPlotFromTo(isVertical);
|
|
motion.resetMotion([datumSelection], resetBoxPlotSelectionsScalingCenterFn(isVertical));
|
|
motion.staticFromToMotion(this.id, "datums", this.ctx.animationManager, [datumSelection], from, to, {
|
|
phase: "initial"
|
|
});
|
|
}
|
|
isLabelEnabled() {
|
|
return false;
|
|
}
|
|
updateDatumSelection(opts) {
|
|
const data = opts.nodeData ?? [];
|
|
if (!processedDataIsAnimatable(this.processedData)) {
|
|
return opts.datumSelection.update(data);
|
|
}
|
|
return opts.datumSelection.update(data, void 0, (datum) => createDatumId(datum.datumIndex));
|
|
}
|
|
makeStylerParams(highlightStateEnum) {
|
|
const { id: seriesId } = this;
|
|
const {
|
|
cornerRadius,
|
|
cap: { lengthRatio },
|
|
fill,
|
|
fillOpacity,
|
|
lineDash,
|
|
lineDashOffset,
|
|
stroke: stroke3,
|
|
strokeOpacity,
|
|
strokeWidth,
|
|
maxKey,
|
|
maxName,
|
|
medianKey,
|
|
medianName,
|
|
minKey,
|
|
minName,
|
|
q1Key,
|
|
q1Name,
|
|
q3Key,
|
|
q3Name,
|
|
whisker: {
|
|
lineDash: whiskerLineDash,
|
|
lineDashOffset: whiskerLineDashOffset,
|
|
stroke: whiskerStroke,
|
|
strokeOpacity: whiskerStrokeOpacity,
|
|
strokeWidth: whiskerStrokeWidth
|
|
},
|
|
xKey,
|
|
xName,
|
|
yName
|
|
} = this.properties;
|
|
const highlightState = toHighlightString(highlightStateEnum ?? HighlightState.None);
|
|
return {
|
|
cap: { lengthRatio },
|
|
cornerRadius,
|
|
fill,
|
|
fillOpacity,
|
|
highlightState,
|
|
lineDash,
|
|
lineDashOffset,
|
|
maxKey,
|
|
maxName: maxName ?? maxKey,
|
|
medianKey,
|
|
medianName: medianName ?? medianKey,
|
|
minKey,
|
|
minName: minName ?? minKey,
|
|
q1Key,
|
|
q1Name: q1Name ?? q1Key,
|
|
q3Key,
|
|
q3Name: q3Name ?? q3Key,
|
|
seriesId,
|
|
stroke: stroke3,
|
|
strokeOpacity,
|
|
strokeWidth,
|
|
whisker: {
|
|
lineDash: whiskerLineDash ?? lineDash,
|
|
lineDashOffset: whiskerLineDashOffset ?? lineDashOffset,
|
|
stroke: whiskerStroke ?? stroke3,
|
|
strokeOpacity: whiskerStrokeOpacity ?? strokeOpacity,
|
|
strokeWidth: whiskerStrokeWidth ?? strokeWidth
|
|
},
|
|
xKey,
|
|
xName: xName ?? xKey,
|
|
yName
|
|
};
|
|
}
|
|
getStyle(ignoreStylerCallback, highlightState) {
|
|
const {
|
|
cap,
|
|
cornerRadius,
|
|
fill,
|
|
fillOpacity,
|
|
lineDash,
|
|
lineDashOffset,
|
|
stroke: stroke3,
|
|
strokeOpacity,
|
|
strokeWidth,
|
|
styler,
|
|
whisker
|
|
} = this.properties;
|
|
let stylerResult = {};
|
|
if (!ignoreStylerCallback && styler) {
|
|
const stylerParams = this.makeStylerParams(highlightState);
|
|
stylerResult = this.ctx.optionsGraphService.resolvePartial(
|
|
["series", `${this.declarationOrder}`],
|
|
this.cachedCallWithContext(styler, stylerParams) ?? {},
|
|
{ pick: false }
|
|
) ?? {};
|
|
}
|
|
return {
|
|
cornerRadius: stylerResult.cornerRadius ?? cornerRadius,
|
|
fill: stylerResult.fill ?? fill,
|
|
fillOpacity: stylerResult.fillOpacity ?? fillOpacity,
|
|
lineDash: stylerResult.lineDash ?? lineDash,
|
|
lineDashOffset: stylerResult.lineDashOffset ?? lineDashOffset,
|
|
opacity: 1,
|
|
stroke: stylerResult.stroke ?? stroke3,
|
|
strokeOpacity: stylerResult.strokeOpacity ?? strokeOpacity,
|
|
strokeWidth: stylerResult.strokeWidth ?? strokeWidth,
|
|
cap: { lengthRatio: stylerResult.cap?.lengthRatio ?? cap.lengthRatio },
|
|
whisker: {
|
|
lineDash: stylerResult.whisker?.lineDash ?? whisker.lineDash,
|
|
lineDashOffset: stylerResult.whisker?.lineDashOffset ?? whisker.lineDashOffset,
|
|
stroke: stylerResult.whisker?.stroke ?? whisker.stroke,
|
|
strokeOpacity: stylerResult.whisker?.strokeOpacity ?? whisker.strokeOpacity,
|
|
strokeWidth: stylerResult.whisker?.strokeWidth ?? whisker.strokeWidth
|
|
}
|
|
};
|
|
}
|
|
getItemStyle(datumIndex, isHighlight, highlightState) {
|
|
const { properties } = this;
|
|
const { itemStyler } = properties;
|
|
const highlightStyle = this.getHighlightStyle(isHighlight, datumIndex, highlightState);
|
|
let style = mergeDefaults4(highlightStyle, this.getStyle(datumIndex === void 0, highlightState));
|
|
if (itemStyler != null && datumIndex != null) {
|
|
const overrides = this.cachedDatumCallback(
|
|
createDatumId(datumIndex, isHighlight ? "highlight" : "node"),
|
|
() => {
|
|
const params = this.makeItemStylerParams(datumIndex, isHighlight, style);
|
|
return this.ctx.optionsGraphService.resolvePartial(
|
|
["series", `${this.declarationOrder}`],
|
|
this.callWithContext(itemStyler, params)
|
|
);
|
|
}
|
|
);
|
|
if (overrides) {
|
|
style = mergeDefaults4(overrides, style);
|
|
}
|
|
}
|
|
const { stroke: stroke3, strokeWidth, strokeOpacity, lineDash, lineDashOffset } = style;
|
|
style.whisker = mergeDefaults4(style.whisker, {
|
|
stroke: stroke3,
|
|
strokeWidth,
|
|
strokeOpacity,
|
|
lineDash,
|
|
lineDashOffset
|
|
});
|
|
return style;
|
|
}
|
|
makeItemStylerParams(datumIndex, isHighlight, style) {
|
|
const { id: seriesId } = this;
|
|
const { xKey, minKey, q1Key, medianKey, q3Key, maxKey } = this.properties;
|
|
const datum = this.processedData?.dataSources.get(seriesId)?.data[datumIndex];
|
|
const activeHighlight = this.ctx.highlightManager?.getActiveHighlight();
|
|
const highlightStateString = this.getHighlightStateString(activeHighlight, isHighlight, datumIndex);
|
|
const fill = this.filterItemStylerFillParams(style.fill) ?? style.fill;
|
|
return {
|
|
seriesId,
|
|
datum,
|
|
xKey,
|
|
minKey,
|
|
q1Key,
|
|
medianKey,
|
|
q3Key,
|
|
maxKey,
|
|
highlightState: highlightStateString,
|
|
...style,
|
|
fill
|
|
};
|
|
}
|
|
updateDatumStyles({
|
|
datumSelection,
|
|
isHighlight
|
|
}) {
|
|
const highlightedDatum = this.ctx.highlightManager.getActiveHighlight();
|
|
datumSelection.each((_, nodeDatum) => {
|
|
const highlightState = this.getHighlightState(highlightedDatum, isHighlight, nodeDatum.datumIndex);
|
|
nodeDatum.style = this.getItemStyle(nodeDatum.datumIndex, isHighlight, highlightState);
|
|
});
|
|
}
|
|
updateDatumNodes({
|
|
datumSelection,
|
|
isHighlight
|
|
}) {
|
|
const { contextNodeData, properties } = this;
|
|
if (!contextNodeData) {
|
|
return;
|
|
}
|
|
const isVertical = this.isVertical();
|
|
const highlightedDatum = this.ctx.highlightManager.getActiveHighlight();
|
|
const fillBBox = this.getShapeFillBBox();
|
|
const strokeAlignment = this.getStyle(false, HighlightState.None).strokeWidth / 2;
|
|
const wickStrokeAlignment = properties.whisker.strokeWidth ?? properties.strokeWidth;
|
|
datumSelection.each((boxPlotNode, nodeDatum) => {
|
|
const style = nodeDatum.style ?? contextNodeData.styles[this.getHighlightState(highlightedDatum, isHighlight, nodeDatum.datumIndex)];
|
|
boxPlotNode.setFillProperties(style.fill, fillBBox);
|
|
const nodeOpacity = style.opacity ?? 1;
|
|
const whiskerOpacity = style.whisker?.strokeOpacity ?? style.strokeOpacity;
|
|
boxPlotNode.fill = style.fill;
|
|
boxPlotNode.fillOpacity = style.fillOpacity * nodeOpacity;
|
|
boxPlotNode.stroke = style.stroke;
|
|
boxPlotNode.strokeWidth = style.strokeWidth;
|
|
boxPlotNode.strokeOpacity = style.strokeOpacity * nodeOpacity;
|
|
boxPlotNode.lineDash = style.lineDash;
|
|
boxPlotNode.lineDashOffset = style.lineDashOffset;
|
|
boxPlotNode.wickStroke = style.whisker.stroke;
|
|
boxPlotNode.wickStrokeWidth = style.whisker.strokeWidth;
|
|
boxPlotNode.wickStrokeOpacity = whiskerOpacity * nodeOpacity;
|
|
boxPlotNode.wickLineDash = style.whisker.lineDash;
|
|
boxPlotNode.wickLineDashOffset = style.whisker.lineDashOffset;
|
|
boxPlotNode.cornerRadius = style.cornerRadius;
|
|
boxPlotNode.crisp = true;
|
|
boxPlotNode.horizontal = !isVertical;
|
|
boxPlotNode.center = nodeDatum.scaledValues.xValue;
|
|
boxPlotNode.thickness = nodeDatum.bandwidth;
|
|
boxPlotNode.min = nodeDatum.scaledValues.minValue;
|
|
boxPlotNode.q1 = nodeDatum.scaledValues.q1Value;
|
|
boxPlotNode.median = nodeDatum.scaledValues.medianValue;
|
|
boxPlotNode.q3 = nodeDatum.scaledValues.q3Value;
|
|
boxPlotNode.max = nodeDatum.scaledValues.maxValue;
|
|
boxPlotNode.capLengthRatio = style.cap.lengthRatio;
|
|
boxPlotNode.strokeAlignment = strokeAlignment;
|
|
boxPlotNode.wickStrokeAlignment = wickStrokeAlignment;
|
|
});
|
|
}
|
|
updateLabelNodes() {
|
|
}
|
|
updateLabelSelection(opts) {
|
|
const { labelData, labelSelection } = opts;
|
|
return labelSelection.update(labelData);
|
|
}
|
|
nodeFactory() {
|
|
return new BoxPlotNode();
|
|
}
|
|
computeFocusBounds({ datumIndex }) {
|
|
return computeBarFocusBounds(this, this.contextNodeData?.nodeData[datumIndex].focusRect);
|
|
}
|
|
hasItemStylers() {
|
|
return this.properties.itemStyler != null || this.properties.styler != null;
|
|
}
|
|
};
|
|
BoxPlotSeries.className = "BoxPlotSeries";
|
|
BoxPlotSeries.type = "box-plot";
|
|
|
|
// packages/ag-charts-enterprise/src/series/box-plot/boxPlotSeriesOptionsDef.ts
|
|
import { _ModuleSupport as _ModuleSupport85 } from "ag-charts-community";
|
|
import {
|
|
boolean as boolean6,
|
|
commonSeriesOptionsDefs,
|
|
constant,
|
|
positiveNumberNonZero,
|
|
ratio as ratio2,
|
|
required,
|
|
shapeSegmentation,
|
|
string
|
|
} from "ag-charts-core";
|
|
var { boxPlotSeriesThemeableOptionsDef } = _ModuleSupport85;
|
|
var boxPlotSeriesOptionsDef = {
|
|
...commonSeriesOptionsDefs,
|
|
...boxPlotSeriesThemeableOptionsDef,
|
|
type: required(constant("box-plot")),
|
|
xKey: required(string),
|
|
minKey: required(string),
|
|
q1Key: required(string),
|
|
medianKey: required(string),
|
|
q3Key: required(string),
|
|
maxKey: required(string),
|
|
xKeyAxis: string,
|
|
yKeyAxis: string,
|
|
xName: string,
|
|
yName: string,
|
|
minName: string,
|
|
q1Name: string,
|
|
medianName: string,
|
|
q3Name: string,
|
|
maxName: string,
|
|
grouped: boolean6,
|
|
legendItemName: string,
|
|
segmentation: shapeSegmentation,
|
|
width: positiveNumberNonZero,
|
|
widthRatio: ratio2
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/series/box-plot/boxPlotThemes.ts
|
|
import {
|
|
CARTESIAN_AXIS_TYPE,
|
|
FILL_GRADIENT_LINEAR_DEFAULTS,
|
|
FILL_IMAGE_DEFAULTS,
|
|
FILL_PATTERN_DEFAULTS,
|
|
SAFE_FILL_OPERATION,
|
|
SEGMENTATION_DEFAULTS
|
|
} from "ag-charts-core";
|
|
var BOX_PLOT_SERIES_THEME = {
|
|
series: {
|
|
direction: "vertical",
|
|
fill: {
|
|
$applySwitch: [
|
|
{ $path: "type" },
|
|
{
|
|
$if: [
|
|
{
|
|
$or: [
|
|
{ $isGradient: { $palette: "fill" } },
|
|
{ $isPattern: { $palette: "fill" } },
|
|
{ $isImage: { $palette: "fill" } }
|
|
]
|
|
},
|
|
{ $palette: "fill" },
|
|
{ $mix: [SAFE_FILL_OPERATION, { $ref: "chartBackgroundColor" }, 0.7] }
|
|
]
|
|
},
|
|
["gradient", FILL_GRADIENT_LINEAR_DEFAULTS],
|
|
["image", FILL_IMAGE_DEFAULTS],
|
|
["pattern", FILL_PATTERN_DEFAULTS]
|
|
]
|
|
},
|
|
stroke: { $palette: "stroke" },
|
|
strokeWidth: 2,
|
|
fillOpacity: 1,
|
|
strokeOpacity: 1,
|
|
lineDash: void 0,
|
|
lineDashOffset: 0,
|
|
highlight: {
|
|
unhighlightedItem: {
|
|
opacity: 0.5
|
|
},
|
|
unhighlightedSeries: {
|
|
opacity: 0.1
|
|
}
|
|
},
|
|
segmentation: SEGMENTATION_DEFAULTS
|
|
},
|
|
axes: {
|
|
[CARTESIAN_AXIS_TYPE.NUMBER]: {
|
|
crosshair: {
|
|
snap: false
|
|
}
|
|
},
|
|
[CARTESIAN_AXIS_TYPE.CATEGORY]: {
|
|
groupPaddingInner: 0.2,
|
|
crosshair: {
|
|
enabled: false,
|
|
snap: false
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/series/box-plot/boxPlotModule.ts
|
|
var { predictCartesianNonPrimitiveAxis } = _ModuleSupport86;
|
|
var BoxPlotSeriesModule = {
|
|
type: "series",
|
|
name: "box-plot",
|
|
chartType: "cartesian",
|
|
enterprise: true,
|
|
groupable: true,
|
|
version: VERSION15,
|
|
dependencies: [CartesianChartModule],
|
|
options: boxPlotSeriesOptionsDef,
|
|
matchingKeys: ["xKey", "lowKey", "q1Key", "medianKey", "q3Key", "highKey", "outlierKey", "normalizedTo"],
|
|
predictAxis: predictCartesianNonPrimitiveAxis,
|
|
defaultAxes: DIRECTION_SWAP_AXES,
|
|
axisKeys: { [ChartAxisDirection16.X]: "xKeyAxis", [ChartAxisDirection16.Y]: "yKeyAxis" },
|
|
axisKeysFlipped: { [ChartAxisDirection16.X]: "yKeyAxis", [ChartAxisDirection16.Y]: "xKeyAxis" },
|
|
themeTemplate: BOX_PLOT_SERIES_THEME,
|
|
create: (ctx) => new BoxPlotSeries(ctx)
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/series/candlestick/candlestickModule.ts
|
|
import { CartesianChartModule as CartesianChartModule2, VERSION as VERSION16, _ModuleSupport as _ModuleSupport95 } from "ag-charts-community";
|
|
import { CARTESIAN_AXIS_TYPE as CARTESIAN_AXIS_TYPE3, CARTESIAN_POSITION, ChartAxisDirection as ChartAxisDirection18 } from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/series/candlestick/candlestickSeries.ts
|
|
import "ag-charts-community";
|
|
import { isGradientFill, isImageFill, isPatternFill } from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/series/ohlc/ohlcSeriesBase.ts
|
|
import {
|
|
_ModuleSupport as _ModuleSupport89
|
|
} from "ag-charts-community";
|
|
import {
|
|
AGGREGATION_INDEX_X_MAX,
|
|
AGGREGATION_INDEX_X_MIN,
|
|
AGGREGATION_INDEX_Y_MAX,
|
|
AGGREGATION_INDEX_Y_MIN,
|
|
AGGREGATION_SPAN,
|
|
ChartAxisDirection as ChartAxisDirection17,
|
|
DebugMetrics,
|
|
Logger as Logger9,
|
|
mergeDefaults as mergeDefaults5
|
|
} from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/series/ohlc/ohlcAggregation.ts
|
|
import "ag-charts-community";
|
|
import {
|
|
aggregationDomain,
|
|
computeExtremesAggregation,
|
|
computeExtremesAggregationPartial,
|
|
simpleMemorize2
|
|
} from "ag-charts-core";
|
|
function aggregateOhlcData(scale, xValues, highValues, lowValues, domainInput, smallestKeyInterval, xNeedsValueOf, yNeedsValueOf) {
|
|
const [d0, d1] = aggregationDomain(scale, domainInput);
|
|
return computeExtremesAggregation([d0, d1], xValues, highValues, lowValues, {
|
|
smallestKeyInterval,
|
|
xNeedsValueOf,
|
|
yNeedsValueOf
|
|
});
|
|
}
|
|
var memoizedAggregateOhlcData = simpleMemorize2(aggregateOhlcData);
|
|
function aggregateOhlcDataFromDataModel(scale, dataModel, processedData, series, existingFilters) {
|
|
const xValues = dataModel.resolveKeysById(series, "xValue", processedData);
|
|
const highValues = dataModel.resolveColumnById(series, "highValue", processedData);
|
|
const lowValues = dataModel.resolveColumnById(series, "lowValue", processedData);
|
|
const domainInput = dataModel.getDomain(series, "xValue", "key", processedData);
|
|
const xNeedsValueOf = dataModel.resolveColumnNeedsValueOf(series, "xValue", processedData);
|
|
const yNeedsValueOf = dataModel.resolveColumnNeedsValueOf(series, "highValue", processedData) ?? dataModel.resolveColumnNeedsValueOf(series, "lowValue", processedData);
|
|
if (existingFilters) {
|
|
const [d0, d1] = aggregationDomain(scale, domainInput);
|
|
return computeExtremesAggregation([d0, d1], xValues, highValues, lowValues, {
|
|
smallestKeyInterval: processedData.reduced?.smallestKeyInterval,
|
|
xNeedsValueOf,
|
|
yNeedsValueOf,
|
|
existingFilters
|
|
});
|
|
}
|
|
return memoizedAggregateOhlcData(
|
|
scale,
|
|
xValues,
|
|
highValues,
|
|
lowValues,
|
|
domainInput,
|
|
processedData.reduced?.smallestKeyInterval,
|
|
xNeedsValueOf,
|
|
yNeedsValueOf
|
|
);
|
|
}
|
|
function aggregateOhlcDataFromDataModelPartial(scale, dataModel, processedData, series, targetRange, existingFilters) {
|
|
const xValues = dataModel.resolveKeysById(series, "xValue", processedData);
|
|
const highValues = dataModel.resolveColumnById(series, "highValue", processedData);
|
|
const lowValues = dataModel.resolveColumnById(series, "lowValue", processedData);
|
|
const domainInput = dataModel.getDomain(series, "xValue", "key", processedData);
|
|
const xNeedsValueOf = dataModel.resolveColumnNeedsValueOf(series, "xValue", processedData);
|
|
const yNeedsValueOf = dataModel.resolveColumnNeedsValueOf(series, "highValue", processedData) ?? dataModel.resolveColumnNeedsValueOf(series, "lowValue", processedData);
|
|
const [d0, d1] = aggregationDomain(scale, domainInput);
|
|
return computeExtremesAggregationPartial([d0, d1], xValues, highValues, lowValues, {
|
|
smallestKeyInterval: processedData.reduced?.smallestKeyInterval,
|
|
targetRange,
|
|
xNeedsValueOf,
|
|
yNeedsValueOf,
|
|
existingFilters
|
|
});
|
|
}
|
|
|
|
// packages/ag-charts-enterprise/src/series/ohlc/ohlcNode.ts
|
|
import { _ModuleSupport as _ModuleSupport88 } from "ag-charts-community";
|
|
import { DeclaredSceneChangeDetection } from "ag-charts-core";
|
|
var { Path: Path8, BBox: BBox11 } = _ModuleSupport88;
|
|
var OhlcBaseNode = class extends Path8 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.centerX = 0;
|
|
this.y = 0;
|
|
this.width = 0;
|
|
this.height = 0;
|
|
this.yOpen = 0;
|
|
this.yClose = 0;
|
|
this.crisp = false;
|
|
}
|
|
/**
|
|
* High-performance static property setter that bypasses the decorator system entirely.
|
|
* Writes directly to backing fields (__propertyName) to avoid:
|
|
* - Decorator setter chains and equality checks
|
|
* - Multiple onChangeDetection calls per property
|
|
* - Object.keys() iteration in assignIfNotStrictlyEqual
|
|
* - Object allocation overhead
|
|
*
|
|
* A single markDirty() call at the end ensures the scene graph is properly invalidated.
|
|
* WARNING: Only use for hot paths where performance is critical and properties don't need
|
|
* individual change detection (e.g., when updating many nodes in a loop).
|
|
*/
|
|
setStaticProperties(centerX, width, y, height, yOpen, yClose, crisp) {
|
|
this.__centerX = centerX;
|
|
this.__width = width;
|
|
this.__y = y;
|
|
this.__height = height;
|
|
this.__yOpen = yOpen;
|
|
this.__yClose = yClose;
|
|
this.__crisp = crisp;
|
|
this.dirtyPath = true;
|
|
this.markDirty();
|
|
}
|
|
computeBBox() {
|
|
const { __centerX: centerX, __y: y, __width: width, __height: height } = this;
|
|
return new BBox11(centerX - width / 2, y, width, height);
|
|
}
|
|
isPointInPath(x, y) {
|
|
return this.getBBox().containsPoint(x, y);
|
|
}
|
|
distanceSquared(x, y) {
|
|
return this.getBBox().distanceSquared(x, y);
|
|
}
|
|
get midPoint() {
|
|
return { x: this.__centerX, y: this.__y + this.__height / 2 };
|
|
}
|
|
alignedCoordinates() {
|
|
const { __y: y, __width: width, __height: height, __crisp: crisp } = this;
|
|
let { __centerX: centerX, __yOpen: yOpen, __yClose: yClose } = this;
|
|
let x0 = centerX - width / 2;
|
|
let x1 = centerX + width / 2;
|
|
let y0 = y;
|
|
let y1 = y + height;
|
|
if (crisp && width > 1) {
|
|
centerX = this.align(centerX);
|
|
if (yOpen <= yClose) {
|
|
const h = this.align(yOpen, yClose - yOpen);
|
|
yOpen = this.align(yOpen);
|
|
yClose = yOpen + h;
|
|
} else {
|
|
const h = this.align(yClose, yOpen - yClose);
|
|
yClose = this.align(yClose);
|
|
yOpen = yClose + h;
|
|
}
|
|
const halfWidth = this.align(width / 2);
|
|
x0 = centerX - halfWidth;
|
|
x1 = centerX + halfWidth;
|
|
y0 = this.align(y);
|
|
y1 = y0 + this.align(y0, height);
|
|
}
|
|
return { centerX, x0, x1, y0, y1, yOpen, yClose };
|
|
}
|
|
executeStroke(ctx, path) {
|
|
const { __width: width, strokeWidth } = this;
|
|
if (width < strokeWidth) {
|
|
ctx.lineWidth = width;
|
|
}
|
|
super.executeStroke(ctx, path);
|
|
}
|
|
};
|
|
__decorateClass([
|
|
DeclaredSceneChangeDetection()
|
|
], OhlcBaseNode.prototype, "centerX", 2);
|
|
__decorateClass([
|
|
DeclaredSceneChangeDetection()
|
|
], OhlcBaseNode.prototype, "y", 2);
|
|
__decorateClass([
|
|
DeclaredSceneChangeDetection()
|
|
], OhlcBaseNode.prototype, "width", 2);
|
|
__decorateClass([
|
|
DeclaredSceneChangeDetection()
|
|
], OhlcBaseNode.prototype, "height", 2);
|
|
__decorateClass([
|
|
DeclaredSceneChangeDetection()
|
|
], OhlcBaseNode.prototype, "yOpen", 2);
|
|
__decorateClass([
|
|
DeclaredSceneChangeDetection()
|
|
], OhlcBaseNode.prototype, "yClose", 2);
|
|
__decorateClass([
|
|
DeclaredSceneChangeDetection()
|
|
], OhlcBaseNode.prototype, "crisp", 2);
|
|
var OhlcNode = class extends OhlcBaseNode {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.strokeAlignment = 0;
|
|
}
|
|
updatePath() {
|
|
const { path } = this;
|
|
const { centerX, x0, x1, y0, y1, yOpen, yClose } = this.alignedCoordinates();
|
|
const pixelRatio = this.layerManager?.canvas.pixelRatio ?? 1;
|
|
const strokeAlignment = this.__strokeAlignment > 0 ? pixelRatio / this.__strokeAlignment / 2 % 1 : 0;
|
|
path.clear();
|
|
path.moveTo(centerX - strokeAlignment, y0);
|
|
path.lineTo(centerX - strokeAlignment, y1);
|
|
if (Math.abs(x1 - x0) > 1) {
|
|
path.moveTo(x0, yOpen - strokeAlignment);
|
|
path.lineTo(centerX - strokeAlignment, yOpen - strokeAlignment);
|
|
path.moveTo(centerX - strokeAlignment, yClose - strokeAlignment);
|
|
path.lineTo(x1, yClose - strokeAlignment);
|
|
}
|
|
}
|
|
};
|
|
__decorateClass([
|
|
DeclaredSceneChangeDetection()
|
|
], OhlcNode.prototype, "strokeAlignment", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/series/ohlc/ohlcSeriesBase.ts
|
|
var OPEN = AGGREGATION_INDEX_X_MIN;
|
|
var HIGH = AGGREGATION_INDEX_Y_MAX;
|
|
var LOW = AGGREGATION_INDEX_Y_MIN;
|
|
var CLOSE = AGGREGATION_INDEX_X_MAX;
|
|
var SPAN = AGGREGATION_SPAN;
|
|
var {
|
|
AggregationManager,
|
|
fixNumericExtent: fixNumericExtent3,
|
|
keyProperty: keyProperty3,
|
|
createDatumId: createDatumId2,
|
|
SeriesNodePickMode: SeriesNodePickMode2,
|
|
SMALLEST_KEY_INTERVAL: SMALLEST_KEY_INTERVAL2,
|
|
valueProperty: valueProperty4,
|
|
diff: diff2,
|
|
animationValidation: animationValidation2,
|
|
computeBarFocusBounds: computeBarFocusBounds2,
|
|
visibleRangeIndices,
|
|
BandScale,
|
|
processedDataIsAnimatable: processedDataIsAnimatable2,
|
|
getItemStylesPerItemId
|
|
} = _ModuleSupport89;
|
|
var OhlcSeriesNodeEvent = class extends _ModuleSupport89.SeriesNodeEvent {
|
|
constructor(type, nativeEvent, datum, series) {
|
|
super(type, nativeEvent, datum, series);
|
|
this.xKey = series.properties.xKey;
|
|
this.openKey = series.properties.openKey;
|
|
this.closeKey = series.properties.closeKey;
|
|
this.highKey = series.properties.highKey;
|
|
this.lowKey = series.properties.lowKey;
|
|
}
|
|
};
|
|
function resetOhlcSelectionsDirect(selections) {
|
|
for (const selection of selections) {
|
|
const nodes = selection.nodes();
|
|
selection.batchedUpdate(function resetOhlcNodes() {
|
|
for (const node of nodes) {
|
|
const datum = node.datum;
|
|
if (datum == null)
|
|
continue;
|
|
node.setStaticProperties(
|
|
datum.centerX,
|
|
datum.width,
|
|
datum.y,
|
|
datum.height,
|
|
datum.yOpen,
|
|
datum.yClose,
|
|
datum.crisp
|
|
);
|
|
}
|
|
selection.cleanup();
|
|
});
|
|
}
|
|
}
|
|
var OhlcSeriesBase = class extends _ModuleSupport89.AbstractBarSeries {
|
|
constructor(moduleCtx) {
|
|
super({
|
|
moduleCtx,
|
|
pickModes: [SeriesNodePickMode2.AXIS_ALIGNED, SeriesNodePickMode2.EXACT_SHAPE_MATCH],
|
|
propertyKeys: {
|
|
x: ["xKey"],
|
|
y: ["lowKey", "highKey", "openKey", "closeKey"]
|
|
},
|
|
propertyNames: {
|
|
x: ["xName"],
|
|
y: ["lowName", "highName", "openName", "closeName"]
|
|
},
|
|
categoryKey: "xValue",
|
|
pathsPerSeries: []
|
|
});
|
|
this.NodeEvent = OhlcSeriesNodeEvent;
|
|
this.aggregationManager = new AggregationManager();
|
|
}
|
|
async processData(dataController) {
|
|
if (!this.visible)
|
|
return;
|
|
const { xKey, openKey, closeKey, highKey, lowKey } = this.properties;
|
|
const animationEnabled = !this.ctx.animationManager.isSkipped();
|
|
const xScale = this.getCategoryAxis()?.scale;
|
|
const yScale = this.getValueAxis()?.scale;
|
|
const { isContinuousX, xScaleType, yScaleType } = this.getScaleInformation({ xScale, yScale });
|
|
const extraProps = [];
|
|
if (this.needsDataModelDiff() && this.processedData) {
|
|
extraProps.push(diff2(this.id, this.processedData));
|
|
}
|
|
if (animationEnabled) {
|
|
extraProps.push(animationValidation2());
|
|
}
|
|
if (openKey) {
|
|
extraProps.push(
|
|
valueProperty4(openKey, yScaleType, {
|
|
id: `openValue`,
|
|
invalidValue: void 0,
|
|
missingValue: void 0
|
|
})
|
|
);
|
|
}
|
|
const allowNullKey = this.properties.allowNullKeys ?? false;
|
|
const { dataModel, processedData } = await this.requestDataModel(dataController, this.data, {
|
|
props: [
|
|
keyProperty3(xKey, xScaleType, { id: `xValue`, allowNullKey }),
|
|
valueProperty4(closeKey, yScaleType, { id: `closeValue` }),
|
|
valueProperty4(highKey, yScaleType, { id: `highValue` }),
|
|
valueProperty4(lowKey, yScaleType, { id: `lowValue` }),
|
|
...isContinuousX ? [SMALLEST_KEY_INTERVAL2] : [],
|
|
...extraProps
|
|
]
|
|
});
|
|
this.smallestDataInterval = processedData.reduced?.smallestKeyInterval;
|
|
this.aggregateData(dataModel, processedData);
|
|
this.animationState.transition("updateData");
|
|
}
|
|
aggregateData(dataModel, processedData) {
|
|
this.aggregationManager.markStale(processedData.input.count);
|
|
if (processedData.type !== "ungrouped")
|
|
return;
|
|
if (processedDataIsAnimatable2(processedData))
|
|
return;
|
|
const xAxis = this.axes[ChartAxisDirection17.X];
|
|
if (xAxis == null)
|
|
return;
|
|
const targetRange = this.estimateTargetRange();
|
|
this.aggregationManager.aggregate({
|
|
computePartial: (existingFilters) => aggregateOhlcDataFromDataModelPartial(
|
|
xAxis.scale.type,
|
|
dataModel,
|
|
processedData,
|
|
this,
|
|
targetRange,
|
|
existingFilters
|
|
),
|
|
computeFull: (existingFilters) => aggregateOhlcDataFromDataModel(xAxis.scale.type, dataModel, processedData, this, existingFilters),
|
|
targetRange
|
|
});
|
|
const filters = this.aggregationManager.filters;
|
|
if (filters && filters.length > 0) {
|
|
DebugMetrics.record(
|
|
`${this.type}:aggregation`,
|
|
filters.map((f) => f.maxRange)
|
|
);
|
|
}
|
|
}
|
|
estimateTargetRange() {
|
|
const xAxis = this.axes[ChartAxisDirection17.X];
|
|
if (!xAxis)
|
|
return -1;
|
|
const [r0, r1] = xAxis.scale.range;
|
|
return Math.abs(r1 - r0);
|
|
}
|
|
getSeriesDomain(direction) {
|
|
const { processedData, dataModel } = this;
|
|
if (!(processedData && dataModel))
|
|
return { domain: [] };
|
|
if (direction !== this.getBarDirection()) {
|
|
const { def } = dataModel.resolveProcessedDataDefById(this, `xValue`);
|
|
const keys = dataModel.getDomain(this, `xValue`, "key", processedData);
|
|
if (def.type === "key" && def.valueType === "category") {
|
|
return keys;
|
|
}
|
|
return { domain: this.padBandExtent(keys.domain) };
|
|
}
|
|
const yExtent = this.domainForClippedRange(direction, ["highValue", "lowValue"], "xValue");
|
|
return { domain: fixNumericExtent3(yExtent) };
|
|
}
|
|
getSeriesRange(_direction, visibleRange) {
|
|
return this.domainForVisibleRange(ChartAxisDirection17.Y, ["highValue", "lowValue"], "xValue", visibleRange);
|
|
}
|
|
getZoomRangeFittingItems(xVisibleRange, yVisibleRange, minVisibleItems) {
|
|
return this.zoomFittingVisibleItems(
|
|
"xValue",
|
|
["highValue", "lowValue"],
|
|
xVisibleRange,
|
|
yVisibleRange,
|
|
minVisibleItems
|
|
);
|
|
}
|
|
getVisibleItems(xVisibleRange, yVisibleRange, minVisibleItems) {
|
|
return this.countVisibleItems(
|
|
"xValue",
|
|
["highValue", "lowValue"],
|
|
xVisibleRange,
|
|
yVisibleRange,
|
|
minVisibleItems
|
|
);
|
|
}
|
|
/**
|
|
* Creates shared context for node datum creation/update operations.
|
|
* This context is instantiated once and reused across all datum operations
|
|
* to minimize memory allocations. Only caches values that are expensive to
|
|
* compute - cheap property lookups use `this` directly.
|
|
*/
|
|
buildDatumContext(xAxis, yAxis) {
|
|
const { dataModel, processedData } = this;
|
|
if (!dataModel || !processedData)
|
|
return void 0;
|
|
const rawData = processedData.dataSources.get(this.id)?.data ?? [];
|
|
if (rawData.length === 0)
|
|
return void 0;
|
|
const xScale = xAxis.scale;
|
|
const yScale = yAxis.scale;
|
|
const applyWidthOffset = BandScale.is(xScale);
|
|
const [r0, r1] = xScale.range;
|
|
const range2 = Math.abs(r1 - r0);
|
|
this.aggregationManager.ensureLevelForRange(range2);
|
|
const dataAggregationFilter = this.aggregationManager.getFilterForRange(range2);
|
|
const crisp = dataAggregationFilter == null;
|
|
const canIncrementallyUpdate = this.contextNodeData?.nodeData != null && (processedData.changeDescription != null || !processedDataIsAnimatable2(processedData) || dataAggregationFilter != null);
|
|
const { groupOffset, barWidth } = this.getBarDimensions();
|
|
return {
|
|
rawData,
|
|
xValues: dataModel.resolveKeysById(this, "xValue", processedData),
|
|
openValues: dataModel.resolveColumnById(this, "openValue", processedData),
|
|
closeValues: dataModel.resolveColumnById(this, "closeValue", processedData),
|
|
highValues: dataModel.resolveColumnById(this, "highValue", processedData),
|
|
lowValues: dataModel.resolveColumnById(this, "lowValue", processedData),
|
|
xScale,
|
|
yScale,
|
|
xAxis,
|
|
yAxis,
|
|
groupOffset,
|
|
barWidth,
|
|
applyWidthOffset,
|
|
// TODO: replace with barOffset?
|
|
crisp,
|
|
xKey: this.properties.xKey,
|
|
openKey: this.properties.openKey,
|
|
closeKey: this.properties.closeKey,
|
|
highKey: this.properties.highKey,
|
|
lowKey: this.properties.lowKey,
|
|
dataAggregationFilter,
|
|
range: range2,
|
|
nodeDatumStateScratch: {
|
|
datum: void 0,
|
|
xValue: void 0,
|
|
openValue: 0,
|
|
closeValue: 0,
|
|
highValue: 0,
|
|
lowValue: 0,
|
|
isRising: true,
|
|
itemType: "up"
|
|
},
|
|
canIncrementallyUpdate,
|
|
nodeIndex: 0,
|
|
nodeData: canIncrementallyUpdate ? this.contextNodeData.nodeData : []
|
|
};
|
|
}
|
|
/**
|
|
* Validates and prepares state for a single OHLC datum.
|
|
* Mutates ctx.nodeDatumStateScratch with computed values.
|
|
* Returns the scratch object if valid, undefined if invalid.
|
|
*/
|
|
prepareOhlcNodeDatumState(ctx, datumIndex) {
|
|
const xValue = ctx.xValues[datumIndex];
|
|
if (xValue === void 0 && !this.properties.allowNullKeys) {
|
|
return void 0;
|
|
}
|
|
const openValue = ctx.openValues[datumIndex];
|
|
const closeValue = ctx.closeValues[datumIndex];
|
|
const highValue = ctx.highValues[datumIndex];
|
|
const lowValue = ctx.lowValues[datumIndex];
|
|
const validLowValue = lowValue != null && lowValue <= openValue && lowValue <= closeValue;
|
|
const validHighValue = highValue != null && highValue >= openValue && highValue >= closeValue;
|
|
if (!validLowValue) {
|
|
Logger9.warnOnce(
|
|
`invalid low value for key [${ctx.lowKey}] in data element, low value cannot be higher than datum open or close values`
|
|
);
|
|
return void 0;
|
|
}
|
|
if (!validHighValue) {
|
|
Logger9.warnOnce(
|
|
`invalid high value for key [${ctx.highKey}] in data element, high value cannot be lower than datum open or close values.`
|
|
);
|
|
return void 0;
|
|
}
|
|
const datum = ctx.rawData[datumIndex];
|
|
const isRising = closeValue > openValue;
|
|
const itemType = isRising ? "up" : "down";
|
|
const scratch = ctx.nodeDatumStateScratch;
|
|
scratch.datum = datum;
|
|
scratch.xValue = xValue;
|
|
scratch.openValue = openValue;
|
|
scratch.closeValue = closeValue;
|
|
scratch.highValue = highValue;
|
|
scratch.lowValue = lowValue;
|
|
scratch.isRising = isRising;
|
|
scratch.itemType = itemType;
|
|
return scratch;
|
|
}
|
|
/**
|
|
* Creates a skeleton OhlcNodeDatum from prepared state.
|
|
* Takes pre-computed positioning and state from scratch object.
|
|
*/
|
|
createSkeletonNodeDatum(ctx, scratch, datumIndex, centerX, width, crisp) {
|
|
const xOffset = ctx.applyWidthOffset ? width / 2 : 0;
|
|
const adjustedCenterX = centerX + xOffset;
|
|
const yOpen = ctx.yScale.convert(scratch.openValue);
|
|
const yClose = ctx.yScale.convert(scratch.closeValue);
|
|
const yHigh = ctx.yScale.convert(scratch.highValue);
|
|
const yLow = ctx.yScale.convert(scratch.lowValue);
|
|
const y = Math.min(yHigh, yLow);
|
|
const height = Math.max(yHigh, yLow) - y;
|
|
return {
|
|
series: this,
|
|
itemType: scratch.itemType,
|
|
datum: scratch.datum,
|
|
datumIndex,
|
|
xKey: ctx.xKey,
|
|
xValue: scratch.xValue,
|
|
openValue: scratch.openValue,
|
|
closeValue: scratch.closeValue,
|
|
highValue: scratch.highValue,
|
|
lowValue: scratch.lowValue,
|
|
midPoint: {
|
|
x: adjustedCenterX,
|
|
y: y + height / 2
|
|
},
|
|
aggregatedValue: scratch.closeValue,
|
|
isRising: scratch.isRising,
|
|
centerX: adjustedCenterX,
|
|
width,
|
|
y,
|
|
height,
|
|
yOpen,
|
|
yClose,
|
|
crisp
|
|
};
|
|
}
|
|
/**
|
|
* Updates an existing OhlcNodeDatum in-place for value-only changes.
|
|
* This is more efficient than recreating the entire node when only data values change
|
|
* but the structure (insertions/removals) remains the same.
|
|
*/
|
|
updateNodeDatum(ctx, node, prepared, datumIndex, centerX, width, crisp) {
|
|
const mutableNode = node;
|
|
const xOffset = ctx.applyWidthOffset ? width / 2 : 0;
|
|
const adjustedCenterX = centerX + xOffset;
|
|
const yOpen = ctx.yScale.convert(prepared.openValue);
|
|
const yClose = ctx.yScale.convert(prepared.closeValue);
|
|
const yHigh = ctx.yScale.convert(prepared.highValue);
|
|
const yLow = ctx.yScale.convert(prepared.lowValue);
|
|
const y = Math.min(yHigh, yLow);
|
|
const height = Math.max(yHigh, yLow) - y;
|
|
mutableNode.datum = prepared.datum;
|
|
mutableNode.datumIndex = datumIndex;
|
|
mutableNode.itemType = prepared.itemType;
|
|
mutableNode.xValue = prepared.xValue;
|
|
mutableNode.openValue = prepared.openValue;
|
|
mutableNode.closeValue = prepared.closeValue;
|
|
mutableNode.highValue = prepared.highValue;
|
|
mutableNode.lowValue = prepared.lowValue;
|
|
mutableNode.aggregatedValue = prepared.closeValue;
|
|
mutableNode.isRising = prepared.isRising;
|
|
mutableNode.centerX = adjustedCenterX;
|
|
mutableNode.width = width;
|
|
mutableNode.y = y;
|
|
mutableNode.height = height;
|
|
mutableNode.yOpen = yOpen;
|
|
mutableNode.yClose = yClose;
|
|
mutableNode.crisp = crisp;
|
|
const mutableMidPoint = mutableNode.midPoint;
|
|
mutableMidPoint.x = adjustedCenterX;
|
|
mutableMidPoint.y = y + height / 2;
|
|
}
|
|
/**
|
|
* Handles node creation/update - reuses existing nodes when possible for incremental updates.
|
|
* This method decides whether to update existing nodes in-place or create new ones.
|
|
*/
|
|
upsertNodeDatum(ctx, datumIndex, centerX, width, crisp) {
|
|
const prepared = this.prepareOhlcNodeDatumState(ctx, datumIndex);
|
|
if (!prepared)
|
|
return;
|
|
const canReuse = ctx.canIncrementallyUpdate && ctx.nodeIndex < ctx.nodeData.length;
|
|
if (canReuse) {
|
|
this.updateNodeDatum(ctx, ctx.nodeData[ctx.nodeIndex], prepared, datumIndex, centerX, width, crisp);
|
|
} else {
|
|
const newNode = this.createSkeletonNodeDatum(ctx, prepared, datumIndex, centerX, width, crisp);
|
|
ctx.nodeData.push(newNode);
|
|
}
|
|
ctx.nodeIndex++;
|
|
}
|
|
createNodeData() {
|
|
const { visible } = this;
|
|
const xAxis = this.getCategoryAxis();
|
|
const yAxis = this.getValueAxis();
|
|
if (!xAxis || !yAxis)
|
|
return;
|
|
const ctx = this.buildDatumContext(xAxis, yAxis);
|
|
const resultContext = {
|
|
itemId: this.properties.xKey,
|
|
nodeData: ctx?.nodeData ?? [],
|
|
labelData: [],
|
|
scales: this.calculateScaling(),
|
|
groupScale: this.getScaling(this.ctx.seriesStateManager.getGroupScale(this)),
|
|
visible: this.visible,
|
|
styles: getItemStylesPerItemId(this.getItemStyle.bind(this), "up", "down")
|
|
};
|
|
if (!visible || !ctx)
|
|
return resultContext;
|
|
const xPosition = (index) => {
|
|
const x = ctx.xScale.convert(ctx.xValues[index]);
|
|
if (!Number.isFinite(x))
|
|
return Number.NaN;
|
|
return x + ctx.groupOffset;
|
|
};
|
|
if (ctx.dataAggregationFilter == null) {
|
|
const invalidData = this.processedData.invalidData?.get(this.id);
|
|
let [start, end] = visibleRangeIndices(1, ctx.rawData.length, ctx.xAxis.range, (index) => {
|
|
const xOffset = ctx.applyWidthOffset ? 0 : -ctx.barWidth / 2;
|
|
const x = xPosition(index) + xOffset;
|
|
return [x, x + ctx.barWidth];
|
|
});
|
|
if (this.processedData.input.count < 1e3) {
|
|
start = 0;
|
|
end = this.processedData.input.count;
|
|
}
|
|
for (let datumIndex = start; datumIndex < end; datumIndex += 1) {
|
|
if (invalidData?.[datumIndex] === true)
|
|
continue;
|
|
const centerX = xPosition(datumIndex);
|
|
this.upsertNodeDatum(ctx, datumIndex, centerX, ctx.barWidth, ctx.crisp);
|
|
}
|
|
if (ctx.canIncrementallyUpdate && ctx.nodeIndex < ctx.nodeData.length) {
|
|
ctx.nodeData.length = ctx.nodeIndex;
|
|
}
|
|
} else {
|
|
const { maxRange, indexData, midpointIndices } = ctx.dataAggregationFilter;
|
|
const [start, end] = visibleRangeIndices(1, maxRange, ctx.xAxis.range, (index) => {
|
|
const aggIndex = index * SPAN;
|
|
const closeIndex = indexData[aggIndex + CLOSE];
|
|
const midDatumIndex = midpointIndices[index];
|
|
if (midDatumIndex === -1)
|
|
return;
|
|
const xOffset = ctx.applyWidthOffset ? 0 : -ctx.barWidth / 2;
|
|
return [xPosition(midDatumIndex) + xOffset, xPosition(closeIndex) + xOffset + ctx.barWidth];
|
|
});
|
|
for (let i = start; i < end; i += 1) {
|
|
const aggIndex = i * SPAN;
|
|
const openIndex = indexData[aggIndex + OPEN];
|
|
const closeIndex = indexData[aggIndex + CLOSE];
|
|
const highIndex = indexData[aggIndex + HIGH];
|
|
const lowIndex = indexData[aggIndex + LOW];
|
|
const midDatumIndex = midpointIndices[i];
|
|
if (midDatumIndex === -1)
|
|
continue;
|
|
const prepared = this.prepareOhlcNodeDatumState(ctx, midDatumIndex);
|
|
if (!prepared)
|
|
continue;
|
|
prepared.openValue = ctx.openValues[openIndex];
|
|
prepared.closeValue = ctx.closeValues[closeIndex];
|
|
prepared.highValue = ctx.highValues[highIndex];
|
|
prepared.lowValue = ctx.lowValues[lowIndex];
|
|
prepared.isRising = prepared.closeValue > prepared.openValue;
|
|
prepared.itemType = prepared.isRising ? "up" : "down";
|
|
const centerX = xPosition(midDatumIndex);
|
|
const width = Math.abs(xPosition(closeIndex) - xPosition(openIndex)) + ctx.barWidth;
|
|
const canReuse = ctx.canIncrementallyUpdate && ctx.nodeIndex < ctx.nodeData.length;
|
|
if (canReuse) {
|
|
this.updateNodeDatum(
|
|
ctx,
|
|
ctx.nodeData[ctx.nodeIndex],
|
|
prepared,
|
|
midDatumIndex,
|
|
centerX,
|
|
width,
|
|
false
|
|
);
|
|
} else {
|
|
const nodeDatum = this.createSkeletonNodeDatum(ctx, prepared, midDatumIndex, centerX, width, false);
|
|
ctx.nodeData.push(nodeDatum);
|
|
}
|
|
ctx.nodeIndex++;
|
|
}
|
|
if (ctx.canIncrementallyUpdate && ctx.nodeIndex < ctx.nodeData.length) {
|
|
ctx.nodeData.length = ctx.nodeIndex;
|
|
}
|
|
}
|
|
return resultContext;
|
|
}
|
|
isVertical() {
|
|
return true;
|
|
}
|
|
isLabelEnabled() {
|
|
return false;
|
|
}
|
|
resetDatumAnimation(data) {
|
|
resetOhlcSelectionsDirect([data.datumSelection]);
|
|
}
|
|
updateDatumSelection(opts) {
|
|
const data = opts.nodeData ?? [];
|
|
if (!processedDataIsAnimatable2(this.processedData)) {
|
|
return opts.datumSelection.update(data);
|
|
}
|
|
return opts.datumSelection.update(data, void 0, (datum) => createDatumId2(datum.xValue));
|
|
}
|
|
updateLabelNodes(_opts) {
|
|
}
|
|
updateLabelSelection(opts) {
|
|
const { labelData, labelSelection } = opts;
|
|
return labelSelection.update(labelData);
|
|
}
|
|
getItemStyle(datumIndex, isHighlight, highlightState, itemType = "up") {
|
|
const { properties, dataModel, processedData } = this;
|
|
const { itemStyler } = properties;
|
|
const highlightStyle = this.getHighlightStyle(isHighlight, datumIndex, highlightState);
|
|
const baseStyle = mergeDefaults5(highlightStyle, properties.getStyle(itemType));
|
|
let style = baseStyle;
|
|
if (itemStyler && dataModel != null && processedData != null && datumIndex != null) {
|
|
const xValue = dataModel.resolveKeysById(this, `xValue`, processedData)[datumIndex];
|
|
const overrides = this.cachedDatumCallback(
|
|
createDatumId2(createDatumId2(xValue), isHighlight ? "highlight" : "node"),
|
|
() => {
|
|
const params = this.makeItemStylerParams(itemType, datumIndex, isHighlight, style);
|
|
return this.ctx.optionsGraphService.resolvePartial(
|
|
["series", `${this.declarationOrder}`, "item", itemType],
|
|
this.callWithContext(itemStyler, params)
|
|
);
|
|
}
|
|
);
|
|
if (overrides) {
|
|
style = mergeDefaults5(overrides, style);
|
|
}
|
|
}
|
|
return style;
|
|
}
|
|
makeItemStylerParams(itemType, datumIndex, isHighlight, style) {
|
|
const { id: seriesId, properties, processedData } = this;
|
|
const { xKey, openKey, closeKey, highKey, lowKey } = properties;
|
|
const datum = processedData.dataSources.get(seriesId)?.data[datumIndex];
|
|
const activeHighlight = this.ctx.highlightManager?.getActiveHighlight();
|
|
const highlightStateString = this.getHighlightStateString(activeHighlight, isHighlight, datumIndex);
|
|
const params = {
|
|
seriesId,
|
|
datum,
|
|
itemType,
|
|
xKey,
|
|
openKey,
|
|
closeKey,
|
|
highKey,
|
|
lowKey,
|
|
highlightState: highlightStateString,
|
|
...style
|
|
};
|
|
if ("fill" in params && "fill" in style) {
|
|
params.fill = this.filterItemStylerFillParams(style.fill) ?? style.fill;
|
|
}
|
|
return params;
|
|
}
|
|
getTooltipContent(datumIndex) {
|
|
const { id: seriesId, dataModel, processedData, properties } = this;
|
|
const {
|
|
xKey,
|
|
xName,
|
|
yName,
|
|
openKey,
|
|
openName,
|
|
highKey,
|
|
highName,
|
|
lowKey,
|
|
lowName,
|
|
closeKey,
|
|
closeName,
|
|
legendItemName,
|
|
tooltip
|
|
} = properties;
|
|
const xAxis = this.getCategoryAxis();
|
|
const yAxis = this.getValueAxis();
|
|
if (!dataModel || !processedData || !xAxis || !yAxis)
|
|
return;
|
|
const datum = processedData.dataSources.get(this.id)?.data[datumIndex];
|
|
const xValue = dataModel.resolveKeysById(this, `xValue`, processedData)[datumIndex];
|
|
const openValue = dataModel.resolveColumnById(this, `openValue`, processedData)[datumIndex];
|
|
const highValue = dataModel.resolveColumnById(this, `highValue`, processedData)[datumIndex];
|
|
const lowValue = dataModel.resolveColumnById(this, `lowValue`, processedData)[datumIndex];
|
|
const closeValue = dataModel.resolveColumnById(this, `closeValue`, processedData)[datumIndex];
|
|
const allowNullKeys = this.properties.allowNullKeys ?? false;
|
|
if (xValue === void 0 && !allowNullKeys)
|
|
return;
|
|
const itemType = closeValue >= openValue ? "up" : "down";
|
|
const item = this.properties.item[itemType];
|
|
const format = this.getItemStyle(datumIndex, false);
|
|
const marker = {
|
|
fill: item.fill ?? item.stroke,
|
|
fillOpacity: item.fillOpacity ?? item.strokeOpacity ?? 1,
|
|
stroke: item.stroke,
|
|
strokeWidth: item.strokeWidth ?? 1,
|
|
strokeOpacity: item.strokeOpacity ?? 1,
|
|
lineDash: item.lineDash ?? [0],
|
|
lineDashOffset: item.lineDashOffset ?? 0
|
|
};
|
|
return this.formatTooltipWithContext(
|
|
tooltip,
|
|
{
|
|
heading: this.getAxisValueText(xAxis, "tooltip", xValue, datum, xKey, legendItemName),
|
|
title: legendItemName,
|
|
symbol: {
|
|
marker
|
|
},
|
|
data: [
|
|
{
|
|
label: openName,
|
|
fallbackLabel: openKey,
|
|
value: this.getAxisValueText(yAxis, "tooltip", openValue, datum, openKey, legendItemName),
|
|
missing: _ModuleSupport89.isTooltipValueMissing(openValue)
|
|
},
|
|
{
|
|
label: highName,
|
|
fallbackLabel: highKey,
|
|
value: this.getAxisValueText(yAxis, "tooltip", highValue, datum, highKey, legendItemName),
|
|
missing: _ModuleSupport89.isTooltipValueMissing(highValue)
|
|
},
|
|
{
|
|
label: lowName,
|
|
fallbackLabel: lowKey,
|
|
value: this.getAxisValueText(yAxis, "tooltip", lowValue, datum, lowKey, legendItemName),
|
|
missing: _ModuleSupport89.isTooltipValueMissing(lowValue)
|
|
},
|
|
{
|
|
label: closeName,
|
|
fallbackLabel: closeKey,
|
|
value: this.getAxisValueText(yAxis, "tooltip", closeValue, datum, closeKey, legendItemName),
|
|
missing: _ModuleSupport89.isTooltipValueMissing(closeValue)
|
|
}
|
|
]
|
|
},
|
|
{
|
|
seriesId,
|
|
datum,
|
|
title: yName,
|
|
itemType,
|
|
xKey,
|
|
xName,
|
|
yName,
|
|
openKey,
|
|
openName,
|
|
highKey,
|
|
highName,
|
|
lowKey,
|
|
lowName,
|
|
closeKey,
|
|
closeName,
|
|
...format
|
|
}
|
|
);
|
|
}
|
|
computeFocusBounds(opts) {
|
|
const nodeDatum = this.getNodeData()?.at(opts.datumIndex);
|
|
if (nodeDatum == null)
|
|
return;
|
|
const { centerX, y, width, height } = nodeDatum;
|
|
const datum = {
|
|
x: centerX - width / 2,
|
|
y,
|
|
width,
|
|
height
|
|
};
|
|
return computeBarFocusBounds2(this, datum);
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/series/candlestick/candlestickNode.ts
|
|
import { _ModuleSupport as _ModuleSupport90 } from "ag-charts-community";
|
|
import { DeclaredSceneChangeDetection as DeclaredSceneChangeDetection2, SceneArrayChangeDetection as SceneArrayChangeDetection2 } from "ag-charts-core";
|
|
var { ExtendedPath2D: ExtendedPath2D4, BBox: BBox12 } = _ModuleSupport90;
|
|
var CandlestickNode = class extends OhlcBaseNode {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.wickPath = new ExtendedPath2D4();
|
|
this.wickStroke = void 0;
|
|
this.wickStrokeWidth = void 0;
|
|
this.wickStrokeOpacity = void 0;
|
|
this.wickStrokeAlignment = 0;
|
|
}
|
|
/**
|
|
* High-performance wick property setter that bypasses the decorator system entirely.
|
|
* Writes directly to backing fields (__propertyName) to avoid:
|
|
* - Decorator setter chains and equality checks
|
|
* - Multiple onChangeDetection calls per property
|
|
* - Object.keys() iteration in assignIfNotStrictlyEqual
|
|
* - Object allocation overhead
|
|
*
|
|
* A single markDirty() call at the end ensures the scene graph is properly invalidated.
|
|
* WARNING: Only use for hot paths where performance is critical and properties don't need
|
|
* individual change detection (e.g., when updating many nodes in a loop).
|
|
*/
|
|
setWickProperties(wickStroke, wickStrokeWidth, wickStrokeOpacity, wickLineDash, wickLineDashOffset) {
|
|
this.__wickStroke = wickStroke;
|
|
this.__wickStrokeWidth = wickStrokeWidth;
|
|
this.__wickStrokeOpacity = wickStrokeOpacity;
|
|
this.wickLineDash = wickLineDash;
|
|
this.__wickLineDashOffset = wickLineDashOffset;
|
|
this.dirtyPath = true;
|
|
this.markDirty();
|
|
}
|
|
computeDefaultGradientFillBBox() {
|
|
const { __width: width, __centerX: centerX, __yOpen: yOpen, __yClose: yClose } = this;
|
|
const boxTop = Math.min(yOpen, yClose);
|
|
const boxBottom = Math.max(yOpen, yClose);
|
|
const rectHeight = boxBottom - boxTop;
|
|
const x0 = centerX - width / 2;
|
|
const x1 = centerX + width / 2;
|
|
return new BBox12(x0, boxTop, x1 - x0, rectHeight);
|
|
}
|
|
updatePath() {
|
|
const {
|
|
path,
|
|
stroke: stroke3,
|
|
strokeWidth,
|
|
strokeOpacity,
|
|
lineDash,
|
|
lineDashOffset,
|
|
__wickStroke: wickStroke,
|
|
__wickStrokeWidth: wickStrokeWidth,
|
|
__wickStrokeOpacity: wickStrokeOpacity,
|
|
wickLineDash,
|
|
__wickLineDashOffset: wickLineDashOffset
|
|
} = this;
|
|
const { centerX, x0, x1, y0, y1, yOpen, yClose } = this.alignedCoordinates();
|
|
const pixelRatio = this.layerManager?.canvas.pixelRatio ?? 1;
|
|
const wickStrokeAlignment = this.__wickStrokeAlignment > 0 ? pixelRatio / this.__wickStrokeAlignment / 2 % 1 : 0;
|
|
this.path.clear();
|
|
this.wickPath.clear();
|
|
const needsWickPath = wickStroke != null && wickStroke !== stroke3 || wickStrokeWidth != null && wickStrokeWidth !== strokeWidth || wickStrokeOpacity != null && wickStrokeOpacity !== strokeOpacity || wickLineDash != null && wickLineDash !== lineDash || wickLineDashOffset != null && wickLineDashOffset !== lineDashOffset;
|
|
const wickPath = needsWickPath ? this.wickPath : path;
|
|
if (Math.abs(x1 - x0) <= 3) {
|
|
wickPath.moveTo(centerX - wickStrokeAlignment, y0);
|
|
wickPath.lineTo(centerX - wickStrokeAlignment, y1);
|
|
return;
|
|
}
|
|
const boxTop = Math.min(yOpen, yClose);
|
|
const boxBottom = Math.max(yOpen, yClose);
|
|
const boxStrokeAdjustment = strokeWidth / 2;
|
|
wickPath.moveTo(centerX - wickStrokeAlignment, y0);
|
|
wickPath.lineTo(centerX - wickStrokeAlignment, boxTop + boxStrokeAdjustment);
|
|
wickPath.moveTo(centerX - wickStrokeAlignment, y1);
|
|
wickPath.lineTo(centerX - wickStrokeAlignment, boxBottom - boxStrokeAdjustment);
|
|
const rectHeight = boxBottom - boxTop - 2 * boxStrokeAdjustment;
|
|
if (rectHeight > 0) {
|
|
path.rect(
|
|
x0 + boxStrokeAdjustment,
|
|
boxTop + boxStrokeAdjustment,
|
|
x1 - x0 - 2 * boxStrokeAdjustment,
|
|
rectHeight
|
|
);
|
|
} else {
|
|
const boxMid = (boxTop + boxBottom) / 2;
|
|
path.moveTo(x0, boxMid);
|
|
path.lineTo(x1, boxMid);
|
|
}
|
|
}
|
|
drawPath(ctx) {
|
|
super.drawPath(ctx);
|
|
const { wickPath } = this;
|
|
if (wickPath.isEmpty())
|
|
return;
|
|
const {
|
|
stroke: stroke3,
|
|
strokeWidth,
|
|
strokeOpacity,
|
|
lineDash,
|
|
lineDashOffset,
|
|
__wickStroke: wickStroke = stroke3,
|
|
__wickStrokeWidth: wickStrokeWidth = strokeWidth,
|
|
__wickStrokeOpacity: wickStrokeOpacity = strokeOpacity,
|
|
wickLineDash = lineDash,
|
|
__wickLineDashOffset: wickLineDashOffset = lineDashOffset
|
|
} = this;
|
|
if (wickStrokeWidth === 0)
|
|
return;
|
|
ctx.globalAlpha *= wickStrokeOpacity;
|
|
if (typeof wickStroke === "string") {
|
|
ctx.strokeStyle = wickStroke;
|
|
}
|
|
ctx.lineWidth = wickStrokeWidth;
|
|
if (wickLineDash != null) {
|
|
ctx.setLineDash([...wickLineDash]);
|
|
}
|
|
ctx.lineDashOffset = wickLineDashOffset;
|
|
ctx.stroke(wickPath.getPath2D());
|
|
}
|
|
};
|
|
__decorateClass([
|
|
DeclaredSceneChangeDetection2()
|
|
], CandlestickNode.prototype, "wickStroke", 2);
|
|
__decorateClass([
|
|
DeclaredSceneChangeDetection2()
|
|
], CandlestickNode.prototype, "wickStrokeWidth", 2);
|
|
__decorateClass([
|
|
DeclaredSceneChangeDetection2()
|
|
], CandlestickNode.prototype, "wickStrokeOpacity", 2);
|
|
__decorateClass([
|
|
SceneArrayChangeDetection2()
|
|
], CandlestickNode.prototype, "wickLineDash", 2);
|
|
__decorateClass([
|
|
DeclaredSceneChangeDetection2()
|
|
], CandlestickNode.prototype, "wickLineDashOffset", 2);
|
|
__decorateClass([
|
|
DeclaredSceneChangeDetection2()
|
|
], CandlestickNode.prototype, "wickStrokeAlignment", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/series/candlestick/candlestickSeriesProperties.ts
|
|
import { _ModuleSupport as _ModuleSupport92 } from "ag-charts-community";
|
|
import { BaseProperties as BaseProperties21, Property as Property52 } from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/series/ohlc/ohlcSeriesProperties.ts
|
|
import { _ModuleSupport as _ModuleSupport91 } from "ag-charts-community";
|
|
import { BaseProperties as BaseProperties20, Property as Property51 } from "ag-charts-core";
|
|
var { AbstractBarSeriesProperties: AbstractBarSeriesProperties2, makeSeriesTooltip: makeSeriesTooltip2 } = _ModuleSupport91;
|
|
var OhlcSeriesItem = class extends BaseProperties20 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.stroke = "#333";
|
|
this.strokeWidth = 1;
|
|
this.strokeOpacity = 1;
|
|
this.lineDash = [0];
|
|
this.lineDashOffset = 0;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property51
|
|
], OhlcSeriesItem.prototype, "stroke", 2);
|
|
__decorateClass([
|
|
Property51
|
|
], OhlcSeriesItem.prototype, "strokeWidth", 2);
|
|
__decorateClass([
|
|
Property51
|
|
], OhlcSeriesItem.prototype, "strokeOpacity", 2);
|
|
__decorateClass([
|
|
Property51
|
|
], OhlcSeriesItem.prototype, "lineDash", 2);
|
|
__decorateClass([
|
|
Property51
|
|
], OhlcSeriesItem.prototype, "lineDashOffset", 2);
|
|
var OhlcSeriesItems = class extends BaseProperties20 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.up = new OhlcSeriesItem();
|
|
this.down = new OhlcSeriesItem();
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property51
|
|
], OhlcSeriesItems.prototype, "up", 2);
|
|
__decorateClass([
|
|
Property51
|
|
], OhlcSeriesItems.prototype, "down", 2);
|
|
var OhlcSeriesBaseProperties = class extends AbstractBarSeriesProperties2 {
|
|
};
|
|
__decorateClass([
|
|
Property51
|
|
], OhlcSeriesBaseProperties.prototype, "xKey", 2);
|
|
__decorateClass([
|
|
Property51
|
|
], OhlcSeriesBaseProperties.prototype, "openKey", 2);
|
|
__decorateClass([
|
|
Property51
|
|
], OhlcSeriesBaseProperties.prototype, "closeKey", 2);
|
|
__decorateClass([
|
|
Property51
|
|
], OhlcSeriesBaseProperties.prototype, "highKey", 2);
|
|
__decorateClass([
|
|
Property51
|
|
], OhlcSeriesBaseProperties.prototype, "lowKey", 2);
|
|
__decorateClass([
|
|
Property51
|
|
], OhlcSeriesBaseProperties.prototype, "xName", 2);
|
|
__decorateClass([
|
|
Property51
|
|
], OhlcSeriesBaseProperties.prototype, "yName", 2);
|
|
__decorateClass([
|
|
Property51
|
|
], OhlcSeriesBaseProperties.prototype, "openName", 2);
|
|
__decorateClass([
|
|
Property51
|
|
], OhlcSeriesBaseProperties.prototype, "closeName", 2);
|
|
__decorateClass([
|
|
Property51
|
|
], OhlcSeriesBaseProperties.prototype, "highName", 2);
|
|
__decorateClass([
|
|
Property51
|
|
], OhlcSeriesBaseProperties.prototype, "lowName", 2);
|
|
var OhlcSeriesProperties = class extends OhlcSeriesBaseProperties {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.tooltip = makeSeriesTooltip2();
|
|
this.item = new OhlcSeriesItems();
|
|
}
|
|
getStyle(itemType) {
|
|
const { strokeWidth, strokeOpacity, stroke: stroke3, lineDash, lineDashOffset } = this.item[itemType];
|
|
return {
|
|
stroke: stroke3,
|
|
strokeWidth,
|
|
strokeOpacity,
|
|
lineDash,
|
|
lineDashOffset,
|
|
opacity: 1
|
|
};
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property51
|
|
], OhlcSeriesProperties.prototype, "tooltip", 2);
|
|
__decorateClass([
|
|
Property51
|
|
], OhlcSeriesProperties.prototype, "item", 2);
|
|
__decorateClass([
|
|
Property51
|
|
], OhlcSeriesProperties.prototype, "itemStyler", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/series/candlestick/candlestickSeriesProperties.ts
|
|
var { makeSeriesTooltip: makeSeriesTooltip3 } = _ModuleSupport92;
|
|
var CandlestickSeriesWick = class extends BaseProperties21 {
|
|
};
|
|
__decorateClass([
|
|
Property52
|
|
], CandlestickSeriesWick.prototype, "stroke", 2);
|
|
__decorateClass([
|
|
Property52
|
|
], CandlestickSeriesWick.prototype, "strokeWidth", 2);
|
|
__decorateClass([
|
|
Property52
|
|
], CandlestickSeriesWick.prototype, "strokeOpacity", 2);
|
|
__decorateClass([
|
|
Property52
|
|
], CandlestickSeriesWick.prototype, "lineDash", 2);
|
|
__decorateClass([
|
|
Property52
|
|
], CandlestickSeriesWick.prototype, "lineDashOffset", 2);
|
|
var CandlestickSeriesItem = class extends BaseProperties21 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.fill = "#c16068";
|
|
this.fillOpacity = 1;
|
|
this.stroke = "#333";
|
|
this.strokeWidth = 1;
|
|
this.strokeOpacity = 1;
|
|
this.lineDash = [0];
|
|
this.lineDashOffset = 0;
|
|
this.cornerRadius = 0;
|
|
this.wick = new CandlestickSeriesWick();
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property52
|
|
], CandlestickSeriesItem.prototype, "fill", 2);
|
|
__decorateClass([
|
|
Property52
|
|
], CandlestickSeriesItem.prototype, "fillOpacity", 2);
|
|
__decorateClass([
|
|
Property52
|
|
], CandlestickSeriesItem.prototype, "stroke", 2);
|
|
__decorateClass([
|
|
Property52
|
|
], CandlestickSeriesItem.prototype, "strokeWidth", 2);
|
|
__decorateClass([
|
|
Property52
|
|
], CandlestickSeriesItem.prototype, "strokeOpacity", 2);
|
|
__decorateClass([
|
|
Property52
|
|
], CandlestickSeriesItem.prototype, "lineDash", 2);
|
|
__decorateClass([
|
|
Property52
|
|
], CandlestickSeriesItem.prototype, "lineDashOffset", 2);
|
|
__decorateClass([
|
|
Property52
|
|
], CandlestickSeriesItem.prototype, "cornerRadius", 2);
|
|
__decorateClass([
|
|
Property52
|
|
], CandlestickSeriesItem.prototype, "wick", 2);
|
|
var CandlestickSeriesItems = class extends BaseProperties21 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.up = new CandlestickSeriesItem();
|
|
this.down = new CandlestickSeriesItem();
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property52
|
|
], CandlestickSeriesItems.prototype, "up", 2);
|
|
__decorateClass([
|
|
Property52
|
|
], CandlestickSeriesItems.prototype, "down", 2);
|
|
var CandlestickSeriesProperties = class extends OhlcSeriesBaseProperties {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.item = new CandlestickSeriesItems();
|
|
this.tooltip = makeSeriesTooltip3();
|
|
}
|
|
getStyle(itemType) {
|
|
const { fill, fillOpacity, strokeWidth, strokeOpacity, stroke: stroke3, lineDash, lineDashOffset, cornerRadius, wick } = this.item[itemType];
|
|
return {
|
|
fill,
|
|
fillOpacity,
|
|
stroke: stroke3,
|
|
strokeWidth,
|
|
strokeOpacity,
|
|
lineDash,
|
|
lineDashOffset,
|
|
cornerRadius,
|
|
opacity: 1,
|
|
wick
|
|
};
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property52
|
|
], CandlestickSeriesProperties.prototype, "item", 2);
|
|
__decorateClass([
|
|
Property52
|
|
], CandlestickSeriesProperties.prototype, "tooltip", 2);
|
|
__decorateClass([
|
|
Property52
|
|
], CandlestickSeriesProperties.prototype, "itemStyler", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/series/candlestick/candlestickSeries.ts
|
|
var CandlestickSeries = class extends OhlcSeriesBase {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.properties = new CandlestickSeriesProperties();
|
|
}
|
|
nodeFactory() {
|
|
const node = new CandlestickNode();
|
|
node.lineCap = "butt";
|
|
return node;
|
|
}
|
|
updateDatumStyles({
|
|
datumSelection,
|
|
isHighlight
|
|
}) {
|
|
datumSelection.each((_, datum) => {
|
|
datum.style = this.getItemStyle(datum.datumIndex, isHighlight, void 0, datum.itemType);
|
|
});
|
|
}
|
|
updateDatumNodes({
|
|
datumSelection,
|
|
isHighlight
|
|
}) {
|
|
const { contextNodeData, properties } = this;
|
|
if (!contextNodeData) {
|
|
return;
|
|
}
|
|
const highlightedDatum = this.ctx.highlightManager.getActiveHighlight();
|
|
const { up, down } = properties.item;
|
|
const fillBBox = this.getShapeFillBBox();
|
|
const series = this;
|
|
datumSelection.each(function updateCandlestickNode(node, datum) {
|
|
const { centerX, width, y, height, yOpen, yClose, crisp } = datum;
|
|
const baseStyle = datum.isRising ? up : down;
|
|
const highlightState = series.getHighlightState(highlightedDatum, isHighlight, datum.datumIndex);
|
|
const style = datum.style ?? contextNodeData.styles[datum.itemType][highlightState];
|
|
node.setStaticProperties(centerX, width, y, height, yOpen, yClose, crisp);
|
|
node.setStyleProperties(style, fillBBox);
|
|
const styleWick = style?.wick;
|
|
node.setWickProperties(
|
|
styleWick?.stroke,
|
|
styleWick?.strokeWidth,
|
|
styleWick?.strokeOpacity,
|
|
styleWick?.lineDash,
|
|
styleWick?.lineDashOffset
|
|
);
|
|
node.wickStrokeAlignment = baseStyle.wick.strokeWidth ?? baseStyle.strokeWidth;
|
|
});
|
|
}
|
|
legendItemSymbol() {
|
|
const { up, down } = this.properties.item;
|
|
const upColorStops = isGradientFill(up.fill) ? up.fill.colorStops.map(
|
|
(c) => typeof c === "string" ? c : { color: c.color, stop: c.stop == null ? void 0 : c.stop * 0.5 }
|
|
) : [
|
|
{ color: isPatternFill(up.fill) || isImageFill(up.fill) ? up.stroke : up.fill, stop: 0 },
|
|
{ color: isPatternFill(up.fill) || isImageFill(up.fill) ? up.stroke : up.fill, stop: 0.5 }
|
|
];
|
|
const downColorStops = isGradientFill(down.fill) ? down.fill.colorStops.map(
|
|
(c) => typeof c === "string" ? c : { color: c.color, stop: c.stop == null ? void 0 : c.stop * 0.5 }
|
|
) : [{ color: isPatternFill(down.fill) || isImageFill(down.fill) ? down.stroke : down.fill, stop: 0.5 }];
|
|
const fill = {
|
|
type: "gradient",
|
|
gradient: "linear",
|
|
rotation: 90,
|
|
colorStops: [...upColorStops, ...downColorStops],
|
|
reverse: false
|
|
};
|
|
const stroke3 = {
|
|
type: "gradient",
|
|
gradient: "linear",
|
|
rotation: 90,
|
|
colorStops: [
|
|
{ color: up.stroke, stop: 0 },
|
|
{ color: up.stroke, stop: 0.5 },
|
|
{ color: down.stroke, stop: 0.5 }
|
|
],
|
|
reverse: false
|
|
};
|
|
return {
|
|
marker: {
|
|
fill,
|
|
fillOpacity: up.fillOpacity,
|
|
stroke: stroke3,
|
|
strokeWidth: up.strokeWidth ?? 1,
|
|
strokeOpacity: up.strokeOpacity ?? 1,
|
|
lineDash: up.lineDash,
|
|
lineDashOffset: up.lineDashOffset
|
|
}
|
|
};
|
|
}
|
|
getLegendData(legendType) {
|
|
const {
|
|
id,
|
|
data,
|
|
visible,
|
|
ctx: { legendManager }
|
|
} = this;
|
|
const { xKey, yName, showInLegend, legendItemName } = this.properties;
|
|
if (!data?.data.length || !xKey || legendType !== "category") {
|
|
return [];
|
|
}
|
|
return [
|
|
{
|
|
legendType: "category",
|
|
id,
|
|
itemId: id,
|
|
seriesId: id,
|
|
enabled: visible && legendManager.getItemEnabled({ seriesId: id, itemId: id }),
|
|
label: {
|
|
text: legendItemName ?? yName ?? id
|
|
},
|
|
symbol: this.legendItemSymbol(),
|
|
legendItemName,
|
|
hideInLegend: !showInLegend
|
|
}
|
|
];
|
|
}
|
|
hasItemStylers() {
|
|
return this.properties.itemStyler != null;
|
|
}
|
|
};
|
|
CandlestickSeries.className = "CandleStickSeries";
|
|
CandlestickSeries.type = "candlestick";
|
|
|
|
// packages/ag-charts-enterprise/src/series/candlestick/candlestickSeriesOptionsDef.ts
|
|
import { _ModuleSupport as _ModuleSupport94 } from "ag-charts-community";
|
|
import {
|
|
boolean as boolean7,
|
|
commonSeriesOptionsDefs as commonSeriesOptionsDefs2,
|
|
constant as constant2,
|
|
number,
|
|
required as required2,
|
|
string as string2,
|
|
undocumented as undocumented4
|
|
} from "ag-charts-core";
|
|
var { candlestickSeriesThemeableOptionsDef } = _ModuleSupport94;
|
|
var candlestickSeriesOptionsDef = {
|
|
...commonSeriesOptionsDefs2,
|
|
...candlestickSeriesThemeableOptionsDef,
|
|
type: required2(constant2("candlestick")),
|
|
xKey: required2(string2),
|
|
openKey: required2(string2),
|
|
highKey: required2(string2),
|
|
lowKey: required2(string2),
|
|
closeKey: required2(string2),
|
|
xName: string2,
|
|
yName: string2,
|
|
openName: string2,
|
|
highName: string2,
|
|
lowName: string2,
|
|
closeName: string2,
|
|
xKeyAxis: string2,
|
|
yKeyAxis: string2
|
|
};
|
|
candlestickSeriesOptionsDef.pickOutsideVisibleMinorAxis = undocumented4(boolean7);
|
|
candlestickSeriesOptionsDef.focusPriority = undocumented4(number);
|
|
|
|
// packages/ag-charts-enterprise/src/series/candlestick/candlestickThemes.ts
|
|
import "ag-charts-community";
|
|
import {
|
|
CARTESIAN_AXIS_TYPE as CARTESIAN_AXIS_TYPE2,
|
|
FILL_GRADIENT_LINEAR_KEYED_DEFAULTS,
|
|
FILL_IMAGE_DEFAULTS as FILL_IMAGE_DEFAULTS2,
|
|
FILL_PATTERN_KEYED_DEFAULTS,
|
|
MULTI_SERIES_HIGHLIGHT_STYLE
|
|
} from "ag-charts-core";
|
|
function itemTheme(key) {
|
|
return {
|
|
fill: {
|
|
$applySwitch: [
|
|
{ $path: "type" },
|
|
{
|
|
$if: [
|
|
{ $eq: [{ $palette: "type" }, "user-indexed"] },
|
|
key === "up" ? "transparent" : { $palette: "fill" },
|
|
{ $palette: `${key}.fill` }
|
|
]
|
|
},
|
|
["gradient", FILL_GRADIENT_LINEAR_KEYED_DEFAULTS(key)],
|
|
["image", FILL_IMAGE_DEFAULTS2],
|
|
["pattern", FILL_PATTERN_KEYED_DEFAULTS(key)]
|
|
]
|
|
},
|
|
stroke: {
|
|
$if: [
|
|
{ $eq: [{ $palette: "type" }, "user-indexed"] },
|
|
{ $palette: "stroke" },
|
|
{ $palette: `${key}.stroke` }
|
|
]
|
|
}
|
|
};
|
|
}
|
|
var CANDLESTICK_SERIES_THEME = {
|
|
series: {
|
|
item: {
|
|
up: itemTheme("up"),
|
|
down: itemTheme("down")
|
|
},
|
|
tooltip: {
|
|
range: { $path: ["/tooltip/range", "nearest"] }
|
|
},
|
|
highlight: MULTI_SERIES_HIGHLIGHT_STYLE
|
|
},
|
|
animation: { enabled: false },
|
|
axes: {
|
|
[CARTESIAN_AXIS_TYPE2.NUMBER]: {
|
|
crosshair: {
|
|
snap: false
|
|
}
|
|
},
|
|
[CARTESIAN_AXIS_TYPE2.ORDINAL_TIME]: {
|
|
groupPaddingInner: 0,
|
|
crosshair: {
|
|
enabled: true
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/series/candlestick/candlestickModule.ts
|
|
var { predictCartesianFinancialAxis } = _ModuleSupport95;
|
|
var CandlestickSeriesModule = {
|
|
type: "series",
|
|
name: "candlestick",
|
|
chartType: "cartesian",
|
|
enterprise: true,
|
|
groupable: false,
|
|
version: VERSION16,
|
|
dependencies: [CartesianChartModule2],
|
|
options: candlestickSeriesOptionsDef,
|
|
matchingKeys: ["xKey", "lowKey", "highKey", "openKey", "closeKey", "normalizedTo"],
|
|
predictAxis: predictCartesianFinancialAxis,
|
|
defaultAxes: {
|
|
y: {
|
|
type: CARTESIAN_AXIS_TYPE3.NUMBER,
|
|
position: CARTESIAN_POSITION.LEFT
|
|
},
|
|
x: {
|
|
type: CARTESIAN_AXIS_TYPE3.ORDINAL_TIME,
|
|
position: CARTESIAN_POSITION.BOTTOM
|
|
}
|
|
},
|
|
axisKeys: { [ChartAxisDirection18.X]: "xKeyAxis", [ChartAxisDirection18.Y]: "yKeyAxis" },
|
|
themeTemplate: CANDLESTICK_SERIES_THEME,
|
|
create: (ctx) => new CandlestickSeries(ctx)
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/series/heatmap/heatmapModule.ts
|
|
import { CartesianChartModule as CartesianChartModule3, VERSION as VERSION17 } from "ag-charts-community";
|
|
import { CARTESIAN_AXIS_TYPE as CARTESIAN_AXIS_TYPE4, CARTESIAN_POSITION as CARTESIAN_POSITION2, ChartAxisDirection as ChartAxisDirection20 } from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/series/heatmap/heatmapSeries.ts
|
|
import { _ModuleSupport as _ModuleSupport98 } from "ag-charts-community";
|
|
import {
|
|
ChartAxisDirection as ChartAxisDirection19,
|
|
Logger as Logger11,
|
|
extent,
|
|
formatValue,
|
|
mergeDefaults as mergeDefaults6,
|
|
toPlainText as toPlainText3
|
|
} from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/series/util/labelFormatter.ts
|
|
import { Logger as Logger10, cachedTextMeasurer as cachedTextMeasurer2, findMaxValue, wrapLines } from "ag-charts-core";
|
|
function generateLabelSecondaryLabelFontSizeCandidates(label, secondaryLabel) {
|
|
const { fontSize: labelFontSize, minimumFontSize: labelMinimumFontSize = labelFontSize } = label;
|
|
const {
|
|
fontSize: secondaryLabelFontSize,
|
|
minimumFontSize: secondaryLabelMinimumFontSize = secondaryLabelFontSize
|
|
} = secondaryLabel;
|
|
const labelTracks = labelFontSize - labelMinimumFontSize;
|
|
const secondaryLabelTracks = secondaryLabelFontSize - secondaryLabelMinimumFontSize;
|
|
let currentLabelFontSize = label.fontSize;
|
|
let currentSecondaryLabelFontSize = secondaryLabel.fontSize;
|
|
const out = [{ labelFontSize, secondaryLabelFontSize }];
|
|
while (currentLabelFontSize > labelMinimumFontSize || currentSecondaryLabelFontSize > secondaryLabelMinimumFontSize) {
|
|
const labelProgress = labelTracks > 0 ? (currentLabelFontSize - labelMinimumFontSize) / labelTracks : -1;
|
|
const secondaryLabelProgress = secondaryLabelTracks > 0 ? (currentSecondaryLabelFontSize - secondaryLabelMinimumFontSize) / secondaryLabelTracks : -1;
|
|
if (labelProgress > secondaryLabelProgress) {
|
|
currentLabelFontSize--;
|
|
} else {
|
|
currentSecondaryLabelFontSize--;
|
|
}
|
|
out.push({
|
|
labelFontSize: currentLabelFontSize,
|
|
secondaryLabelFontSize: currentSecondaryLabelFontSize
|
|
});
|
|
}
|
|
out.reverse();
|
|
return out;
|
|
}
|
|
function formatStackedLabels(labelValue, labelProps, secondaryLabelValue, secondaryLabelProps, { padding: padding2 }, sizeFittingHeight) {
|
|
const { spacing = 0 } = labelProps;
|
|
const widthAdjust = 2 * padding2;
|
|
const heightAdjust = 2 * padding2 + spacing;
|
|
const minimumHeight = (labelProps.minimumFontSize ?? labelProps.fontSize) + (secondaryLabelProps.minimumFontSize ?? secondaryLabelProps.fontSize);
|
|
if (minimumHeight > sizeFittingHeight(minimumHeight + heightAdjust, false).height - heightAdjust)
|
|
return;
|
|
const fontSizeCandidates = generateLabelSecondaryLabelFontSizeCandidates(labelProps, secondaryLabelProps);
|
|
const labelTextSizeProps = {
|
|
fontFamily: labelProps.fontFamily,
|
|
fontStyle: labelProps.fontStyle,
|
|
fontWeight: labelProps.fontWeight
|
|
};
|
|
const secondaryLabelTextSizeProps = {
|
|
fontFamily: secondaryLabelProps.fontFamily,
|
|
fontStyle: secondaryLabelProps.fontStyle,
|
|
fontWeight: secondaryLabelProps.fontWeight
|
|
};
|
|
let label;
|
|
let secondaryLabel;
|
|
return findMaxValue(0, fontSizeCandidates.length - 1, (index) => {
|
|
const { labelFontSize, secondaryLabelFontSize } = fontSizeCandidates[index];
|
|
const allowTruncation = index === 0;
|
|
const labelFont = { ...labelTextSizeProps, fontSize: labelFontSize };
|
|
const secondaryLabelFont = { ...secondaryLabelTextSizeProps, fontSize: secondaryLabelFontSize };
|
|
const labelLineHeight = cachedTextMeasurer2(labelFont).lineHeight();
|
|
const secondaryLabelLineHeight = cachedTextMeasurer2(secondaryLabelFont).lineHeight();
|
|
const sizeFitting = sizeFittingHeight(
|
|
labelLineHeight + secondaryLabelLineHeight + heightAdjust,
|
|
allowTruncation
|
|
);
|
|
const availableWidth = sizeFitting.width - widthAdjust;
|
|
const availableHeight = sizeFitting.height - heightAdjust;
|
|
if (labelLineHeight + secondaryLabelLineHeight > availableHeight)
|
|
return;
|
|
if (label?.fontSize !== labelFontSize) {
|
|
label = wrapLabel(
|
|
labelProps,
|
|
labelValue,
|
|
availableWidth,
|
|
availableHeight,
|
|
labelFont,
|
|
labelProps.wrapping,
|
|
allowTruncation ? labelProps.overflowStrategy : "hide"
|
|
);
|
|
}
|
|
if (label == null || label.width > availableWidth || label.height > availableHeight)
|
|
return;
|
|
if (secondaryLabel?.fontSize !== secondaryLabelFontSize) {
|
|
secondaryLabel = wrapLabel(
|
|
secondaryLabelProps,
|
|
secondaryLabelValue,
|
|
availableWidth,
|
|
availableHeight,
|
|
secondaryLabelFont,
|
|
secondaryLabelProps.wrapping,
|
|
allowTruncation ? secondaryLabelProps.overflowStrategy : "hide"
|
|
);
|
|
}
|
|
if (secondaryLabel == null)
|
|
return;
|
|
const totalLabelHeight = label.height + secondaryLabel.height;
|
|
if (secondaryLabel.width > availableWidth || totalLabelHeight > availableHeight)
|
|
return;
|
|
return {
|
|
width: Math.max(label.width, secondaryLabel.width),
|
|
height: totalLabelHeight + spacing,
|
|
meta: sizeFitting.meta,
|
|
label,
|
|
secondaryLabel
|
|
};
|
|
});
|
|
}
|
|
function formatSingleLabel(value, props, { padding: padding2 }, sizeFittingHeight) {
|
|
const sizeAdjust = 2 * padding2;
|
|
const minimumFontSize = Math.min(props.minimumFontSize ?? props.fontSize, props.fontSize);
|
|
const textSizeProps = {
|
|
fontFamily: props.fontFamily,
|
|
fontStyle: props.fontStyle,
|
|
fontWeight: props.fontWeight
|
|
};
|
|
return findMaxValue(minimumFontSize, props.fontSize, (fontSize) => {
|
|
const currentFont = { ...textSizeProps, fontSize };
|
|
const measurer3 = cachedTextMeasurer2(currentFont);
|
|
const allowTruncation = fontSize === minimumFontSize;
|
|
const lineHeight = props.lineHeight ?? measurer3.lineHeight();
|
|
const sizeFitting = sizeFittingHeight(lineHeight + sizeAdjust, allowTruncation);
|
|
const availableWidth = sizeFitting.width - sizeAdjust;
|
|
const availableHeight = sizeFitting.height - sizeAdjust;
|
|
if (lineHeight > availableHeight || availableWidth < 0)
|
|
return;
|
|
const lines = wrapLines(value, {
|
|
maxWidth: availableWidth,
|
|
maxHeight: availableHeight,
|
|
font: currentFont,
|
|
textWrap: props.wrapping,
|
|
overflow: (allowTruncation ? props.overflowStrategy : null) ?? "hide"
|
|
});
|
|
if (!lines.length)
|
|
return;
|
|
const { width, height } = measurer3.measureLines(lines);
|
|
const text2 = lines.join("\n");
|
|
return [{ width, height, text: text2, fontSize, lineHeight }, sizeFitting.meta];
|
|
});
|
|
}
|
|
function hasInvalidFontSize(label) {
|
|
return label?.minimumFontSize != null && label?.fontSize != null && label?.minimumFontSize > label?.fontSize;
|
|
}
|
|
function formatLabels(baseLabelValue, labelProps, baseSecondaryLabelValue, secondaryLabelProps, layoutParams, sizeFittingHeight) {
|
|
const labelValue = labelProps.enabled ? baseLabelValue : void 0;
|
|
const secondaryLabelValue = secondaryLabelProps.enabled ? baseSecondaryLabelValue : void 0;
|
|
if (hasInvalidFontSize(labelProps) || hasInvalidFontSize(secondaryLabelProps)) {
|
|
Logger10.warnOnce(`minimumFontSize should be set to a value less than or equal to the font size`);
|
|
}
|
|
let value;
|
|
if (labelValue != null && secondaryLabelValue != null) {
|
|
value = formatStackedLabels(
|
|
labelValue,
|
|
labelProps,
|
|
secondaryLabelValue,
|
|
secondaryLabelProps,
|
|
layoutParams,
|
|
sizeFittingHeight
|
|
);
|
|
}
|
|
let labelMeta;
|
|
if (value == null && labelValue != null) {
|
|
labelMeta = formatSingleLabel(labelValue, labelProps, layoutParams, sizeFittingHeight);
|
|
}
|
|
if (labelMeta != null) {
|
|
const [label, meta] = labelMeta;
|
|
value = {
|
|
width: label.width,
|
|
height: label.height,
|
|
meta,
|
|
label,
|
|
secondaryLabel: void 0
|
|
};
|
|
}
|
|
let secondaryLabelMeta;
|
|
if (value == null && labelValue == null && secondaryLabelValue != null) {
|
|
secondaryLabelMeta = formatSingleLabel(
|
|
secondaryLabelValue,
|
|
secondaryLabelProps,
|
|
layoutParams,
|
|
sizeFittingHeight
|
|
);
|
|
}
|
|
if (secondaryLabelMeta != null) {
|
|
const [secondaryLabel, meta] = secondaryLabelMeta;
|
|
value = {
|
|
width: secondaryLabel.width,
|
|
height: secondaryLabel.height,
|
|
meta,
|
|
label: void 0,
|
|
secondaryLabel
|
|
};
|
|
}
|
|
return value;
|
|
}
|
|
function wrapLabel(props, text2, maxWidth, maxHeight, font3, textWrap, overflow) {
|
|
const lines = wrapLines(text2, { maxWidth, maxHeight, font: font3, textWrap, overflow });
|
|
if (!lines.length)
|
|
return;
|
|
const measurer3 = cachedTextMeasurer2(font3);
|
|
const lineHeight = props.lineHeight ?? measurer3.lineHeight();
|
|
const { width } = measurer3.measureLines(lines);
|
|
return {
|
|
width,
|
|
lineHeight,
|
|
text: lines.join("\n"),
|
|
height: lines.length * lineHeight,
|
|
fontSize: font3.fontSize
|
|
};
|
|
}
|
|
|
|
// packages/ag-charts-enterprise/src/series/heatmap/heatmapSeriesProperties.ts
|
|
import { _ModuleSupport as _ModuleSupport97 } from "ag-charts-community";
|
|
import { Property as Property54 } from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/series/util/autoSizedLabel.ts
|
|
import { _ModuleSupport as _ModuleSupport96 } from "ag-charts-community";
|
|
import { Property as Property53 } from "ag-charts-core";
|
|
var BaseAutoSizedLabel = class extends _ModuleSupport96.Label {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.wrapping = "on-space";
|
|
this.overflowStrategy = "ellipsis";
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property53
|
|
], BaseAutoSizedLabel.prototype, "wrapping", 2);
|
|
__decorateClass([
|
|
Property53
|
|
], BaseAutoSizedLabel.prototype, "overflowStrategy", 2);
|
|
__decorateClass([
|
|
Property53
|
|
], BaseAutoSizedLabel.prototype, "lineHeight", 2);
|
|
__decorateClass([
|
|
Property53
|
|
], BaseAutoSizedLabel.prototype, "minimumFontSize", 2);
|
|
var AutoSizedLabel = class extends BaseAutoSizedLabel {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.spacing = 0;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property53
|
|
], AutoSizedLabel.prototype, "spacing", 2);
|
|
var AutoSizedSecondaryLabel = class extends BaseAutoSizedLabel {
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/series/heatmap/heatmapSeriesProperties.ts
|
|
var { CartesianSeriesProperties, makeSeriesTooltip: makeSeriesTooltip4 } = _ModuleSupport97;
|
|
var HeatmapSeriesProperties = class extends CartesianSeriesProperties {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.colorRange = ["black", "black"];
|
|
this.stroke = "black";
|
|
this.strokeOpacity = 1;
|
|
this.strokeWidth = 0;
|
|
this.textAlign = "center";
|
|
this.verticalAlign = "middle";
|
|
this.itemPadding = 0;
|
|
this.label = new AutoSizedLabel();
|
|
this.tooltip = makeSeriesTooltip4();
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property54
|
|
], HeatmapSeriesProperties.prototype, "title", 2);
|
|
__decorateClass([
|
|
Property54
|
|
], HeatmapSeriesProperties.prototype, "xKey", 2);
|
|
__decorateClass([
|
|
Property54
|
|
], HeatmapSeriesProperties.prototype, "yKey", 2);
|
|
__decorateClass([
|
|
Property54
|
|
], HeatmapSeriesProperties.prototype, "colorKey", 2);
|
|
__decorateClass([
|
|
Property54
|
|
], HeatmapSeriesProperties.prototype, "xName", 2);
|
|
__decorateClass([
|
|
Property54
|
|
], HeatmapSeriesProperties.prototype, "yName", 2);
|
|
__decorateClass([
|
|
Property54
|
|
], HeatmapSeriesProperties.prototype, "colorName", 2);
|
|
__decorateClass([
|
|
Property54
|
|
], HeatmapSeriesProperties.prototype, "colorRange", 2);
|
|
__decorateClass([
|
|
Property54
|
|
], HeatmapSeriesProperties.prototype, "stroke", 2);
|
|
__decorateClass([
|
|
Property54
|
|
], HeatmapSeriesProperties.prototype, "strokeOpacity", 2);
|
|
__decorateClass([
|
|
Property54
|
|
], HeatmapSeriesProperties.prototype, "strokeWidth", 2);
|
|
__decorateClass([
|
|
Property54
|
|
], HeatmapSeriesProperties.prototype, "textAlign", 2);
|
|
__decorateClass([
|
|
Property54
|
|
], HeatmapSeriesProperties.prototype, "verticalAlign", 2);
|
|
__decorateClass([
|
|
Property54
|
|
], HeatmapSeriesProperties.prototype, "itemPadding", 2);
|
|
__decorateClass([
|
|
Property54
|
|
], HeatmapSeriesProperties.prototype, "itemStyler", 2);
|
|
__decorateClass([
|
|
Property54
|
|
], HeatmapSeriesProperties.prototype, "label", 2);
|
|
__decorateClass([
|
|
Property54
|
|
], HeatmapSeriesProperties.prototype, "tooltip", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/series/heatmap/heatmapSeries.ts
|
|
var {
|
|
SeriesNodePickMode: SeriesNodePickMode3,
|
|
computeBarFocusBounds: computeBarFocusBounds3,
|
|
getMissCount,
|
|
valueProperty: valueProperty5,
|
|
DEFAULT_CARTESIAN_DIRECTION_KEYS,
|
|
DEFAULT_CARTESIAN_DIRECTION_NAMES,
|
|
createDatumId: createDatumId3,
|
|
ColorScale,
|
|
Rect,
|
|
PointerEvents,
|
|
addHitTestersToQuadtree,
|
|
findQuadtreeMatch,
|
|
updateLabelNode,
|
|
upsertNodeDatum: upsertNodeDatum2
|
|
} = _ModuleSupport98;
|
|
var HeatmapSeriesNodeEvent = class extends _ModuleSupport98.CartesianSeriesNodeEvent {
|
|
constructor(type, nativeEvent, datum, series) {
|
|
super(type, nativeEvent, datum, series);
|
|
this.colorKey = series.properties.colorKey;
|
|
}
|
|
};
|
|
var textAlignFactors = {
|
|
left: -0.5,
|
|
center: 0,
|
|
right: -0.5
|
|
};
|
|
var verticalAlignFactors = {
|
|
top: -0.5,
|
|
middle: 0,
|
|
bottom: -0.5
|
|
};
|
|
var HeatmapSeries = class extends _ModuleSupport98.CartesianSeries {
|
|
constructor(moduleCtx) {
|
|
super({
|
|
moduleCtx,
|
|
propertyKeys: {
|
|
...DEFAULT_CARTESIAN_DIRECTION_KEYS,
|
|
color: ["colorKey"]
|
|
},
|
|
propertyNames: {
|
|
...DEFAULT_CARTESIAN_DIRECTION_NAMES,
|
|
color: ["colorName"]
|
|
},
|
|
categoryKey: void 0,
|
|
pickModes: [SeriesNodePickMode3.NEAREST_NODE, SeriesNodePickMode3.EXACT_SHAPE_MATCH],
|
|
pathsPerSeries: []
|
|
});
|
|
this.properties = new HeatmapSeriesProperties();
|
|
this.NodeEvent = HeatmapSeriesNodeEvent;
|
|
this.colorScale = new ColorScale();
|
|
}
|
|
async processData(dataController) {
|
|
const xAxis = this.axes[ChartAxisDirection19.X];
|
|
const yAxis = this.axes[ChartAxisDirection19.Y];
|
|
if (!xAxis || !yAxis) {
|
|
return;
|
|
}
|
|
const { xKey, yKey, colorRange, colorKey } = this.properties;
|
|
const xScale = this.axes[ChartAxisDirection19.X]?.scale;
|
|
const yScale = this.axes[ChartAxisDirection19.Y]?.scale;
|
|
const { xScaleType, yScaleType } = this.getScaleInformation({ xScale, yScale });
|
|
const colorScaleType = this.colorScale.type;
|
|
const allowNullKey = this.properties.allowNullKeys ?? false;
|
|
const { dataModel, processedData } = await this.requestDataModel(dataController, this.data, {
|
|
props: [
|
|
valueProperty5(xKey, xScaleType, { id: "xValue", allowNullKey }),
|
|
valueProperty5(yKey, yScaleType, { id: "yValue", allowNullKey }),
|
|
...colorKey ? [valueProperty5(colorKey, colorScaleType, { id: "colorValue", invalidValue: void 0 })] : []
|
|
]
|
|
});
|
|
if (this.isColorScaleValid()) {
|
|
const colorKeyIdx = dataModel.resolveProcessedDataIndexById(this, "colorValue");
|
|
const rawDomain = processedData.domain.values[colorKeyIdx].filter((v) => v != null);
|
|
const domain = extent(rawDomain);
|
|
this.colorScale.domain = domain ?? [];
|
|
if (domain?.length && domain[0] === domain[1]) {
|
|
const midIndex = Math.floor(colorRange.length / 2);
|
|
this.colorScale.range = [colorRange[midIndex], colorRange[midIndex]];
|
|
} else {
|
|
this.colorScale.range = colorRange;
|
|
}
|
|
this.colorScale.update();
|
|
}
|
|
}
|
|
isColorScaleValid() {
|
|
const { colorKey } = this.properties;
|
|
if (!colorKey) {
|
|
return false;
|
|
}
|
|
const { dataModel, processedData } = this;
|
|
if (!dataModel || !processedData) {
|
|
return false;
|
|
}
|
|
const colorDataIdx = dataModel.resolveProcessedDataIndexById(this, "colorValue");
|
|
const dataCount = processedData.input.count;
|
|
const missCount = getMissCount(this, processedData.defs.values[colorDataIdx].missing);
|
|
const colorKeyIdx = dataModel.resolveProcessedDataIndexById(this, "colorValue");
|
|
const actualCount = processedData.domain.values[colorKeyIdx].filter((v) => v != null).length;
|
|
const colorDataMissing = dataCount === 0 || dataCount === missCount || actualCount === 0;
|
|
return !colorDataMissing;
|
|
}
|
|
xCoordinateRange(xValue, pixelSize) {
|
|
const xScale = this.axes[ChartAxisDirection19.X].scale;
|
|
const xOffset = pixelSize * (xScale.bandwidth ?? 0) / 2;
|
|
const x = xScale.convert(xValue) + xOffset;
|
|
const width = pixelSize * (xScale.bandwidth ?? 10);
|
|
return [x, x + width];
|
|
}
|
|
yCoordinateRange(yValues, pixelSize) {
|
|
const yScale = this.axes[ChartAxisDirection19.Y].scale;
|
|
const yOffset = pixelSize * (yScale.bandwidth ?? 0) / 2;
|
|
const y = yScale.convert(yValues[0]) + yOffset;
|
|
const height = pixelSize * (yScale.bandwidth ?? 10);
|
|
return [y, y + height];
|
|
}
|
|
getSeriesDomain(direction) {
|
|
const { dataModel, processedData } = this;
|
|
if (!dataModel || !processedData)
|
|
return { domain: [] };
|
|
if (direction === ChartAxisDirection19.X) {
|
|
const domain = dataModel.getDomain(this, `xValue`, "value", processedData).domain;
|
|
return { domain };
|
|
} else {
|
|
const domain = dataModel.getDomain(this, `yValue`, "value", processedData).domain;
|
|
return { domain };
|
|
}
|
|
}
|
|
getSeriesRange() {
|
|
return [Number.NaN, Number.NaN];
|
|
}
|
|
/**
|
|
* Template method hook: Validates preconditions for createNodeData.
|
|
* Overrides base to add heatmap-specific category axis validation.
|
|
*/
|
|
validateCreateNodeDataPreconditions() {
|
|
const result = super.validateCreateNodeDataPreconditions();
|
|
if (!result)
|
|
return void 0;
|
|
const { xAxis, yAxis } = result;
|
|
if (xAxis.type !== "category" || yAxis.type !== "category") {
|
|
Logger11.warnOnce(
|
|
`Heatmap series expected axes to have "category" type, but received "${xAxis.type}" and "${yAxis.type}" instead.`
|
|
);
|
|
return void 0;
|
|
}
|
|
return result;
|
|
}
|
|
/**
|
|
* Template method hook: Iterates over data and creates/updates node datums.
|
|
*/
|
|
populateNodeData(ctx) {
|
|
for (const [datumIndex, datum] of ctx.rawData.entries()) {
|
|
const nodeDatum = upsertNodeDatum2(
|
|
ctx,
|
|
{ datumIndex, datum },
|
|
(c, p) => this.createNodeDatum(c, p.datumIndex, p.datum),
|
|
(c, n, p) => this.updateNodeDatum(c, n, p.datumIndex, p.datum)
|
|
);
|
|
if (nodeDatum) {
|
|
const labelDatum = this.createLabelDatum(ctx, datumIndex, datum, nodeDatum);
|
|
if (labelDatum) {
|
|
ctx.labels.push(labelDatum);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* Template method hook: Creates the result object shell.
|
|
*/
|
|
initializeResult(ctx) {
|
|
return {
|
|
itemId: this.properties.yKey ?? this.id,
|
|
nodeData: ctx.nodes,
|
|
labelData: ctx.labels,
|
|
scales: this.calculateScaling(),
|
|
visible: this.visible
|
|
};
|
|
}
|
|
/**
|
|
* Template method hook: Creates the shared context for datum creation.
|
|
* Caches expensive lookups and computations that are constant across all datums.
|
|
*/
|
|
createNodeDatumContext(xAxis, yAxis) {
|
|
const { dataModel, processedData, contextNodeData } = this;
|
|
if (!dataModel || !processedData)
|
|
return void 0;
|
|
const { xKey, xName, yKey, yName, colorKey, colorName, textAlign, verticalAlign, itemPadding } = this.properties;
|
|
const xScale = xAxis.scale;
|
|
const yScale = yAxis.scale;
|
|
const xValues = dataModel.resolveColumnById(this, `xValue`, processedData);
|
|
const yValues = dataModel.resolveColumnById(this, `yValue`, processedData);
|
|
const colorValues = colorKey ? dataModel.resolveColumnById(this, `colorValue`, processedData) : void 0;
|
|
const colorDomain = colorKey ? dataModel.getDomain(this, "colorValue", "value", processedData).domain : [];
|
|
const width = xScale.bandwidth ?? 10;
|
|
const height = yScale.bandwidth ?? 10;
|
|
const rawData = processedData.dataSources.get(this.id)?.data ?? [];
|
|
const canIncrementallyUpdate = contextNodeData?.nodeData != null && processedData.changeDescription != null;
|
|
return {
|
|
// Base context fields
|
|
xAxis,
|
|
yAxis,
|
|
xScale,
|
|
yScale,
|
|
rawData,
|
|
xValues,
|
|
xKey,
|
|
yKey,
|
|
xName,
|
|
yName,
|
|
animationEnabled: !this.ctx.animationManager.isSkipped(),
|
|
canIncrementallyUpdate,
|
|
nodes: canIncrementallyUpdate ? contextNodeData.nodeData : [],
|
|
nodeIndex: 0,
|
|
// Heatmap-specific positioning
|
|
xOffset: (xScale.bandwidth ?? 0) / 2,
|
|
yOffset: (yScale.bandwidth ?? 0) / 2,
|
|
width,
|
|
height,
|
|
textAlignFactor: (width - 2 * itemPadding) * textAlignFactors[textAlign],
|
|
verticalAlignFactor: (height - 2 * itemPadding) * verticalAlignFactors[verticalAlign],
|
|
// Heatmap-specific data
|
|
yValues,
|
|
colorKey,
|
|
colorName,
|
|
colorValues,
|
|
colorDomain,
|
|
itemPadding,
|
|
// Label support - labels are always rebuilt from scratch (not incrementally updated)
|
|
labels: [],
|
|
labelIndex: 0
|
|
};
|
|
}
|
|
/**
|
|
* Creates a skeleton HeatmapNodeDatum with minimal required fields.
|
|
* The node will be populated by updateNodeDatum.
|
|
*/
|
|
createSkeletonNodeDatum(ctx, datumIndex, datum) {
|
|
const { xKey, yKey, width, height, colorValues } = ctx;
|
|
const xDatum = ctx.xValues[datumIndex];
|
|
const yDatum = ctx.yValues[datumIndex];
|
|
const colorValue = colorValues?.[datumIndex];
|
|
return {
|
|
series: this,
|
|
datumIndex,
|
|
yKey,
|
|
xKey,
|
|
xValue: xDatum,
|
|
yValue: yDatum,
|
|
colorValue,
|
|
datum,
|
|
point: { x: 0, y: 0, size: 0 },
|
|
width,
|
|
height,
|
|
midPoint: { x: 0, y: 0 },
|
|
missing: colorValues != null && colorValue == null,
|
|
style: {}
|
|
};
|
|
}
|
|
/**
|
|
* Updates an existing HeatmapNodeDatum in-place.
|
|
*/
|
|
updateNodeDatum(ctx, node, datumIndex, datum) {
|
|
const { xScale, yScale, xOffset, yOffset, width, height, xKey, yKey, colorValues } = ctx;
|
|
const mutableNode = node;
|
|
const xDatum = ctx.xValues[datumIndex];
|
|
const yDatum = ctx.yValues[datumIndex];
|
|
const x = xScale.convert(xDatum) + xOffset;
|
|
const y = yScale.convert(yDatum) + yOffset;
|
|
if (!Number.isFinite(x) || !Number.isFinite(y))
|
|
return;
|
|
const colorValue = colorValues?.[datumIndex];
|
|
mutableNode.datumIndex = datumIndex;
|
|
mutableNode.datum = datum;
|
|
mutableNode.yKey = yKey;
|
|
mutableNode.xKey = xKey;
|
|
mutableNode.xValue = xDatum;
|
|
mutableNode.yValue = yDatum;
|
|
mutableNode.colorValue = colorValue;
|
|
mutableNode.width = width;
|
|
mutableNode.height = height;
|
|
mutableNode.missing = colorValues != null && colorValue == null;
|
|
const mutablePoint = mutableNode.point;
|
|
mutablePoint.x = x;
|
|
mutablePoint.y = y;
|
|
mutablePoint.size = 0;
|
|
mutableNode.midPoint.x = x;
|
|
mutableNode.midPoint.y = y;
|
|
mutableNode.style = this.getItemStyle({ datumIndex, datum, colorValue }, false);
|
|
}
|
|
/**
|
|
* Creates a HeatmapNodeDatum for a single data point.
|
|
* Returns undefined for invalid data points (e.g., null/undefined keys when not allowed).
|
|
*/
|
|
createNodeDatum(ctx, datumIndex, datum) {
|
|
const { xScale, yScale, xOffset, yOffset } = ctx;
|
|
const xDatum = ctx.xValues[datumIndex];
|
|
const yDatum = ctx.yValues[datumIndex];
|
|
const x = xScale.convert(xDatum) + xOffset;
|
|
const y = yScale.convert(yDatum) + yOffset;
|
|
if (!Number.isFinite(x) || !Number.isFinite(y)) {
|
|
return void 0;
|
|
}
|
|
const node = this.createSkeletonNodeDatum(ctx, datumIndex, datum);
|
|
this.updateNodeDatum(ctx, node, datumIndex, datum);
|
|
return node;
|
|
}
|
|
createLabelDatum(ctx, datumIndex, datum, nodeDatum) {
|
|
const { label } = this.properties;
|
|
const {
|
|
width,
|
|
height,
|
|
textAlignFactor,
|
|
verticalAlignFactor,
|
|
itemPadding,
|
|
colorKey,
|
|
colorName,
|
|
colorDomain,
|
|
xKey,
|
|
yKey,
|
|
xName,
|
|
yName
|
|
} = ctx;
|
|
const colorValue = ctx.colorValues?.[datumIndex];
|
|
const labelText = label.enabled && colorValue != null ? this.getLabelText(
|
|
colorValue,
|
|
datum,
|
|
colorKey,
|
|
"color",
|
|
colorDomain,
|
|
label,
|
|
{ value: colorValue, datum, colorKey, colorName, xKey, yKey, xName, yName }
|
|
) : void 0;
|
|
const sizeFittingHeight = () => ({ width, height, meta: null });
|
|
const labels = formatLabels(
|
|
toPlainText3(labelText),
|
|
this.properties.label,
|
|
void 0,
|
|
this.properties.label,
|
|
{ padding: itemPadding },
|
|
sizeFittingHeight
|
|
);
|
|
if (labels?.label == null) {
|
|
return void 0;
|
|
}
|
|
const { text: text2, fontSize, lineHeight, height: labelHeight } = labels.label;
|
|
const { fontStyle, fontFamily, fontWeight, color: color7 } = this.properties.label;
|
|
const { textAlign, verticalAlign } = this.properties;
|
|
const lx = nodeDatum.point.x + textAlignFactor * (width - 2 * itemPadding);
|
|
const ly = nodeDatum.point.y + verticalAlignFactor * (height - 2 * itemPadding) - (labels.height - labelHeight) * 0.5;
|
|
return {
|
|
series: this,
|
|
datum,
|
|
datumIndex,
|
|
text: text2,
|
|
fontSize,
|
|
lineHeight,
|
|
fontStyle,
|
|
fontFamily,
|
|
fontWeight,
|
|
color: color7,
|
|
textAlign,
|
|
textBaseline: verticalAlign,
|
|
x: lx,
|
|
y: ly,
|
|
style: nodeDatum.style
|
|
};
|
|
}
|
|
nodeFactory() {
|
|
return new Rect();
|
|
}
|
|
update(params) {
|
|
this.ctx.animationManager.skipCurrentBatch();
|
|
return super.update(params);
|
|
}
|
|
updateDatumSelection(opts) {
|
|
const { nodeData, datumSelection } = opts;
|
|
const data = nodeData ?? [];
|
|
return datumSelection.update(data);
|
|
}
|
|
getItemStyle({ datumIndex, datum, colorValue }, isHighlight, highlightState) {
|
|
const { properties } = this;
|
|
const { itemStyler, stroke: stroke3, strokeWidth, strokeOpacity } = properties;
|
|
const highlightStyle = this.getHighlightStyle(isHighlight, datumIndex, highlightState);
|
|
const style = mergeDefaults6(highlightStyle, {
|
|
fill: this.isColorScaleValid() && colorValue != null ? this.colorScale.convert(colorValue) : "transparent",
|
|
fillOpacity: 1,
|
|
stroke: stroke3,
|
|
strokeWidth,
|
|
strokeOpacity,
|
|
opacity: 1
|
|
});
|
|
let overrides;
|
|
if (itemStyler != null && datumIndex != null) {
|
|
overrides = this.cachedDatumCallback(createDatumId3(datumIndex, isHighlight ? "highlight" : "node"), () => {
|
|
const params = this.makeItemStylerParams(datum, datumIndex, isHighlight, style);
|
|
return this.callWithContext(itemStyler, params);
|
|
});
|
|
}
|
|
return overrides ? mergeDefaults6(overrides, style) : style;
|
|
}
|
|
makeItemStylerParams(datum, datumIndex, isHighlight, style) {
|
|
const { id: seriesId, properties } = this;
|
|
const { xKey, yKey } = properties;
|
|
const activeHighlight = this.ctx.highlightManager?.getActiveHighlight();
|
|
const highlightState = this.getHighlightStateString(activeHighlight, isHighlight, datumIndex);
|
|
const fill = this.filterItemStylerFillParams(style.fill) ?? style.fill;
|
|
return {
|
|
seriesId,
|
|
datum,
|
|
xKey,
|
|
yKey,
|
|
highlightState,
|
|
...style,
|
|
fill
|
|
};
|
|
}
|
|
updateDatumStyles({
|
|
datumSelection,
|
|
isHighlight
|
|
}) {
|
|
const activeHighlight = this.ctx.highlightManager?.getActiveHighlight();
|
|
datumSelection.each((_, nodeDatum) => {
|
|
const highlightState = this.getHighlightState(activeHighlight, isHighlight, nodeDatum.datumIndex);
|
|
nodeDatum.style = this.getItemStyle(nodeDatum, isHighlight, highlightState);
|
|
});
|
|
}
|
|
updateDatumNodes({
|
|
datumSelection
|
|
}) {
|
|
const xAxis = this.axes[ChartAxisDirection19.X];
|
|
const [visibleMin, visibleMax] = xAxis?.visibleRange ?? [];
|
|
const isZoomed = visibleMin !== 0 || visibleMax !== 1;
|
|
const crisp = !isZoomed;
|
|
datumSelection.each((rect, nodeDatum) => {
|
|
const { point, width, height, style } = nodeDatum;
|
|
rect.setStyleProperties(style);
|
|
rect.crisp = crisp;
|
|
rect.x = Math.floor(point.x - width / 2);
|
|
rect.y = Math.floor(point.y - height / 2);
|
|
rect.width = Math.ceil(width);
|
|
rect.height = Math.ceil(height);
|
|
});
|
|
}
|
|
updateLabelSelection(opts) {
|
|
const { labelData, labelSelection } = opts;
|
|
const { enabled } = this.properties.label;
|
|
const data = enabled ? labelData : [];
|
|
return labelSelection.update(data);
|
|
}
|
|
updateLabelNodes(opts) {
|
|
const { isHighlight = false } = opts;
|
|
const activeHighlight = this.ctx.highlightManager?.getActiveHighlight();
|
|
opts.labelSelection.each((text2, datum) => {
|
|
text2.pointerEvents = PointerEvents.None;
|
|
text2.text = datum.text;
|
|
text2.fillOpacity = this.getHighlightStyle(isHighlight, datum.datumIndex)?.opacity ?? 1;
|
|
updateLabelNode(
|
|
this,
|
|
text2,
|
|
this.properties,
|
|
this.properties.label,
|
|
datum,
|
|
isHighlight,
|
|
activeHighlight
|
|
);
|
|
});
|
|
}
|
|
getTooltipContent(datumIndex) {
|
|
const { id: seriesId, dataModel, processedData, axes, properties, colorScale, ctx } = this;
|
|
const { formatManager } = ctx;
|
|
const { xKey, xName, yKey, yName, colorKey, colorName, colorRange, title, legendItemName, tooltip } = properties;
|
|
const xAxis = axes[ChartAxisDirection19.X];
|
|
const yAxis = axes[ChartAxisDirection19.Y];
|
|
if (!dataModel || !processedData || !xAxis || !yAxis)
|
|
return;
|
|
const datum = processedData.dataSources.get(this.id)?.data[datumIndex];
|
|
const xValue = dataModel.resolveColumnById(this, `xValue`, processedData)[datumIndex];
|
|
const yValue = dataModel.resolveColumnById(this, `yValue`, processedData)[datumIndex];
|
|
const colorValue = colorKey != null && this.isColorScaleValid() ? dataModel.resolveColumnById(this, `colorValue`, processedData)[datumIndex] : void 0;
|
|
const allowNullKeys = this.properties.allowNullKeys ?? false;
|
|
if (xValue === void 0 && !allowNullKeys)
|
|
return;
|
|
const data = [];
|
|
let fill;
|
|
if (colorValue == null) {
|
|
fill = colorRange[0];
|
|
} else {
|
|
fill = colorScale.convert(colorValue);
|
|
const domain = dataModel.getDomain(this, `colorValue`, "value", processedData).domain;
|
|
const content = formatManager.format(this.callWithContext.bind(this), {
|
|
type: "number",
|
|
value: colorValue,
|
|
datum,
|
|
seriesId,
|
|
legendItemName,
|
|
key: colorKey,
|
|
source: "tooltip",
|
|
property: "color",
|
|
domain,
|
|
boundSeries: this.getFormatterContext("color"),
|
|
fractionDigits: void 0,
|
|
visibleDomain: void 0
|
|
});
|
|
data.push({ label: colorName, fallbackLabel: colorKey, value: content ?? formatValue(colorValue) });
|
|
}
|
|
data.push(
|
|
{
|
|
label: xName,
|
|
fallbackLabel: xKey,
|
|
value: this.getAxisValueText(xAxis, "tooltip", xValue, datum, xKey, legendItemName)
|
|
},
|
|
{
|
|
label: yName,
|
|
fallbackLabel: yKey,
|
|
value: this.getAxisValueText(yAxis, "tooltip", yValue, datum, yKey, legendItemName)
|
|
}
|
|
);
|
|
const format = this.getItemStyle({ datumIndex, datum, colorValue }, false);
|
|
if (format.fill != null) {
|
|
fill = format.fill;
|
|
}
|
|
const symbol = fill == null ? void 0 : {
|
|
marker: {
|
|
shape: "square",
|
|
fill,
|
|
fillOpacity: 1,
|
|
stroke: void 0,
|
|
strokeWidth: 0,
|
|
strokeOpacity: 1,
|
|
lineDash: [0],
|
|
lineDashOffset: 0
|
|
}
|
|
};
|
|
return this.formatTooltipWithContext(
|
|
tooltip,
|
|
{ title: title ?? legendItemName, symbol, data },
|
|
{
|
|
seriesId,
|
|
datum,
|
|
title,
|
|
xKey,
|
|
xName,
|
|
yKey,
|
|
yName,
|
|
colorKey,
|
|
colorName,
|
|
...format
|
|
}
|
|
);
|
|
}
|
|
getLegendData(legendType) {
|
|
if (legendType !== "gradient" || !this.isColorScaleValid() || !this.dataModel) {
|
|
return [];
|
|
}
|
|
return [
|
|
{
|
|
legendType: "gradient",
|
|
enabled: this.visible,
|
|
seriesId: this.id,
|
|
series: this.getFormatterContext("color"),
|
|
colorDomain: this.colorScale.domain,
|
|
colorRange: this.colorScale.range
|
|
}
|
|
];
|
|
}
|
|
isLabelEnabled() {
|
|
return this.properties.label.enabled && Boolean(this.properties.colorKey);
|
|
}
|
|
getBandScalePadding() {
|
|
return { inner: 0, outer: 0 };
|
|
}
|
|
computeFocusBounds({ datumIndex }) {
|
|
const datum = this.contextNodeData?.nodeData[datumIndex];
|
|
if (datum === void 0)
|
|
return void 0;
|
|
const { width, height, midPoint } = datum;
|
|
const focusRect = { x: midPoint.x - width / 2, y: midPoint.y - height / 2, width, height };
|
|
return computeBarFocusBounds3(this, focusRect);
|
|
}
|
|
initQuadTree(quadtree) {
|
|
addHitTestersToQuadtree(quadtree, this.datumNodesIter());
|
|
}
|
|
pickNodesExactShape(point) {
|
|
const item = findQuadtreeMatch(this, point);
|
|
return item != null && item.distance <= 0 ? [item.datum] : [];
|
|
}
|
|
pickNodeClosestDatum(point) {
|
|
return findQuadtreeMatch(this, point);
|
|
}
|
|
hasItemStylers() {
|
|
return this.properties.itemStyler != null || this.properties.label.itemStyler != null || this.isColorScaleValid();
|
|
}
|
|
};
|
|
HeatmapSeries.className = "HeatmapSeries";
|
|
HeatmapSeries.type = "heatmap";
|
|
|
|
// packages/ag-charts-enterprise/src/series/heatmap/heatmapSeriesOptionsDef.ts
|
|
import { _ModuleSupport as _ModuleSupport99 } from "ag-charts-community";
|
|
import {
|
|
arrayOf,
|
|
color as color2,
|
|
commonSeriesOptionsDefs as commonSeriesOptionsDefs3,
|
|
constant as constant3,
|
|
required as required3,
|
|
string as string3,
|
|
without
|
|
} from "ag-charts-core";
|
|
var { heatmapSeriesThemeableOptionsDef } = _ModuleSupport99;
|
|
var heatmapSeriesOptionsDef = {
|
|
...without(heatmapSeriesThemeableOptionsDef, ["showInLegend"]),
|
|
...without(commonSeriesOptionsDefs3, ["showInLegend"]),
|
|
type: required3(constant3("heatmap")),
|
|
xKey: required3(string3),
|
|
yKey: required3(string3),
|
|
xKeyAxis: string3,
|
|
yKeyAxis: string3,
|
|
colorKey: string3,
|
|
xName: string3,
|
|
yName: string3,
|
|
colorName: string3,
|
|
colorRange: arrayOf(color2)
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/series/heatmap/heatmapThemes.ts
|
|
import { LABEL_BOXING_DEFAULTS, SAFE_RANGE2_OPERATION } from "ag-charts-core";
|
|
var HEATMAP_SERIES_THEME = {
|
|
series: {
|
|
stroke: {
|
|
$if: [
|
|
{ $eq: [{ $palette: "type" }, "inbuilt"] },
|
|
{ $ref: "chartBackgroundColor" },
|
|
{ $path: ["/0", { $palette: "stroke" }, { $palette: "strokes" }] }
|
|
]
|
|
},
|
|
strokeWidth: { $isUserOption: ["./stroke", 2, void 0] },
|
|
label: {
|
|
...LABEL_BOXING_DEFAULTS,
|
|
enabled: false,
|
|
color: { $ref: "textColor" },
|
|
fontSize: { $ref: "fontSize" },
|
|
fontFamily: { $ref: "fontFamily" },
|
|
fontWeight: { $ref: "fontWeight" },
|
|
wrapping: "on-space",
|
|
overflowStrategy: "ellipsis"
|
|
},
|
|
itemPadding: 3,
|
|
highlight: {
|
|
unhighlightedItem: {
|
|
opacity: 0.6
|
|
}
|
|
}
|
|
},
|
|
gradientLegend: {
|
|
enabled: true
|
|
}
|
|
};
|
|
HEATMAP_SERIES_THEME.series.colorRange = {
|
|
$if: [{ $eq: [{ $palette: "type" }, "inbuilt"] }, { $palette: "divergingColors" }, SAFE_RANGE2_OPERATION]
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/series/heatmap/heatmapModule.ts
|
|
var HeatmapSeriesModule = {
|
|
type: "series",
|
|
name: "heatmap",
|
|
chartType: "cartesian",
|
|
enterprise: true,
|
|
version: VERSION17,
|
|
dependencies: [CartesianChartModule3],
|
|
options: heatmapSeriesOptionsDef,
|
|
defaultAxes: {
|
|
y: { type: CARTESIAN_AXIS_TYPE4.CATEGORY, position: CARTESIAN_POSITION2.LEFT },
|
|
x: { type: CARTESIAN_AXIS_TYPE4.CATEGORY, position: CARTESIAN_POSITION2.BOTTOM }
|
|
},
|
|
axisKeys: { [ChartAxisDirection20.X]: "xKeyAxis", [ChartAxisDirection20.Y]: "yKeyAxis" },
|
|
themeTemplate: HEATMAP_SERIES_THEME,
|
|
create: (ctx) => new HeatmapSeries(ctx)
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/series/ohlc/ohlcModule.ts
|
|
import { CartesianChartModule as CartesianChartModule4, VERSION as VERSION18, _ModuleSupport as _ModuleSupport102 } from "ag-charts-community";
|
|
import {
|
|
CARTESIAN_AXIS_TYPE as CARTESIAN_AXIS_TYPE5,
|
|
CARTESIAN_POSITION as CARTESIAN_POSITION3,
|
|
ChartAxisDirection as ChartAxisDirection21,
|
|
MULTI_SERIES_HIGHLIGHT_STYLE as MULTI_SERIES_HIGHLIGHT_STYLE2
|
|
} from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/series/ohlc/ohlcSeries.ts
|
|
import "ag-charts-community";
|
|
var OhlcSeries = class extends OhlcSeriesBase {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.properties = new OhlcSeriesProperties();
|
|
}
|
|
nodeFactory() {
|
|
const node = new OhlcNode();
|
|
node.lineCap = "square";
|
|
return node;
|
|
}
|
|
updateDatumStyles({
|
|
datumSelection,
|
|
isHighlight
|
|
}) {
|
|
datumSelection.each((_, datum) => {
|
|
datum.style = this.getItemStyle(datum.datumIndex, isHighlight, void 0, datum.itemType);
|
|
});
|
|
}
|
|
updateDatumNodes({
|
|
datumSelection,
|
|
isHighlight
|
|
}) {
|
|
const { contextNodeData, properties } = this;
|
|
if (!contextNodeData) {
|
|
return;
|
|
}
|
|
const highlightedDatum = this.ctx.highlightManager.getActiveHighlight();
|
|
const { up, down } = properties.item;
|
|
const series = this;
|
|
datumSelection.each(function updateOhlcNode(node, datum) {
|
|
const { centerX, width, y, height, yOpen, yClose, crisp } = datum;
|
|
const baseStyle = datum.isRising ? up : down;
|
|
node.setStaticProperties(centerX, width, y, height, yOpen, yClose, crisp);
|
|
const style = datum.style ?? contextNodeData.styles[datum.itemType][series.getHighlightState(highlightedDatum, isHighlight, datum.datumIndex)];
|
|
node.setStyleProperties(style);
|
|
node.strokeAlignment = baseStyle.strokeWidth;
|
|
});
|
|
}
|
|
getLegendData(legendType) {
|
|
const {
|
|
id,
|
|
data,
|
|
ctx: { legendManager },
|
|
visible
|
|
} = this;
|
|
const {
|
|
xKey,
|
|
yName,
|
|
item: { up, down },
|
|
showInLegend,
|
|
legendItemName
|
|
} = this.properties;
|
|
if (!data?.data.length || !xKey || legendType !== "category") {
|
|
return [];
|
|
}
|
|
const fill = {
|
|
type: "gradient",
|
|
gradient: "linear",
|
|
colorSpace: "rgb",
|
|
colorStops: [
|
|
{ color: up.stroke, stop: 0 },
|
|
{ color: up.stroke, stop: 0.5 },
|
|
{ color: down.stroke, stop: 0.5 }
|
|
],
|
|
rotation: 90
|
|
};
|
|
return [
|
|
{
|
|
legendType: "category",
|
|
id,
|
|
itemId: id,
|
|
seriesId: id,
|
|
enabled: visible && legendManager.getItemEnabled({ seriesId: id, itemId: id }),
|
|
label: {
|
|
text: legendItemName ?? yName ?? id
|
|
},
|
|
symbol: {
|
|
marker: {
|
|
fill,
|
|
fillOpacity: up.strokeOpacity,
|
|
stroke: void 0,
|
|
strokeWidth: 0,
|
|
strokeOpacity: 1,
|
|
lineDash: [0],
|
|
lineDashOffset: 0
|
|
}
|
|
},
|
|
legendItemName,
|
|
hideInLegend: !showInLegend
|
|
}
|
|
];
|
|
}
|
|
hasItemStylers() {
|
|
return this.properties.itemStyler != null;
|
|
}
|
|
};
|
|
OhlcSeries.className = "ohlc";
|
|
OhlcSeries.type = "ohlc";
|
|
|
|
// packages/ag-charts-enterprise/src/series/ohlc/ohlcSeriesOptionsDef.ts
|
|
import { _ModuleSupport as _ModuleSupport101 } from "ag-charts-community";
|
|
import {
|
|
boolean as boolean8,
|
|
commonSeriesOptionsDefs as commonSeriesOptionsDefs4,
|
|
constant as constant4,
|
|
number as number2,
|
|
required as required4,
|
|
string as string4,
|
|
undocumented as undocumented5
|
|
} from "ag-charts-core";
|
|
var { ohlcSeriesThemeableOptionsDef } = _ModuleSupport101;
|
|
var ohlcSeriesOptionsDef = {
|
|
...commonSeriesOptionsDefs4,
|
|
...ohlcSeriesThemeableOptionsDef,
|
|
type: required4(constant4("ohlc")),
|
|
xKey: required4(string4),
|
|
openKey: required4(string4),
|
|
highKey: required4(string4),
|
|
lowKey: required4(string4),
|
|
closeKey: required4(string4),
|
|
xKeyAxis: string4,
|
|
yKeyAxis: string4,
|
|
xName: string4,
|
|
yName: string4,
|
|
openName: string4,
|
|
highName: string4,
|
|
lowName: string4,
|
|
closeName: string4
|
|
};
|
|
ohlcSeriesOptionsDef.pickOutsideVisibleMinorAxis = undocumented5(boolean8);
|
|
ohlcSeriesOptionsDef.focusPriority = undocumented5(number2);
|
|
|
|
// packages/ag-charts-enterprise/src/series/ohlc/ohlcModule.ts
|
|
var { predictCartesianFinancialAxis: predictCartesianFinancialAxis2 } = _ModuleSupport102;
|
|
var themeTemplate = {
|
|
animation: { enabled: false },
|
|
series: {
|
|
item: {
|
|
up: {
|
|
stroke: {
|
|
$if: [
|
|
{ $eq: [{ $palette: "type" }, "user-indexed"] },
|
|
{ $palette: "stroke" },
|
|
{ $palette: "up.stroke" }
|
|
]
|
|
}
|
|
},
|
|
down: {
|
|
stroke: {
|
|
$if: [
|
|
{ $eq: [{ $palette: "type" }, "user-indexed"] },
|
|
{ $palette: "stroke" },
|
|
{ $palette: "down.stroke" }
|
|
]
|
|
}
|
|
}
|
|
},
|
|
tooltip: {
|
|
range: { $path: ["/tooltip/range", "nearest"] }
|
|
},
|
|
highlight: MULTI_SERIES_HIGHLIGHT_STYLE2
|
|
},
|
|
axes: {
|
|
[CARTESIAN_AXIS_TYPE5.NUMBER]: {
|
|
crosshair: {
|
|
snap: false
|
|
}
|
|
},
|
|
[CARTESIAN_AXIS_TYPE5.ORDINAL_TIME]: {
|
|
groupPaddingInner: 0,
|
|
crosshair: {
|
|
enabled: true
|
|
}
|
|
}
|
|
}
|
|
};
|
|
var OhlcSeriesModule = {
|
|
type: "series",
|
|
name: "ohlc",
|
|
chartType: "cartesian",
|
|
enterprise: true,
|
|
version: VERSION18,
|
|
dependencies: [CartesianChartModule4],
|
|
options: ohlcSeriesOptionsDef,
|
|
matchingKeys: ["xKey", "lowKey", "highKey", "openKey", "closeKey", "normalizedTo"],
|
|
predictAxis: predictCartesianFinancialAxis2,
|
|
defaultAxes: {
|
|
y: { type: CARTESIAN_AXIS_TYPE5.NUMBER, position: CARTESIAN_POSITION3.LEFT },
|
|
x: { type: CARTESIAN_AXIS_TYPE5.ORDINAL_TIME, position: CARTESIAN_POSITION3.BOTTOM }
|
|
},
|
|
axisKeys: { [ChartAxisDirection21.X]: "xKeyAxis", [ChartAxisDirection21.Y]: "yKeyAxis" },
|
|
themeTemplate,
|
|
create: (ctx) => new OhlcSeries(ctx)
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/series/range-area/rangeAreaModule.ts
|
|
import { CartesianChartModule as CartesianChartModule5, VERSION as VERSION19, _ModuleSupport as _ModuleSupport109 } from "ag-charts-community";
|
|
import {
|
|
CARTESIAN_AXIS_TYPE as CARTESIAN_AXIS_TYPE7,
|
|
CARTESIAN_POSITION as CARTESIAN_POSITION4,
|
|
ChartAxisDirection as ChartAxisDirection23
|
|
} from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/series/range-area/rangeArea.ts
|
|
import {
|
|
_ModuleSupport as _ModuleSupport107
|
|
} from "ag-charts-community";
|
|
import {
|
|
AGGREGATION_INDEX_UNSET,
|
|
AGGREGATION_INDEX_Y_MAX as AGGREGATION_INDEX_Y_MAX2,
|
|
AGGREGATION_INDEX_Y_MIN as AGGREGATION_INDEX_Y_MIN2,
|
|
AGGREGATION_SPAN as AGGREGATION_SPAN2,
|
|
ChartAxisDirection as ChartAxisDirection22,
|
|
DebugMetrics as DebugMetrics2,
|
|
extent as extent2,
|
|
findMinMax as findMinMax2,
|
|
mergeDefaults as mergeDefaults7
|
|
} from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/series/range-area/rangeAreaAggregation.ts
|
|
import "ag-charts-community";
|
|
import {
|
|
aggregationDomain as aggregationDomain2,
|
|
computeExtremesAggregation as computeExtremesAggregation2,
|
|
computeExtremesAggregationPartial as computeExtremesAggregationPartial2,
|
|
simpleMemorize2 as simpleMemorize22
|
|
} from "ag-charts-core";
|
|
function aggregateRangeAreaData(scale, xValues, highValues, lowValues, domainInput, smallestKeyInterval, xNeedsValueOf, yNeedsValueOf) {
|
|
const [d0, d1] = aggregationDomain2(scale, domainInput);
|
|
return computeExtremesAggregation2([d0, d1], xValues, highValues, lowValues, {
|
|
smallestKeyInterval,
|
|
xNeedsValueOf,
|
|
yNeedsValueOf
|
|
});
|
|
}
|
|
var memoizedAggregateRangeAreaData = simpleMemorize22(aggregateRangeAreaData);
|
|
function aggregateRangeAreaDataFromDataModel(scale, dataModel, processedData, series, existingFilters) {
|
|
const xValues = dataModel.resolveKeysById(series, "xValue", processedData);
|
|
const highValues = dataModel.resolveColumnById(series, "yHighValue", processedData);
|
|
const lowValues = dataModel.resolveColumnById(series, "yLowValue", processedData);
|
|
const domainInput = dataModel.getDomain(series, "xValue", "key", processedData);
|
|
const xNeedsValueOf = dataModel.resolveColumnNeedsValueOf(series, "xValue", processedData);
|
|
const yNeedsValueOf = dataModel.resolveColumnNeedsValueOf(series, "yHighValue", processedData) ?? dataModel.resolveColumnNeedsValueOf(series, "yLowValue", processedData);
|
|
if (existingFilters) {
|
|
const [d0, d1] = aggregationDomain2(scale, domainInput);
|
|
return computeExtremesAggregation2([d0, d1], xValues, highValues, lowValues, {
|
|
smallestKeyInterval: processedData.reduced?.smallestKeyInterval,
|
|
xNeedsValueOf,
|
|
yNeedsValueOf,
|
|
existingFilters
|
|
});
|
|
}
|
|
return memoizedAggregateRangeAreaData(
|
|
scale,
|
|
xValues,
|
|
highValues,
|
|
lowValues,
|
|
domainInput,
|
|
processedData.reduced?.smallestKeyInterval,
|
|
xNeedsValueOf,
|
|
yNeedsValueOf
|
|
);
|
|
}
|
|
function aggregateRangeAreaDataFromDataModelPartial(scale, dataModel, processedData, series, targetRange, existingFilters) {
|
|
const xValues = dataModel.resolveKeysById(series, "xValue", processedData);
|
|
const highValues = dataModel.resolveColumnById(series, "yHighValue", processedData);
|
|
const lowValues = dataModel.resolveColumnById(series, "yLowValue", processedData);
|
|
const domainInput = dataModel.getDomain(series, "xValue", "key", processedData);
|
|
const xNeedsValueOf = dataModel.resolveColumnNeedsValueOf(series, "xValue", processedData);
|
|
const yNeedsValueOf = dataModel.resolveColumnNeedsValueOf(series, "yHighValue", processedData) ?? dataModel.resolveColumnNeedsValueOf(series, "yLowValue", processedData);
|
|
const [d0, d1] = aggregationDomain2(scale, domainInput);
|
|
return computeExtremesAggregationPartial2([d0, d1], xValues, highValues, lowValues, {
|
|
smallestKeyInterval: processedData.reduced?.smallestKeyInterval,
|
|
targetRange,
|
|
xNeedsValueOf,
|
|
yNeedsValueOf,
|
|
existingFilters
|
|
});
|
|
}
|
|
|
|
// packages/ag-charts-enterprise/src/series/range-area/rangeAreaIntersection.ts
|
|
import "ag-charts-community";
|
|
import { spanRange } from "ag-charts-core";
|
|
function getYValueAtX({ span }, x) {
|
|
switch (span.type) {
|
|
case "linear":
|
|
case "step":
|
|
case "multi-line": {
|
|
const t = (x - span.x0) / (span.x1 - span.x0);
|
|
return span.y0 + t * (span.y1 - span.y0);
|
|
}
|
|
case "cubic": {
|
|
const { cp0x, cp0y, cp1x, cp1y, cp2x, cp2y, cp3x, cp3y } = span;
|
|
let t = 0.5;
|
|
const tolerance = 1e-6;
|
|
for (let i = 0; i < 10; i++) {
|
|
const mt2 = 1 - t;
|
|
const xt = mt2 * mt2 * mt2 * cp0x + 3 * mt2 * mt2 * t * cp1x + 3 * mt2 * t * t * cp2x + t * t * t * cp3x;
|
|
const fx = xt - x;
|
|
if (Math.abs(fx) < tolerance)
|
|
break;
|
|
const dxdt = 3 * mt2 * mt2 * (cp1x - cp0x) + 6 * mt2 * t * (cp2x - cp1x) + 3 * t * t * (cp3x - cp2x);
|
|
if (Math.abs(dxdt) < 1e-12)
|
|
break;
|
|
t = t - fx / dxdt;
|
|
t = Math.max(0, Math.min(1, t));
|
|
}
|
|
const mt = 1 - t;
|
|
return mt * mt * mt * cp0y + 3 * mt * mt * t * cp1y + 3 * mt * t * t * cp2y + t * t * t * cp3y;
|
|
}
|
|
}
|
|
}
|
|
function findSpanForX(spans, x, startIndex = 0) {
|
|
for (let i = startIndex; i < spans.length; i++) {
|
|
const span = spans[i];
|
|
const [start, end] = spanRange(span.span);
|
|
if (x >= start.x && x <= end.x) {
|
|
return { span, index: i };
|
|
}
|
|
if (x < start.x) {
|
|
break;
|
|
}
|
|
}
|
|
return { span: null, index: startIndex };
|
|
}
|
|
function checkForIntersection(highSpans, lowSpans, x, wasInverted, spanIndex) {
|
|
const high = findSpanForX(highSpans, x, spanIndex);
|
|
const low = findSpanForX(lowSpans, x, spanIndex);
|
|
if (!high.span || !low.span) {
|
|
return { intersection: null, spanIndex: high.index, isInverted: wasInverted };
|
|
}
|
|
const highY = getYValueAtX(high.span, x);
|
|
const lowY = getYValueAtX(low.span, x);
|
|
const isInverted = highY > lowY;
|
|
const intersection = wasInverted === isInverted ? null : { x, y: highY };
|
|
return { intersection, spanIndex: high.index, isInverted };
|
|
}
|
|
function findRangeAreaIntersections(highSpans, lowSpans, minX, maxX, initiallyInverted = false) {
|
|
if (highSpans.length === 0 || lowSpans.length === 0)
|
|
return [];
|
|
const intersections = [];
|
|
let wasInverted = initiallyInverted;
|
|
let spanIndex = 0;
|
|
for (let x = minX; x <= maxX; x += 0.5) {
|
|
const result = checkForIntersection(highSpans, lowSpans, x, wasInverted, spanIndex);
|
|
if (result.intersection) {
|
|
intersections.push(result.intersection.x);
|
|
}
|
|
spanIndex = result.spanIndex;
|
|
wasInverted = result.isInverted;
|
|
}
|
|
return intersections;
|
|
}
|
|
function calculateIntersectionSegments(intersections, seriesRect, chartSize, startsInverted, style = {}) {
|
|
const horizontalMargin = Math.max(seriesRect.x, chartSize.width - (seriesRect.x + seriesRect.width));
|
|
const verticalMargin = Math.max(seriesRect.y, chartSize.height - (seriesRect.y + seriesRect.height));
|
|
const result = [];
|
|
const createClipRect = (x0, x1) => ({
|
|
x0,
|
|
y0: -verticalMargin,
|
|
x1,
|
|
y1: seriesRect.height + verticalMargin
|
|
});
|
|
if (startsInverted) {
|
|
result.push({
|
|
clipRect: createClipRect(-horizontalMargin, intersections[0] ?? seriesRect.width + horizontalMargin),
|
|
...style
|
|
});
|
|
}
|
|
const startIndex = startsInverted ? 1 : 0;
|
|
for (let i = startIndex; i < intersections.length; i += 2) {
|
|
result.push({
|
|
clipRect: createClipRect(intersections[i], intersections[i + 1] ?? seriesRect.width + horizontalMargin),
|
|
...style
|
|
});
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// packages/ag-charts-enterprise/src/series/range-area/rangeAreaProperties.ts
|
|
import { _ModuleSupport as _ModuleSupport105 } from "ag-charts-community";
|
|
import { BaseProperties as BaseProperties22, InterpolationProperties, Property as Property55 } from "ag-charts-core";
|
|
var { CartesianSeriesProperties: CartesianSeriesProperties2, SeriesMarker, makeSeriesTooltip: makeSeriesTooltip5, DropShadow, Label: Label2 } = _ModuleSupport105;
|
|
var RangeAreaSeriesLabel = class extends Label2 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.placement = "outside";
|
|
this.spacing = 0;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property55
|
|
], RangeAreaSeriesLabel.prototype, "placement", 2);
|
|
__decorateClass([
|
|
Property55
|
|
], RangeAreaSeriesLabel.prototype, "spacing", 2);
|
|
var RangeAreaInvertedStyle = class {
|
|
constructor() {
|
|
this.enabled = false;
|
|
this.fillOpacity = 1;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property55
|
|
], RangeAreaInvertedStyle.prototype, "enabled", 2);
|
|
__decorateClass([
|
|
Property55
|
|
], RangeAreaInvertedStyle.prototype, "fill", 2);
|
|
__decorateClass([
|
|
Property55
|
|
], RangeAreaInvertedStyle.prototype, "fillOpacity", 2);
|
|
var RangeAreaLineStyle = class extends BaseProperties22 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.stroke = "#99CCFF";
|
|
this.strokeWidth = 1;
|
|
this.strokeOpacity = 1;
|
|
this.lineDash = [0];
|
|
this.lineDashOffset = 0;
|
|
this.marker = new SeriesMarker();
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property55
|
|
], RangeAreaLineStyle.prototype, "stroke", 2);
|
|
__decorateClass([
|
|
Property55
|
|
], RangeAreaLineStyle.prototype, "strokeWidth", 2);
|
|
__decorateClass([
|
|
Property55
|
|
], RangeAreaLineStyle.prototype, "strokeOpacity", 2);
|
|
__decorateClass([
|
|
Property55
|
|
], RangeAreaLineStyle.prototype, "lineDash", 2);
|
|
__decorateClass([
|
|
Property55
|
|
], RangeAreaLineStyle.prototype, "lineDashOffset", 2);
|
|
__decorateClass([
|
|
Property55
|
|
], RangeAreaLineStyle.prototype, "marker", 2);
|
|
var RangeAreaItemProperties = class extends BaseProperties22 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.low = new RangeAreaLineStyle();
|
|
this.high = new RangeAreaLineStyle();
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property55
|
|
], RangeAreaItemProperties.prototype, "low", 2);
|
|
__decorateClass([
|
|
Property55
|
|
], RangeAreaItemProperties.prototype, "high", 2);
|
|
var SharedRangeAreaMarker = class extends BaseProperties22 {
|
|
};
|
|
__decorateClass([
|
|
Property55
|
|
], SharedRangeAreaMarker.prototype, "enabled", 2);
|
|
__decorateClass([
|
|
Property55
|
|
], SharedRangeAreaMarker.prototype, "shape", 2);
|
|
__decorateClass([
|
|
Property55
|
|
], SharedRangeAreaMarker.prototype, "size", 2);
|
|
__decorateClass([
|
|
Property55
|
|
], SharedRangeAreaMarker.prototype, "fill", 2);
|
|
__decorateClass([
|
|
Property55
|
|
], SharedRangeAreaMarker.prototype, "fillOpacity", 2);
|
|
__decorateClass([
|
|
Property55
|
|
], SharedRangeAreaMarker.prototype, "stroke", 2);
|
|
__decorateClass([
|
|
Property55
|
|
], SharedRangeAreaMarker.prototype, "strokeWidth", 2);
|
|
__decorateClass([
|
|
Property55
|
|
], SharedRangeAreaMarker.prototype, "strokeOpacity", 2);
|
|
__decorateClass([
|
|
Property55
|
|
], SharedRangeAreaMarker.prototype, "lineDash", 2);
|
|
__decorateClass([
|
|
Property55
|
|
], SharedRangeAreaMarker.prototype, "lineDashOffset", 2);
|
|
__decorateClass([
|
|
Property55
|
|
], SharedRangeAreaMarker.prototype, "itemStyler", 2);
|
|
var RangeAreaProperties = class extends CartesianSeriesProperties2 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.fill = "#99CCFF";
|
|
this.fillOpacity = 1;
|
|
this.stroke = "#99CCFF";
|
|
this.strokeWidth = 1;
|
|
this.strokeOpacity = 1;
|
|
this.lineDash = [0];
|
|
this.lineDashOffset = 0;
|
|
this.interpolation = new InterpolationProperties();
|
|
this.item = new RangeAreaItemProperties();
|
|
this.invertedStyle = new RangeAreaInvertedStyle();
|
|
this.shadow = new DropShadow().set({ enabled: false });
|
|
this.marker = new SharedRangeAreaMarker();
|
|
this.label = new RangeAreaSeriesLabel();
|
|
this.tooltip = makeSeriesTooltip5();
|
|
this.connectMissingData = false;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property55
|
|
], RangeAreaProperties.prototype, "xKey", 2);
|
|
__decorateClass([
|
|
Property55
|
|
], RangeAreaProperties.prototype, "yLowKey", 2);
|
|
__decorateClass([
|
|
Property55
|
|
], RangeAreaProperties.prototype, "yHighKey", 2);
|
|
__decorateClass([
|
|
Property55
|
|
], RangeAreaProperties.prototype, "xName", 2);
|
|
__decorateClass([
|
|
Property55
|
|
], RangeAreaProperties.prototype, "yName", 2);
|
|
__decorateClass([
|
|
Property55
|
|
], RangeAreaProperties.prototype, "yLowName", 2);
|
|
__decorateClass([
|
|
Property55
|
|
], RangeAreaProperties.prototype, "yHighName", 2);
|
|
__decorateClass([
|
|
Property55
|
|
], RangeAreaProperties.prototype, "fill", 2);
|
|
__decorateClass([
|
|
Property55
|
|
], RangeAreaProperties.prototype, "fillOpacity", 2);
|
|
__decorateClass([
|
|
Property55
|
|
], RangeAreaProperties.prototype, "stroke", 2);
|
|
__decorateClass([
|
|
Property55
|
|
], RangeAreaProperties.prototype, "strokeWidth", 2);
|
|
__decorateClass([
|
|
Property55
|
|
], RangeAreaProperties.prototype, "strokeOpacity", 2);
|
|
__decorateClass([
|
|
Property55
|
|
], RangeAreaProperties.prototype, "lineDash", 2);
|
|
__decorateClass([
|
|
Property55
|
|
], RangeAreaProperties.prototype, "lineDashOffset", 2);
|
|
__decorateClass([
|
|
Property55
|
|
], RangeAreaProperties.prototype, "interpolation", 2);
|
|
__decorateClass([
|
|
Property55
|
|
], RangeAreaProperties.prototype, "styler", 2);
|
|
__decorateClass([
|
|
Property55
|
|
], RangeAreaProperties.prototype, "item", 2);
|
|
__decorateClass([
|
|
Property55
|
|
], RangeAreaProperties.prototype, "invertedStyle", 2);
|
|
__decorateClass([
|
|
Property55
|
|
], RangeAreaProperties.prototype, "shadow", 2);
|
|
__decorateClass([
|
|
Property55
|
|
], RangeAreaProperties.prototype, "marker", 2);
|
|
__decorateClass([
|
|
Property55
|
|
], RangeAreaProperties.prototype, "label", 2);
|
|
__decorateClass([
|
|
Property55
|
|
], RangeAreaProperties.prototype, "tooltip", 2);
|
|
__decorateClass([
|
|
Property55
|
|
], RangeAreaProperties.prototype, "connectMissingData", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/series/range-area/rangeAreaUtil.ts
|
|
import {
|
|
_ModuleSupport as _ModuleSupport106
|
|
} from "ag-charts-community";
|
|
import { areScalingEqual, isScaleValid } from "ag-charts-core";
|
|
var {
|
|
CollapseMode,
|
|
pairUpSpans,
|
|
prepareAreaFillAnimationFns,
|
|
plotInterpolatedLinePathStroke,
|
|
prepareLinePathPropertyAnimation
|
|
} = _ModuleSupport106;
|
|
function prepareRangeAreaPathStrokeAnimationFns(status, highSpans, lowSpans, visibleToggleMode) {
|
|
const removePhaseFn = (ratio8, path) => {
|
|
plotInterpolatedLinePathStroke(ratio8, path, highSpans.removed);
|
|
plotInterpolatedLinePathStroke(ratio8, path, lowSpans.removed);
|
|
};
|
|
const updatePhaseFn = (ratio8, path) => {
|
|
plotInterpolatedLinePathStroke(ratio8, path, highSpans.moved);
|
|
plotInterpolatedLinePathStroke(ratio8, path, lowSpans.moved);
|
|
};
|
|
const addPhaseFn = (ratio8, path) => {
|
|
plotInterpolatedLinePathStroke(ratio8, path, highSpans.added);
|
|
plotInterpolatedLinePathStroke(ratio8, path, lowSpans.added);
|
|
};
|
|
const pathProperties = prepareLinePathPropertyAnimation(status, visibleToggleMode);
|
|
return { status, path: { addPhaseFn, updatePhaseFn, removePhaseFn }, pathProperties };
|
|
}
|
|
function prepareRangeAreaPathAnimation(newData, oldData, diff8) {
|
|
const isCategoryBased = newData.scales.x?.type === "category";
|
|
const wasCategoryBased = oldData.scales.x?.type === "category";
|
|
if (isCategoryBased !== wasCategoryBased || !isScaleValid(newData.scales.x) || !isScaleValid(oldData.scales.x)) {
|
|
return;
|
|
}
|
|
let status = "updated";
|
|
if (oldData.visible && !newData.visible) {
|
|
status = "removed";
|
|
} else if (!oldData.visible && newData.visible) {
|
|
status = "added";
|
|
}
|
|
const fillSpans = pairUpSpans(
|
|
{ scales: newData.scales, data: newData.fillData.spans },
|
|
{ scales: oldData.scales, data: oldData.fillData.spans },
|
|
CollapseMode.Split
|
|
);
|
|
if (fillSpans == null)
|
|
return;
|
|
const fillPhantomSpans = pairUpSpans(
|
|
{ scales: newData.scales, data: newData.fillData.phantomSpans },
|
|
{ scales: oldData.scales, data: oldData.fillData.phantomSpans },
|
|
CollapseMode.Split
|
|
);
|
|
if (fillPhantomSpans == null)
|
|
return;
|
|
const highStrokeSpans = pairUpSpans(
|
|
{ scales: newData.scales, data: newData.highStrokeData.spans },
|
|
{ scales: oldData.scales, data: oldData.highStrokeData.spans },
|
|
CollapseMode.Split
|
|
);
|
|
if (highStrokeSpans == null)
|
|
return;
|
|
const lowStrokeSpans = pairUpSpans(
|
|
{ scales: newData.scales, data: newData.lowStrokeData.spans },
|
|
{ scales: oldData.scales, data: oldData.lowStrokeData.spans },
|
|
CollapseMode.Split
|
|
);
|
|
if (lowStrokeSpans == null)
|
|
return;
|
|
const fadeMode = "fade";
|
|
const fill = prepareAreaFillAnimationFns(status, fillSpans, fillPhantomSpans, fadeMode);
|
|
const stroke3 = prepareRangeAreaPathStrokeAnimationFns(status, highStrokeSpans, lowStrokeSpans, fadeMode);
|
|
const hasMotion = (diff8?.changed ?? true) || !areScalingEqual(newData.scales.x, oldData.scales.x) || !areScalingEqual(newData.scales.y, oldData.scales.y) || status !== "updated";
|
|
return { status, fill, stroke: stroke3, hasMotion };
|
|
}
|
|
|
|
// packages/ag-charts-enterprise/src/series/range-area/rangeArea.ts
|
|
var HIGH2 = AGGREGATION_INDEX_Y_MAX2;
|
|
var LOW2 = AGGREGATION_INDEX_Y_MIN2;
|
|
var SPAN2 = AGGREGATION_SPAN2;
|
|
var {
|
|
valueProperty: valueProperty6,
|
|
keyProperty: keyProperty4,
|
|
updateLabelNode: updateLabelNode2,
|
|
fixNumericExtent: fixNumericExtent4,
|
|
buildResetPathFn,
|
|
resetLabelFn,
|
|
resetMarkerFn,
|
|
resetMarkerPositionFn,
|
|
pathSwipeInAnimation,
|
|
resetMotion,
|
|
markerSwipeScaleInAnimation,
|
|
seriesLabelFadeInAnimation,
|
|
animationValidation: animationValidation3,
|
|
diff: diff3,
|
|
updateClipPath,
|
|
computeMarkerFocusBounds,
|
|
plotAreaPathFill,
|
|
plotLinePathStroke,
|
|
interpolatePoints,
|
|
pathFadeInAnimation,
|
|
markerFadeInAnimation,
|
|
fromToMotion,
|
|
pathMotion,
|
|
PointerEvents: PointerEvents2,
|
|
Marker,
|
|
BBox: BBox13,
|
|
processedDataIsAnimatable: processedDataIsAnimatable3,
|
|
markerEnabled,
|
|
getMarkerStyles,
|
|
calculateSegments: calculateSegments2,
|
|
toHighlightString: toHighlightString2,
|
|
HighlightState: HighlightState2,
|
|
AggregationManager: AggregationManager2,
|
|
resetMarkerSelectionsDirect,
|
|
createDatumId: createDatumId4,
|
|
visibleRangeIndices: visibleRangeIndices2
|
|
} = _ModuleSupport107;
|
|
var RangeAreaSeriesNodeEvent = class extends _ModuleSupport107.SeriesNodeEvent {
|
|
constructor(type, nativeEvent, datum, series) {
|
|
super(type, nativeEvent, datum, series);
|
|
this.xKey = series.properties.xKey;
|
|
this.yLowKey = series.properties.yLowKey;
|
|
this.yHighKey = series.properties.yHighKey;
|
|
}
|
|
};
|
|
var RangeAreaSeries = class extends _ModuleSupport107.CartesianSeries {
|
|
constructor(moduleCtx) {
|
|
super({
|
|
moduleCtx,
|
|
pathsPerSeries: ["fill", "lowStroke", "highStroke"],
|
|
pickModes: [_ModuleSupport107.SeriesNodePickMode.AXIS_ALIGNED],
|
|
propertyKeys: {
|
|
[ChartAxisDirection22.X]: ["xKey"],
|
|
[ChartAxisDirection22.Y]: ["yLowKey", "yHighKey"]
|
|
},
|
|
propertyNames: {
|
|
[ChartAxisDirection22.X]: ["xName"],
|
|
[ChartAxisDirection22.Y]: ["yLowName", "yHighName", "yName"]
|
|
},
|
|
categoryKey: "xValue",
|
|
animationResetFns: {
|
|
path: buildResetPathFn({ getVisible: () => this.visible, getOpacity: () => this.getOpacity() }),
|
|
label: resetLabelFn,
|
|
datum: (node, datum) => ({ ...resetMarkerFn(node), ...resetMarkerPositionFn(node, datum) })
|
|
},
|
|
clipFocusBox: false
|
|
});
|
|
this.properties = new RangeAreaProperties();
|
|
this.NodeEvent = RangeAreaSeriesNodeEvent;
|
|
this.aggregationManager = new AggregationManager2();
|
|
}
|
|
renderToOffscreenCanvas() {
|
|
const hasMarkers = (this.contextNodeData?.nodeData?.length ?? 0) > 0;
|
|
return hasMarkers && this.getDrawingMode(false) === "cutout" || super.renderToOffscreenCanvas();
|
|
}
|
|
async processData(dataController) {
|
|
const { xKey, yLowKey, yHighKey } = this.properties;
|
|
const xScale = this.axes[ChartAxisDirection22.X]?.scale;
|
|
const yScale = this.axes[ChartAxisDirection22.Y]?.scale;
|
|
const { xScaleType, yScaleType } = this.getScaleInformation({ xScale, yScale });
|
|
const extraProps = [];
|
|
const animationEnabled = !this.ctx.animationManager.isSkipped();
|
|
if (this.needsDataModelDiff() && this.processedData) {
|
|
extraProps.push(diff3(this.id, this.processedData));
|
|
}
|
|
if (animationEnabled) {
|
|
extraProps.push(animationValidation3());
|
|
}
|
|
const allowNullKey = this.properties.allowNullKeys ?? false;
|
|
const { dataModel, processedData } = await this.requestDataModel(dataController, this.data, {
|
|
props: [
|
|
keyProperty4(xKey, xScaleType, { id: `xValue`, allowNullKey }),
|
|
valueProperty6(yLowKey, yScaleType, { id: `yLowValue` }),
|
|
valueProperty6(yHighKey, yScaleType, { id: `yHighValue` }),
|
|
...extraProps
|
|
]
|
|
});
|
|
this.aggregateData(dataModel, processedData);
|
|
this.animationState.transition("updateData");
|
|
}
|
|
aggregateData(dataModel, processedData) {
|
|
this.aggregationManager.markStale(processedData.input.count);
|
|
if (processedData.type !== "ungrouped")
|
|
return;
|
|
if (processedDataIsAnimatable3(processedData))
|
|
return;
|
|
const xAxis = this.axes[ChartAxisDirection22.X];
|
|
if (xAxis == null)
|
|
return;
|
|
const targetRange = this.estimateTargetRange();
|
|
this.aggregationManager.aggregate({
|
|
computePartial: (existingFilters) => aggregateRangeAreaDataFromDataModelPartial(
|
|
xAxis.scale.type,
|
|
dataModel,
|
|
processedData,
|
|
this,
|
|
targetRange,
|
|
existingFilters
|
|
),
|
|
computeFull: (existingFilters) => aggregateRangeAreaDataFromDataModel(xAxis.scale.type, dataModel, processedData, this, existingFilters),
|
|
targetRange
|
|
});
|
|
const filters = this.aggregationManager.filters;
|
|
if (filters && filters.length > 0) {
|
|
DebugMetrics2.record(
|
|
`${this.type}:aggregation`,
|
|
filters.map((f) => f.maxRange)
|
|
);
|
|
}
|
|
}
|
|
estimateTargetRange() {
|
|
const xAxis = this.axes[ChartAxisDirection22.X];
|
|
if (xAxis?.scale?.range) {
|
|
const [r0, r1] = xAxis.scale.range;
|
|
return Math.abs(r1 - r0);
|
|
}
|
|
return this.ctx.scene?.canvas?.width ?? 800;
|
|
}
|
|
/**
|
|
* Creates the context object for efficient node datum creation.
|
|
* Caches expensive-to-compute values that are reused across all datum iterations.
|
|
*/
|
|
createNodeDatumContext(xAxis, yAxis) {
|
|
const { dataModel, processedData } = this;
|
|
if (!dataModel || !processedData)
|
|
return void 0;
|
|
const rawData = processedData.dataSources.get(this.id)?.data ?? [];
|
|
const xScale = xAxis.scale;
|
|
const yScale = yAxis.scale;
|
|
const xAxisRange = xAxis.range;
|
|
const [r0, r1] = xScale.range;
|
|
const range2 = Math.abs(r1 - r0);
|
|
this.aggregationManager.ensureLevelForRange(range2);
|
|
const dataAggregationFilter = this.aggregationManager.getFilterForRange(range2);
|
|
const existingNodes = this.contextNodeData?.nodeData;
|
|
const animationEnabled = !this.ctx.animationManager.isSkipped();
|
|
const canIncrementallyUpdate = existingNodes != null && (processedData.changeDescription != null || !processedDataIsAnimatable3(processedData) || dataAggregationFilter != null);
|
|
return {
|
|
xAxis,
|
|
yAxis,
|
|
rawData,
|
|
xValues: dataModel.resolveKeysById(this, "xValue", processedData),
|
|
yHighValues: dataModel.resolveColumnById(this, "yHighValue", processedData),
|
|
yLowValues: dataModel.resolveColumnById(this, "yLowValue", processedData),
|
|
xScale,
|
|
yScale,
|
|
xAxisRange,
|
|
xOffset: (xScale.bandwidth ?? 0) / 2,
|
|
dataAggregationFilter,
|
|
range: range2,
|
|
labelsEnabled: this.properties.label.enabled,
|
|
animationEnabled,
|
|
canIncrementallyUpdate,
|
|
xKey: this.properties.xKey,
|
|
yLowKey: this.properties.yLowKey,
|
|
yHighKey: this.properties.yHighKey,
|
|
item: this.properties.item,
|
|
yDomain: this.getSeriesDomain(ChartAxisDirection22.Y).domain,
|
|
connectMissingData: this.properties.connectMissingData,
|
|
interpolation: this.properties.interpolation,
|
|
nodes: canIncrementallyUpdate ? existingNodes : [],
|
|
labelData: [],
|
|
spanPoints: [],
|
|
nodeIndex: 0
|
|
};
|
|
}
|
|
xCoordinateRange(xValue) {
|
|
const x = this.axes[ChartAxisDirection22.X].scale.convert(xValue);
|
|
return [x, x];
|
|
}
|
|
yCoordinateRange(yValues) {
|
|
const y = this.axes[ChartAxisDirection22.Y].scale.convert(yValues[0]);
|
|
return [y, y];
|
|
}
|
|
getSeriesDomain(direction) {
|
|
const { processedData, dataModel } = this;
|
|
if (!(processedData && dataModel))
|
|
return { domain: [] };
|
|
const {
|
|
domain: {
|
|
keys: [keys]
|
|
}
|
|
} = processedData;
|
|
if (direction === ChartAxisDirection22.X) {
|
|
const keyDef = dataModel.resolveProcessedDataDefById(this, `xValue`);
|
|
if (keyDef?.def.type === "key" && keyDef.def.valueType === "category") {
|
|
const sortMetadata = dataModel.getKeySortMetadata(this, "xValue", processedData);
|
|
return { domain: keys, sortMetadata };
|
|
}
|
|
return { domain: fixNumericExtent4(extent2(keys)) };
|
|
} else {
|
|
const yExtent = this.domainForClippedRange(ChartAxisDirection22.Y, ["yHighValue", "yLowValue"], "xValue");
|
|
const fixedYExtent = findMinMax2(yExtent);
|
|
return { domain: fixNumericExtent4(fixedYExtent) };
|
|
}
|
|
}
|
|
getSeriesRange(_direction, visibleRange) {
|
|
return this.domainForVisibleRange(ChartAxisDirection22.Y, ["yHighValue", "yLowValue"], "xValue", visibleRange);
|
|
}
|
|
/**
|
|
* Processes a single datum and updates the context's marker, label, and span arrays.
|
|
* Uses the scratch object to avoid per-iteration allocations.
|
|
*
|
|
* @param yHighValueOverride - Optional override for yHighValue, used in aggregation mode
|
|
* when the extreme values come from different data points
|
|
* @param yLowValueOverride - Optional override for yLowValue, used in aggregation mode
|
|
*/
|
|
handleDatumPoint(ctx, scratch, datumIndex, yHighValueOverride, yLowValueOverride) {
|
|
scratch.xValue = ctx.xValues[datumIndex];
|
|
if (scratch.xValue === void 0 && !this.properties.allowNullKeys)
|
|
return;
|
|
scratch.datum = ctx.rawData[datumIndex];
|
|
scratch.yHighValue = yHighValueOverride ?? ctx.yHighValues[datumIndex];
|
|
scratch.yLowValue = yLowValueOverride ?? ctx.yLowValues[datumIndex];
|
|
const currentSpanPoints = ctx.spanPoints.at(-1);
|
|
if (Number.isFinite(scratch.yHighValue) && Number.isFinite(scratch.yLowValue)) {
|
|
scratch.inverted = scratch.yLowValue > scratch.yHighValue;
|
|
scratch.x = ctx.xScale.convert(scratch.xValue) + ctx.xOffset;
|
|
if (!Number.isFinite(scratch.x))
|
|
return;
|
|
scratch.yHighCoordinate = ctx.yScale.convert(scratch.yHighValue);
|
|
scratch.yLowCoordinate = ctx.yScale.convert(scratch.yLowValue);
|
|
this.upsertMarkerDatum(ctx, scratch, datumIndex, "high", scratch.yHighValue, scratch.yHighCoordinate);
|
|
this.upsertMarkerDatum(ctx, scratch, datumIndex, "low", scratch.yLowValue, scratch.yLowCoordinate);
|
|
const spanPoint = {
|
|
high: {
|
|
point: { x: scratch.x, y: scratch.yHighCoordinate },
|
|
xDatum: scratch.xValue,
|
|
yDatum: scratch.yHighValue
|
|
},
|
|
low: {
|
|
point: { x: scratch.x, y: scratch.yLowCoordinate },
|
|
xDatum: scratch.xValue,
|
|
yDatum: scratch.yLowValue
|
|
}
|
|
};
|
|
if (Array.isArray(currentSpanPoints)) {
|
|
currentSpanPoints.push(spanPoint);
|
|
} else if (currentSpanPoints == null) {
|
|
ctx.spanPoints.push([spanPoint]);
|
|
} else {
|
|
currentSpanPoints.skip += 1;
|
|
ctx.spanPoints.push([spanPoint]);
|
|
}
|
|
} else if (!ctx.connectMissingData) {
|
|
if (Array.isArray(currentSpanPoints) || currentSpanPoints == null) {
|
|
ctx.spanPoints.push({ skip: 0 });
|
|
} else {
|
|
currentSpanPoints.skip += 1;
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* Creates or updates marker datum for a single boundary (high or low).
|
|
* Supports incremental updates by reusing existing marker data objects when possible.
|
|
*/
|
|
upsertMarkerDatum(ctx, scratch, datumIndex, itemType, yValue, y) {
|
|
const { size } = ctx.item[itemType].marker;
|
|
const canReuseNode = ctx.canIncrementallyUpdate && ctx.nodeIndex < ctx.nodes.length;
|
|
if (canReuseNode) {
|
|
const existingNode = ctx.nodes[ctx.nodeIndex];
|
|
existingNode.index = datumIndex;
|
|
existingNode.itemType = itemType;
|
|
existingNode.datum = scratch.datum;
|
|
existingNode.datumIndex = datumIndex;
|
|
existingNode.midPoint = { x: scratch.x, y };
|
|
existingNode.yHighValue = scratch.yHighValue;
|
|
existingNode.yLowValue = scratch.yLowValue;
|
|
existingNode.xValue = scratch.xValue;
|
|
existingNode.point = { x: scratch.x, y, size };
|
|
} else {
|
|
ctx.nodes.push({
|
|
index: datumIndex,
|
|
series: this,
|
|
itemType,
|
|
datum: scratch.datum,
|
|
datumIndex,
|
|
midPoint: { x: scratch.x, y },
|
|
yHighValue: scratch.yHighValue,
|
|
yLowValue: scratch.yLowValue,
|
|
xValue: scratch.xValue,
|
|
xKey: ctx.xKey,
|
|
yLowKey: ctx.yLowKey,
|
|
yHighKey: ctx.yHighKey,
|
|
point: { x: scratch.x, y, size },
|
|
enabled: true
|
|
});
|
|
}
|
|
ctx.nodeIndex++;
|
|
if (ctx.labelsEnabled) {
|
|
const labelDatum = this.createLabelData({
|
|
datumIndex,
|
|
point: { x: scratch.x, y },
|
|
value: yValue,
|
|
yLowValue: scratch.yLowValue,
|
|
yHighValue: scratch.yHighValue,
|
|
itemType,
|
|
inverted: scratch.inverted,
|
|
datum: scratch.datum,
|
|
series: this
|
|
});
|
|
ctx.labelData.push(labelDatum);
|
|
}
|
|
}
|
|
populateNodeData(ctx) {
|
|
const { processedData } = this;
|
|
if (!processedData)
|
|
return;
|
|
const scratch = {
|
|
datum: void 0,
|
|
xValue: void 0,
|
|
yHighValue: 0,
|
|
yLowValue: 0,
|
|
x: 0,
|
|
yHighCoordinate: 0,
|
|
yLowCoordinate: 0,
|
|
inverted: false
|
|
};
|
|
const xPosition = (index) => ctx.xScale.convert(ctx.xValues[index]) + ctx.xOffset;
|
|
if (processedData.input.count < 1e3 || ctx.dataAggregationFilter == null) {
|
|
let [start, end] = visibleRangeIndices2(1, ctx.xValues.length, ctx.xAxisRange, (index) => {
|
|
const x = xPosition(index);
|
|
return [x, x];
|
|
});
|
|
if (processedData.input.count < 1e3) {
|
|
start = 0;
|
|
end = processedData.input.count;
|
|
}
|
|
start = Math.max(start - 1, 0);
|
|
end = Math.min(end + 1, ctx.xValues.length);
|
|
for (let datumIndex = start; datumIndex < end; datumIndex += 1) {
|
|
this.handleDatumPoint(ctx, scratch, datumIndex);
|
|
}
|
|
} else {
|
|
const { maxRange, indexData, midpointIndices } = ctx.dataAggregationFilter;
|
|
const [start, end] = visibleRangeIndices2(1, maxRange, ctx.xAxisRange, (index) => {
|
|
const midDatumIndex = midpointIndices[index];
|
|
if (midDatumIndex === AGGREGATION_INDEX_UNSET)
|
|
return;
|
|
return [xPosition(midDatumIndex), xPosition(midDatumIndex)];
|
|
});
|
|
for (let bucketIndex = start; bucketIndex < end; bucketIndex += 1) {
|
|
const midIndex = midpointIndices[bucketIndex];
|
|
if (midIndex === AGGREGATION_INDEX_UNSET)
|
|
continue;
|
|
const aggIndex = bucketIndex * SPAN2;
|
|
const yHighDatumIndex = indexData[aggIndex + HIGH2];
|
|
const yLowDatumIndex = indexData[aggIndex + LOW2];
|
|
this.handleDatumPoint(
|
|
ctx,
|
|
scratch,
|
|
yHighDatumIndex,
|
|
ctx.yHighValues[yHighDatumIndex],
|
|
ctx.yLowValues[yLowDatumIndex]
|
|
);
|
|
}
|
|
}
|
|
}
|
|
finalizeNodeData(ctx) {
|
|
if (ctx.canIncrementallyUpdate && ctx.nodeIndex < ctx.nodes.length) {
|
|
ctx.nodes.length = ctx.nodeIndex;
|
|
}
|
|
}
|
|
initializeResult(ctx) {
|
|
return {
|
|
itemId: `${ctx.yLowKey}-${ctx.yHighKey}`,
|
|
labelData: ctx.labelData,
|
|
nodeData: ctx.nodes,
|
|
fillData: { itemType: "high", spans: [], phantomSpans: [] },
|
|
highStrokeData: { itemType: "high", spans: [] },
|
|
lowStrokeData: { itemType: "low", spans: [] },
|
|
scales: this.calculateScaling(),
|
|
visible: this.visible,
|
|
styles: {
|
|
low: this.getLowOrHighMarkerStyles("low"),
|
|
high: this.getLowOrHighMarkerStyles("high")
|
|
},
|
|
segments: void 0,
|
|
intersectionSegments: void 0
|
|
};
|
|
}
|
|
assembleResult(ctx, result) {
|
|
const xAxis = this.axes[ChartAxisDirection22.X];
|
|
const yAxis = this.axes[ChartAxisDirection22.Y];
|
|
if (!xAxis || !yAxis || !this.chart?.seriesRect)
|
|
return result;
|
|
const highSpans = ctx.spanPoints.flatMap((p) => {
|
|
if (!Array.isArray(p))
|
|
return [];
|
|
const highPoints = p.map((d) => d.high);
|
|
return interpolatePoints(highPoints, ctx.interpolation);
|
|
});
|
|
const lowSpans = ctx.spanPoints.flatMap((p) => {
|
|
if (!Array.isArray(p))
|
|
return [];
|
|
const lowPoints = p.map((d) => d.low);
|
|
return interpolatePoints(lowPoints, ctx.interpolation);
|
|
});
|
|
const segments = calculateSegments2(
|
|
this.properties.segmentation,
|
|
xAxis,
|
|
yAxis,
|
|
this.chart.seriesRect,
|
|
this.ctx.scene,
|
|
false
|
|
);
|
|
let intersectionSegments = void 0;
|
|
if (this.properties.invertedStyle.enabled) {
|
|
const startsInverted = ctx.yHighValues[0] < ctx.yLowValues[0];
|
|
const intersectionXValues = findRangeAreaIntersections(
|
|
highSpans,
|
|
lowSpans,
|
|
ctx.xScale.range[0],
|
|
ctx.xScale.range[1],
|
|
startsInverted
|
|
);
|
|
intersectionSegments = calculateIntersectionSegments(
|
|
intersectionXValues,
|
|
this.chart.seriesRect,
|
|
this.ctx.scene,
|
|
startsInverted,
|
|
this.properties.invertedStyle
|
|
);
|
|
}
|
|
result.fillData = { itemType: "high", spans: highSpans, phantomSpans: lowSpans };
|
|
result.highStrokeData = { itemType: "high", spans: highSpans };
|
|
result.lowStrokeData = { itemType: "low", spans: lowSpans };
|
|
result.segments = segments;
|
|
result.intersectionSegments = intersectionSegments;
|
|
return result;
|
|
}
|
|
getLowOrHighMarkerStyles(lowOrHigh) {
|
|
const { fill, fillOpacity, item } = this.properties;
|
|
const line = item[lowOrHigh];
|
|
const { stroke: stroke3, strokeWidth, strokeOpacity } = line;
|
|
const inheritedStyles = { fill, fillOpacity, stroke: stroke3, strokeWidth, strokeOpacity };
|
|
return getMarkerStyles(this, line, line.marker, inheritedStyles);
|
|
}
|
|
createLabelData({
|
|
datumIndex,
|
|
point,
|
|
value,
|
|
itemType,
|
|
inverted,
|
|
datum,
|
|
series
|
|
}) {
|
|
const { xKey, yLowKey, yHighKey, xName, yName, yLowName, yHighName, legendItemName, label } = this.properties;
|
|
const { placement } = label;
|
|
const spacing = label.spacing + (typeof label.padding === "number" ? label.padding : 0);
|
|
let actualItemId = itemType;
|
|
if (inverted) {
|
|
actualItemId = itemType === "low" ? "high" : "low";
|
|
}
|
|
const direction = placement === "outside" && actualItemId === "high" || placement === "inside" && actualItemId === "low" ? -1 : 1;
|
|
const yDomain = this.getSeriesDomain(ChartAxisDirection22.Y).domain;
|
|
return {
|
|
x: point.x,
|
|
y: point.y + spacing * direction,
|
|
series,
|
|
itemType,
|
|
datum,
|
|
datumIndex,
|
|
text: this.getLabelText(
|
|
value,
|
|
datum,
|
|
itemType === "high" ? yHighKey : yLowKey,
|
|
"y",
|
|
yDomain,
|
|
label,
|
|
{ value, datum, itemType, xKey, yLowKey, yHighKey, xName, yLowName, yHighName, yName, legendItemName }
|
|
),
|
|
textAlign: "center",
|
|
textBaseline: direction === -1 ? "bottom" : "top"
|
|
};
|
|
}
|
|
isPathOrSelectionDirty() {
|
|
const { low, high } = this.properties.item;
|
|
return low.marker.isDirty() || high.marker.isDirty();
|
|
}
|
|
strokewidthChange() {
|
|
const itemStrokeWidthChange = (lowOrHigh) => {
|
|
const unhighlightedStrokeWidth = this.properties.item[lowOrHigh].strokeWidth ?? 0;
|
|
const highlightedSeriesStrokeWidth = this.properties.highlight.highlightedSeries.item?.[lowOrHigh]?.strokeWidth ?? unhighlightedStrokeWidth;
|
|
const highlightedItemStrokeWidth = this.properties.highlight.highlightedItem.item?.[lowOrHigh]?.strokeWidth ?? unhighlightedStrokeWidth;
|
|
return unhighlightedStrokeWidth > highlightedItemStrokeWidth || highlightedSeriesStrokeWidth > highlightedItemStrokeWidth;
|
|
};
|
|
return itemStrokeWidthChange("low") || itemStrokeWidthChange("high");
|
|
}
|
|
updatePathNodes(opts) {
|
|
const { visible } = opts;
|
|
const [fillPath, lowStrokePath, highStrokePath] = opts.paths;
|
|
const segments = this.contextNodeData?.segments;
|
|
const highlightDatum = this.ctx.highlightManager?.getActiveHighlight();
|
|
const highlightState = this.getHighlightState(highlightDatum, false);
|
|
const highlightStyle = this.getHighlightStyle();
|
|
const { item, fill, fillOpacity, opacity } = mergeDefaults7(highlightStyle, this.getStyle(highlightState));
|
|
lowStrokePath.setProperties({
|
|
datum: segments,
|
|
segments,
|
|
fill: void 0,
|
|
lineCap: "round",
|
|
lineJoin: "round",
|
|
pointerEvents: PointerEvents2.None,
|
|
stroke: item.low.stroke,
|
|
strokeWidth: item.low.strokeWidth,
|
|
strokeOpacity: item.low.strokeOpacity,
|
|
lineDash: item.low.lineDash,
|
|
lineDashOffset: item.low.lineDashOffset,
|
|
opacity,
|
|
visible
|
|
});
|
|
highStrokePath.setProperties({
|
|
segments,
|
|
fill: void 0,
|
|
lineCap: "round",
|
|
lineJoin: "round",
|
|
pointerEvents: PointerEvents2.None,
|
|
stroke: item.high.stroke,
|
|
strokeWidth: item.high.strokeWidth,
|
|
strokeOpacity: item.high.strokeOpacity,
|
|
lineDash: item.high.lineDash,
|
|
lineDashOffset: item.high.lineDashOffset,
|
|
opacity,
|
|
visible
|
|
});
|
|
const fillBBox = this.getShapeFillBBox();
|
|
fillPath.setFillProperties(fill, fillBBox);
|
|
fillPath.setStyleProperties({ stroke: void 0, fill, fillOpacity, opacity }, fillBBox);
|
|
const fillSegments = this.contextNodeData?.intersectionSegments ?? segments;
|
|
fillPath.setProperties({
|
|
segments: fillSegments,
|
|
pointerEvents: PointerEvents2.None,
|
|
lineJoin: "round",
|
|
fillShadow: this.properties.shadow,
|
|
opacity,
|
|
visible
|
|
});
|
|
fillPath.datum = fillSegments;
|
|
updateClipPath(this, fillPath);
|
|
updateClipPath(this, lowStrokePath);
|
|
updateClipPath(this, highStrokePath);
|
|
}
|
|
updatePaths(opts) {
|
|
this.updateAreaPaths(opts.paths, opts.contextData);
|
|
}
|
|
updateAreaPaths(paths, contextData) {
|
|
for (const path of paths) {
|
|
path.visible = contextData.visible;
|
|
}
|
|
if (contextData.visible) {
|
|
this.updateFillPath(paths, contextData);
|
|
this.updateStrokePath(paths, contextData);
|
|
} else {
|
|
for (const path of paths) {
|
|
path.path.clear();
|
|
path.markDirty("RangeArea");
|
|
}
|
|
}
|
|
}
|
|
updateFillPath(paths, contextData) {
|
|
const [fill] = paths;
|
|
fill.path.clear();
|
|
plotAreaPathFill(fill, contextData.fillData);
|
|
fill.markDirty("RangeArea");
|
|
}
|
|
updateStrokePath(paths, contextData) {
|
|
const [, lowStroke, highStroke] = paths;
|
|
lowStroke.path.clear();
|
|
highStroke.path.clear();
|
|
plotLinePathStroke(lowStroke, contextData.lowStrokeData.spans);
|
|
plotLinePathStroke(highStroke, contextData.highStrokeData.spans);
|
|
lowStroke.markDirty("RangeArea");
|
|
highStroke.markDirty("RangeArea");
|
|
}
|
|
resetDatumAnimation(data) {
|
|
resetMarkerSelectionsDirect([data.datumSelection]);
|
|
}
|
|
updateDatumSelection(opts) {
|
|
const { nodeData, datumSelection } = opts;
|
|
const { processedData, axes, properties } = this;
|
|
const rules = properties.styler ? this.getStylerMarkerOptions().item : properties.item;
|
|
const { low, high } = rules;
|
|
const markersEnabled = markerEnabled(processedData.input.count, axes[ChartAxisDirection22.X].scale, {
|
|
enabled: low.marker.enabled || high.marker.enabled
|
|
});
|
|
if (properties.item.low.marker.isDirty() || properties.item.high.marker.isDirty()) {
|
|
datumSelection.clear();
|
|
datumSelection.cleanup();
|
|
}
|
|
let resolvedNodeData;
|
|
if (markersEnabled) {
|
|
if (low.marker.enabled && high.marker.enabled) {
|
|
resolvedNodeData = nodeData;
|
|
} else {
|
|
resolvedNodeData = [];
|
|
for (const datum of nodeData) {
|
|
if (rules[datum.itemType].marker.enabled) {
|
|
resolvedNodeData.push(datum);
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
resolvedNodeData = [];
|
|
}
|
|
if (!processedDataIsAnimatable3(this.processedData)) {
|
|
return datumSelection.update(resolvedNodeData);
|
|
}
|
|
return datumSelection.update(
|
|
resolvedNodeData,
|
|
void 0,
|
|
(datum) => createDatumId4(datum.xValue, datum.itemType)
|
|
);
|
|
}
|
|
updateDatumStyles({
|
|
datumSelection,
|
|
isHighlight
|
|
}) {
|
|
const highlightedDatum = this.ctx.highlightManager.getActiveHighlight();
|
|
datumSelection.each((_, datum) => {
|
|
const highlightState = this.getHighlightState(highlightedDatum, isHighlight, datum.datumIndex);
|
|
const stylerStyle = this.getStyle(highlightState);
|
|
const { fill, fillOpacity, item } = stylerStyle;
|
|
const { stroke: stroke3, strokeWidth, strokeOpacity } = item[datum.itemType];
|
|
const { marker } = this.properties.item[datum.itemType];
|
|
const params = this.makeItemStylerParams(datum.itemType);
|
|
datum.style = this.getMarkerStyle(
|
|
marker,
|
|
datum,
|
|
params,
|
|
{ isHighlight, highlightState, resolveMarkerSubPath: ["item", datum.itemType, "marker"] },
|
|
stylerStyle.item[datum.itemType].marker,
|
|
{
|
|
fill,
|
|
fillOpacity,
|
|
stroke: stroke3,
|
|
strokeWidth,
|
|
strokeOpacity
|
|
}
|
|
);
|
|
});
|
|
}
|
|
updateDatumNodes(opts) {
|
|
const { contextNodeData } = this;
|
|
if (!contextNodeData) {
|
|
return;
|
|
}
|
|
const { datumSelection, isHighlight } = opts;
|
|
const fillBBox = this.getShapeFillBBox();
|
|
const highlightedDatum = this.ctx.highlightManager.getActiveHighlight();
|
|
const drawingMode = this.getDrawingMode(isHighlight, opts.drawingMode);
|
|
datumSelection.each((node, datum) => {
|
|
const { itemType } = datum;
|
|
const style = datum.style ?? contextNodeData.styles[itemType][this.getHighlightState(highlightedDatum, isHighlight, datum.datumIndex)];
|
|
this.applyMarkerStyle(style, node, datum.point, fillBBox);
|
|
node.drawingMode = drawingMode;
|
|
});
|
|
if (!isHighlight) {
|
|
this.properties.item.low.marker.markClean();
|
|
this.properties.item.high.marker.markClean();
|
|
}
|
|
}
|
|
updateLabelSelection(opts) {
|
|
const { labelData, labelSelection } = opts;
|
|
return labelSelection.update(labelData, (text2) => {
|
|
text2.pointerEvents = PointerEvents2.None;
|
|
});
|
|
}
|
|
updateLabelNodes(opts) {
|
|
const params = {
|
|
xKey: this.properties.xKey,
|
|
xName: this.properties.xName ?? this.properties.xKey,
|
|
yName: this.properties.yName,
|
|
yLowKey: this.properties.yLowKey,
|
|
yLowName: this.properties.yLowName ?? this.properties.yLowKey,
|
|
yHighKey: this.properties.yHighKey,
|
|
yHighName: this.properties.yHighName ?? this.properties.yHighKey,
|
|
legendItemName: this.properties.legendItemName
|
|
};
|
|
const activeHighlight = this.ctx.highlightManager?.getActiveHighlight();
|
|
const { isHighlight = false, labelSelection } = opts;
|
|
labelSelection.each((textNode, datum) => {
|
|
textNode.fillOpacity = this.getHighlightStyle(isHighlight, datum.datumIndex).opacity ?? 1;
|
|
updateLabelNode2(this, textNode, params, this.properties.label, datum, isHighlight, activeHighlight);
|
|
});
|
|
}
|
|
getHighlightLabelData(labelData, highlightedItem) {
|
|
if (!labelData?.length)
|
|
return [];
|
|
return labelData.filter((labelDatum) => labelDatum.datum === highlightedItem.datum);
|
|
}
|
|
getHighlightData(nodeData, highlightedItem) {
|
|
const highlightItems = nodeData.filter((nodeDatum) => nodeDatum.datum === highlightedItem.datum).map((nodeDatum) => ({ ...nodeDatum }));
|
|
return highlightItems.length > 0 ? highlightItems : void 0;
|
|
}
|
|
getStyle(highlightState) {
|
|
return this.getStylerCouple(highlightState)[0];
|
|
}
|
|
getStylerMarkerOptions() {
|
|
return this.getStylerCouple()[1];
|
|
}
|
|
getStylerCouple(highlightState) {
|
|
const { fill, fillOpacity, item, styler } = this.properties;
|
|
let stylerResult = {};
|
|
if (styler) {
|
|
const stylerParams = this.makeStylerParams(highlightState);
|
|
stylerResult = this.ctx.optionsGraphService.resolvePartial(
|
|
["series", `${this.declarationOrder}`],
|
|
this.cachedCallWithContext(styler, stylerParams) ?? {},
|
|
{ pick: false }
|
|
) ?? {};
|
|
}
|
|
const markerOpts = {
|
|
item: { low: { marker: { enabled: false } }, high: { marker: { enabled: false } } }
|
|
};
|
|
const makeItemResult = (lowOrHigh) => {
|
|
const stylerItem = stylerResult.item?.[lowOrHigh];
|
|
const { lineDash, lineDashOffset, marker, stroke: stroke3, strokeOpacity, strokeWidth } = item[lowOrHigh];
|
|
markerOpts.item[lowOrHigh].marker.enabled = stylerItem?.marker?.enabled ?? marker.enabled;
|
|
return {
|
|
marker: {
|
|
fill: stylerItem?.marker?.fill ?? marker.fill ?? fill,
|
|
fillOpacity: stylerItem?.marker?.fillOpacity ?? marker.fillOpacity,
|
|
shape: stylerItem?.marker?.shape ?? marker.shape,
|
|
size: stylerItem?.marker?.size ?? marker.size,
|
|
lineDash: stylerItem?.marker?.lineDash ?? marker.lineDash,
|
|
lineDashOffset: stylerItem?.marker?.lineDashOffset ?? marker.lineDashOffset,
|
|
stroke: stylerItem?.marker?.stroke ?? marker.stroke ?? stroke3,
|
|
strokeOpacity: stylerItem?.marker?.strokeOpacity ?? marker.strokeOpacity,
|
|
strokeWidth: stylerItem?.marker?.strokeWidth ?? marker.strokeWidth
|
|
},
|
|
lineDash: stylerItem?.lineDash ?? lineDash,
|
|
lineDashOffset: stylerItem?.lineDashOffset ?? lineDashOffset,
|
|
stroke: stylerItem?.stroke ?? stroke3,
|
|
strokeOpacity: stylerItem?.strokeOpacity ?? strokeOpacity,
|
|
strokeWidth: stylerItem?.strokeWidth ?? strokeWidth
|
|
};
|
|
};
|
|
const style = {
|
|
fill: stylerResult.fill ?? fill,
|
|
fillOpacity: stylerResult.fillOpacity ?? fillOpacity,
|
|
opacity: 1,
|
|
topLevel: {
|
|
lineDash: this.properties.lineDash,
|
|
lineDashOffset: this.properties.lineDashOffset,
|
|
marker: this.properties.marker,
|
|
stroke: this.properties.stroke,
|
|
strokeOpacity: this.properties.strokeOpacity,
|
|
strokeWidth: this.properties.strokeWidth
|
|
},
|
|
item: {
|
|
low: makeItemResult("low"),
|
|
high: makeItemResult("high")
|
|
}
|
|
};
|
|
return [style, markerOpts];
|
|
}
|
|
makeStylerParams(highlightStateEnum) {
|
|
const { id: seriesId } = this;
|
|
const { fill, fillOpacity, item, xKey, yHighKey, yLowKey } = this.properties;
|
|
const highlightState = toHighlightString2(highlightStateEnum ?? HighlightState2.None);
|
|
const makeItemParam = (lowOrHigh) => {
|
|
const { lineDash, lineDashOffset, marker, stroke: stroke3, strokeOpacity, strokeWidth } = item[lowOrHigh];
|
|
return {
|
|
marker: {
|
|
fill: marker.fill ?? fill,
|
|
fillOpacity: marker.fillOpacity,
|
|
size: marker.size,
|
|
shape: marker.shape,
|
|
stroke: marker.stroke ?? stroke3,
|
|
strokeOpacity: marker.strokeOpacity,
|
|
strokeWidth: marker.strokeWidth,
|
|
lineDash: marker.lineDash,
|
|
lineDashOffset: marker.lineDashOffset
|
|
},
|
|
lineDash,
|
|
lineDashOffset,
|
|
stroke: stroke3,
|
|
strokeOpacity,
|
|
strokeWidth
|
|
};
|
|
};
|
|
return {
|
|
item: {
|
|
low: makeItemParam("low"),
|
|
high: makeItemParam("high")
|
|
},
|
|
fill,
|
|
fillOpacity,
|
|
highlightState,
|
|
seriesId,
|
|
xKey,
|
|
yLowKey,
|
|
yHighKey
|
|
};
|
|
}
|
|
makeItemStylerParams(itemType) {
|
|
const { xKey, yLowKey, yHighKey } = this.properties;
|
|
return { xKey, yLowKey, yHighKey, itemType };
|
|
}
|
|
getTooltipContent(datumIndex, removeThisDatum) {
|
|
const itemType = removeThisDatum?.itemType ?? "high";
|
|
const { id: seriesId, dataModel, processedData, axes, properties } = this;
|
|
const { xName, yName, yLowKey, yLowName, xKey, yHighKey, yHighName, tooltip, legendItemName } = properties;
|
|
const xAxis = axes[ChartAxisDirection22.X];
|
|
const yAxis = axes[ChartAxisDirection22.Y];
|
|
if (!dataModel || !processedData || !xAxis || !yAxis)
|
|
return;
|
|
const datum = processedData.dataSources.get(this.id)?.data[datumIndex];
|
|
const xValue = dataModel.resolveKeysById(this, `xValue`, processedData)[datumIndex];
|
|
const yHighValue = dataModel.resolveColumnById(this, `yHighValue`, processedData)[datumIndex];
|
|
const yLowValue = dataModel.resolveColumnById(this, `yLowValue`, processedData)[datumIndex];
|
|
const allowNullKeys = this.properties.allowNullKeys ?? false;
|
|
if (xValue === void 0 && !allowNullKeys)
|
|
return;
|
|
const stylerStyle = this.getStyle();
|
|
const params = this.makeItemStylerParams(itemType);
|
|
const format = this.getMarkerStyle(
|
|
this.properties.item[itemType].marker,
|
|
{ datumIndex, datum },
|
|
params,
|
|
{ isHighlight: false, resolveMarkerSubPath: ["item", itemType, "marker"] },
|
|
stylerStyle.item[itemType].marker
|
|
);
|
|
const value = `${this.getAxisValueText(yAxis, "tooltip", yLowValue, datum, yLowKey, legendItemName)} - ${this.getAxisValueText(yAxis, "tooltip", yHighValue, datum, yHighKey, legendItemName)}`;
|
|
return this.formatTooltipWithContext(
|
|
tooltip,
|
|
{
|
|
heading: this.getAxisValueText(xAxis, "tooltip", xValue, datum, xKey, legendItemName),
|
|
symbol: this.legendItemSymbol(),
|
|
data: [
|
|
{
|
|
label: yName,
|
|
fallbackLabel: `${yLowName ?? yLowKey} - ${yHighName ?? yHighKey}`,
|
|
value,
|
|
missing: _ModuleSupport107.isTooltipValueMissing(yHighValue) && _ModuleSupport107.isTooltipValueMissing(yLowValue)
|
|
}
|
|
]
|
|
},
|
|
{
|
|
seriesId,
|
|
datum,
|
|
title: yName,
|
|
itemType,
|
|
xName,
|
|
yName,
|
|
yLowKey,
|
|
yLowName,
|
|
xKey,
|
|
yHighKey,
|
|
yHighName,
|
|
legendItemName,
|
|
...format
|
|
}
|
|
);
|
|
}
|
|
legendItemSymbol() {
|
|
const { fill, topLevel } = this.getStyle();
|
|
const { stroke: stroke3, strokeWidth, strokeOpacity, lineDash, marker } = topLevel;
|
|
const markerStyle = {
|
|
shape: marker.shape,
|
|
fill: marker.fill ?? fill,
|
|
stroke: marker.stroke ?? stroke3,
|
|
fillOpacity: marker.fillOpacity,
|
|
strokeOpacity: marker.strokeOpacity,
|
|
strokeWidth: marker.strokeWidth,
|
|
lineDash: marker.lineDash,
|
|
lineDashOffset: marker.lineDashOffset
|
|
};
|
|
return {
|
|
marker: markerStyle,
|
|
line: {
|
|
enabled: true,
|
|
stroke: stroke3,
|
|
strokeOpacity,
|
|
strokeWidth,
|
|
lineDash
|
|
}
|
|
};
|
|
}
|
|
getLegendData(legendType) {
|
|
if (legendType !== "category") {
|
|
return [];
|
|
}
|
|
const { id: seriesId, visible } = this;
|
|
const { yLowKey, yHighKey, yName, yLowName, yHighName, legendItemName, showInLegend } = this.properties;
|
|
const legendItemText = legendItemName ?? yName ?? `${yLowName ?? yLowKey} - ${yHighName ?? yHighKey}`;
|
|
const itemId = `${yLowKey}-${yHighKey}`;
|
|
return [
|
|
{
|
|
legendType: "category",
|
|
id: seriesId,
|
|
itemId,
|
|
seriesId,
|
|
enabled: visible,
|
|
label: { text: `${legendItemText}` },
|
|
symbol: this.legendItemSymbol(),
|
|
legendItemName,
|
|
hideInLegend: !showInLegend
|
|
}
|
|
];
|
|
}
|
|
isLabelEnabled() {
|
|
return this.properties.label.enabled;
|
|
}
|
|
nodeFactory() {
|
|
return new Marker();
|
|
}
|
|
animateEmptyUpdateReady(animationData) {
|
|
const { datumSelection, labelSelection, contextData, paths } = animationData;
|
|
const { animationManager } = this.ctx;
|
|
this.updateAreaPaths(paths, contextData);
|
|
pathSwipeInAnimation(this, animationManager, ...paths);
|
|
resetMotion([datumSelection], resetMarkerPositionFn);
|
|
markerSwipeScaleInAnimation(
|
|
this,
|
|
animationManager,
|
|
{ ...this.getAnimationDrawingModes(), phase: "initial" },
|
|
datumSelection
|
|
);
|
|
seriesLabelFadeInAnimation(this, "labels", animationManager, labelSelection, this.highlightLabelSelection);
|
|
}
|
|
animateReadyResize(animationData) {
|
|
const { contextData, paths } = animationData;
|
|
this.updateAreaPaths(paths, contextData);
|
|
super.animateReadyResize(animationData);
|
|
}
|
|
animateWaitingUpdateReady(animationData) {
|
|
const { animationManager } = this.ctx;
|
|
const { datumSelection, labelSelection, contextData, paths, previousContextData } = animationData;
|
|
const [fill, lowStroke, highStroke] = paths;
|
|
if (fill == null && lowStroke == null && highStroke == null)
|
|
return;
|
|
this.resetDatumAnimation(animationData);
|
|
this.resetLabelAnimation(animationData);
|
|
const update = () => {
|
|
this.resetPathAnimation(animationData);
|
|
this.updateAreaPaths(paths, contextData);
|
|
};
|
|
const skip = () => {
|
|
animationManager.skipCurrentBatch();
|
|
update();
|
|
};
|
|
if (contextData == null || previousContextData == null) {
|
|
update();
|
|
markerFadeInAnimation(this, animationManager, "added", this.getAnimationDrawingModes(), datumSelection);
|
|
pathFadeInAnimation(this, "fill_path_properties", animationManager, "add", fill);
|
|
pathFadeInAnimation(this, "low_stroke_path_properties", animationManager, "add", lowStroke);
|
|
pathFadeInAnimation(this, "high_stroke_path_properties", animationManager, "add", highStroke);
|
|
seriesLabelFadeInAnimation(this, "labels", animationManager, labelSelection, this.highlightLabelSelection);
|
|
return;
|
|
}
|
|
const fns = prepareRangeAreaPathAnimation(
|
|
contextData,
|
|
previousContextData,
|
|
this.processedData?.reduced?.diff?.[this.id]
|
|
);
|
|
if (fns === void 0) {
|
|
skip();
|
|
return;
|
|
} else if (fns.status === "no-op") {
|
|
return;
|
|
}
|
|
fromToMotion(this.id, "fill_path_properties", animationManager, [fill], fns.fill.pathProperties);
|
|
fromToMotion(this.id, "low_stroke_path_properties", animationManager, [lowStroke], fns.stroke.pathProperties);
|
|
fromToMotion(this.id, "high_stroke_path_properties", animationManager, [highStroke], fns.stroke.pathProperties);
|
|
if (fns.status === "added") {
|
|
this.updateAreaPaths(paths, contextData);
|
|
} else if (fns.status === "removed") {
|
|
this.updateAreaPaths(paths, previousContextData);
|
|
} else {
|
|
pathMotion(this.id, "fill_path_update", animationManager, [fill], fns.fill.path);
|
|
pathMotion(this.id, "low_stroke_path_update", animationManager, [lowStroke], fns.stroke.path);
|
|
pathMotion(this.id, "high_stroke_path_update", animationManager, [highStroke], fns.stroke.path);
|
|
}
|
|
if (fns.hasMotion) {
|
|
markerFadeInAnimation(this, animationManager, void 0, this.getAnimationDrawingModes(), datumSelection);
|
|
seriesLabelFadeInAnimation(this, "labels", animationManager, labelSelection, this.highlightLabelSelection);
|
|
}
|
|
this.ctx.animationManager.animate({
|
|
id: this.id,
|
|
groupId: "reset_after_animation",
|
|
phase: "trailing",
|
|
from: {},
|
|
to: {},
|
|
onComplete: () => this.updateAreaPaths(paths, contextData)
|
|
});
|
|
}
|
|
getFormattedMarkerStyle(datum) {
|
|
const stylerStyle = this.getStyle();
|
|
const params = this.makeItemStylerParams(datum.itemType);
|
|
return this.getMarkerStyle(
|
|
this.properties.item[datum.itemType].marker,
|
|
datum,
|
|
params,
|
|
{ isHighlight: true, resolveMarkerSubPath: ["item", datum.itemType, "marker"] },
|
|
void 0,
|
|
stylerStyle
|
|
);
|
|
}
|
|
getMarkerStyle(marker, datum, params, opts, defaultOverrideStyle, inheritedStyle) {
|
|
true;
|
|
marker.itemStyler = this.properties.marker.itemStyler;
|
|
return super.getMarkerStyle(marker, datum, params, opts, defaultOverrideStyle, inheritedStyle);
|
|
}
|
|
computeFocusBounds(opts) {
|
|
const hiBox = computeMarkerFocusBounds(this, opts);
|
|
const loBox = computeMarkerFocusBounds(this, { ...opts, datumIndex: opts.datumIndex + 1 });
|
|
if (hiBox && loBox) {
|
|
return BBox13.merge([hiBox, loBox]);
|
|
}
|
|
return void 0;
|
|
}
|
|
isDatumEnabled(nodeData, datumIndex) {
|
|
return datumIndex % 2 === 0 && super.isDatumEnabled(nodeData, datumIndex);
|
|
}
|
|
hasItemStylers() {
|
|
return this.properties.styler != null || this.properties.marker.itemStyler != null || this.properties.label.itemStyler != null;
|
|
}
|
|
};
|
|
RangeAreaSeries.className = "RangeAreaSeries";
|
|
RangeAreaSeries.type = "range-area";
|
|
|
|
// packages/ag-charts-enterprise/src/series/range-area/rangeAreaSeriesOptionsDef.ts
|
|
import { _ModuleSupport as _ModuleSupport108 } from "ag-charts-community";
|
|
import {
|
|
boolean as boolean9,
|
|
commonSeriesOptionsDefs as commonSeriesOptionsDefs5,
|
|
constant as constant5,
|
|
fillOptionsDef,
|
|
number as number3,
|
|
required as required5,
|
|
shapeSegmentation as shapeSegmentation2,
|
|
string as string5,
|
|
undocumented as undocumented6
|
|
} from "ag-charts-core";
|
|
var { rangeAreaSeriesThemeableOptionsDef } = _ModuleSupport108;
|
|
var rangeAreaSeriesOptionsDef = {
|
|
...commonSeriesOptionsDefs5,
|
|
...rangeAreaSeriesThemeableOptionsDef,
|
|
type: required5(constant5("range-area")),
|
|
xKey: required5(string5),
|
|
yLowKey: required5(string5),
|
|
yHighKey: required5(string5),
|
|
xKeyAxis: string5,
|
|
yKeyAxis: string5,
|
|
xName: string5,
|
|
yName: string5,
|
|
yLowName: string5,
|
|
yHighName: string5,
|
|
legendItemName: string5,
|
|
segmentation: shapeSegmentation2,
|
|
invertedStyle: {
|
|
enabled: boolean9,
|
|
...fillOptionsDef
|
|
}
|
|
};
|
|
rangeAreaSeriesOptionsDef.pickOutsideVisibleMinorAxis = undocumented6(boolean9);
|
|
rangeAreaSeriesOptionsDef.focusPriority = undocumented6(number3);
|
|
|
|
// packages/ag-charts-enterprise/src/series/range-area/rangeAreaThemes.ts
|
|
import "ag-charts-community";
|
|
import {
|
|
CARTESIAN_AXIS_TYPE as CARTESIAN_AXIS_TYPE6,
|
|
FILL_GRADIENT_LINEAR_DEFAULTS as FILL_GRADIENT_LINEAR_DEFAULTS2,
|
|
FILL_GRADIENT_RADIAL_REVERSED_DEFAULTS,
|
|
FILL_IMAGE_DEFAULTS as FILL_IMAGE_DEFAULTS3,
|
|
FILL_PATTERN_DEFAULTS as FILL_PATTERN_DEFAULTS2,
|
|
LABEL_BOXING_DEFAULTS as LABEL_BOXING_DEFAULTS2,
|
|
MARKER_SERIES_HIGHLIGHT_STYLE,
|
|
SEGMENTATION_DEFAULTS as SEGMENTATION_DEFAULTS2
|
|
} from "ag-charts-core";
|
|
var RANGE_AREA_ITEM = {
|
|
lineDash: {
|
|
$path: "/series/$index/lineDash"
|
|
},
|
|
lineDashOffset: {
|
|
$path: "/series/$index/lineDashOffset"
|
|
},
|
|
stroke: {
|
|
$path: ["/series/$index/stroke", { $palette: "stroke" }]
|
|
},
|
|
strokeOpacity: {
|
|
$path: "/series/$index/strokeOpacity"
|
|
},
|
|
strokeWidth: {
|
|
$path: ["/series/$index/strokeWidth", 1]
|
|
},
|
|
marker: {
|
|
enabled: {
|
|
$path: "/series/$index/marker/enabled"
|
|
},
|
|
fill: {
|
|
$isUserOption: [
|
|
"/series/$index/marker/fill",
|
|
{
|
|
$if: [
|
|
{
|
|
$or: [
|
|
{ $isGradient: { $path: "/series/$index/marker/fill" } },
|
|
{ $isImage: { $path: "/series/$index/marker/fill" } },
|
|
{ $isPattern: { $path: "/series/$index/marker/fill" } }
|
|
]
|
|
},
|
|
{
|
|
$merge: [
|
|
{ $path: "/series/$index/marker/fill" },
|
|
{
|
|
$applySwitch: [
|
|
{ $path: "type" },
|
|
void 0,
|
|
// default case shouldn't be hit because of $if
|
|
["gradient", FILL_GRADIENT_RADIAL_REVERSED_DEFAULTS],
|
|
["image", FILL_IMAGE_DEFAULTS3],
|
|
["pattern", FILL_PATTERN_DEFAULTS2]
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
$isUserOption: [
|
|
"/series/$index/marker/fill",
|
|
{ $path: "/series/$index/marker/fill" },
|
|
{ $palette: "fill" }
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
$applySwitch: [
|
|
{ $path: "type" },
|
|
{ $palette: "fill" },
|
|
["gradient", FILL_GRADIENT_RADIAL_REVERSED_DEFAULTS],
|
|
["image", FILL_IMAGE_DEFAULTS3],
|
|
["pattern", FILL_PATTERN_DEFAULTS2]
|
|
]
|
|
}
|
|
]
|
|
},
|
|
fillOpacity: {
|
|
$path: "/series/$index/marker/fillOpacity"
|
|
},
|
|
lineDash: {
|
|
$path: "/series/$index/marker/lineDash"
|
|
},
|
|
lineDashOffset: {
|
|
$path: "/series/$index/marker/lineDashOffset"
|
|
},
|
|
shape: {
|
|
$path: "/series/$index/marker/shape"
|
|
},
|
|
size: {
|
|
$path: ["/series/$index/marker/size", 6]
|
|
},
|
|
stroke: {
|
|
$path: ["/series/$index/marker/stroke", { $palette: "stroke" }]
|
|
},
|
|
strokeOpacity: {
|
|
$path: "/series/$index/marker/strokeOpacity"
|
|
},
|
|
strokeWidth: {
|
|
$path: ["/series/$index/marker/strokeWidth", 2]
|
|
}
|
|
}
|
|
};
|
|
var RANGE_AREA_SERIES_THEME = {
|
|
series: {
|
|
fill: {
|
|
$applySwitch: [
|
|
{ $path: "type" },
|
|
{ $palette: "fill" },
|
|
["gradient", FILL_GRADIENT_LINEAR_DEFAULTS2],
|
|
["pattern", FILL_PATTERN_DEFAULTS2]
|
|
]
|
|
},
|
|
fillOpacity: 0.7,
|
|
stroke: { $palette: "stroke" },
|
|
strokeWidth: 1,
|
|
marker: {
|
|
enabled: false,
|
|
fill: {
|
|
$applySwitch: [
|
|
{ $path: "type" },
|
|
{ $palette: "fill" },
|
|
["gradient", FILL_GRADIENT_RADIAL_REVERSED_DEFAULTS],
|
|
["image", FILL_IMAGE_DEFAULTS3],
|
|
["pattern", FILL_PATTERN_DEFAULTS2]
|
|
]
|
|
},
|
|
shape: "circle",
|
|
stroke: { $palette: "stroke" },
|
|
size: 6,
|
|
strokeWidth: 2
|
|
},
|
|
nodeClickRange: "nearest",
|
|
item: {
|
|
low: RANGE_AREA_ITEM,
|
|
high: RANGE_AREA_ITEM
|
|
},
|
|
label: {
|
|
...LABEL_BOXING_DEFAULTS2,
|
|
enabled: false,
|
|
placement: "outside",
|
|
padding: { $isUserOption: ["./spacing", 0, 10] },
|
|
// compatibility with old `padding` property (now named `spacing`).
|
|
fontSize: { $ref: "fontSize" },
|
|
fontFamily: { $ref: "fontFamily" },
|
|
fontWeight: { $ref: "fontWeight" },
|
|
color: { $ref: "textColor" }
|
|
},
|
|
interpolation: {
|
|
type: "linear"
|
|
},
|
|
tooltip: {
|
|
range: { $path: ["/tooltip/range", "nearest"] }
|
|
},
|
|
highlight: MARKER_SERIES_HIGHLIGHT_STYLE,
|
|
segmentation: SEGMENTATION_DEFAULTS2,
|
|
invertedStyle: {
|
|
enabled: false,
|
|
fill: {
|
|
$applySwitch: [
|
|
{ $path: "type" },
|
|
{ $palette: "fill" },
|
|
// @todo(AG-14792) should be { $path: '../fill' } to inherit from series.fill
|
|
["gradient", FILL_GRADIENT_LINEAR_DEFAULTS2],
|
|
["image", FILL_IMAGE_DEFAULTS3],
|
|
["pattern", FILL_PATTERN_DEFAULTS2]
|
|
]
|
|
},
|
|
fillOpacity: { $path: "../fillOpacity" }
|
|
}
|
|
},
|
|
axes: {
|
|
[CARTESIAN_AXIS_TYPE6.NUMBER]: {
|
|
crosshair: { enabled: true }
|
|
}
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/series/range-area/rangeAreaModule.ts
|
|
var { predictCartesianNonPrimitiveAxis: predictCartesianNonPrimitiveAxis2 } = _ModuleSupport109;
|
|
var RangeAreaSeriesModule = {
|
|
type: "series",
|
|
name: "range-area",
|
|
chartType: "cartesian",
|
|
enterprise: true,
|
|
version: VERSION19,
|
|
dependencies: [CartesianChartModule5],
|
|
options: rangeAreaSeriesOptionsDef,
|
|
matchingKeys: ["xKey", "yLowKey", "yHighKey", "normalizedTo"],
|
|
predictAxis: predictCartesianNonPrimitiveAxis2,
|
|
defaultAxes: {
|
|
y: { type: CARTESIAN_AXIS_TYPE7.NUMBER, position: CARTESIAN_POSITION4.LEFT },
|
|
x: { type: CARTESIAN_AXIS_TYPE7.CATEGORY, position: CARTESIAN_POSITION4.BOTTOM }
|
|
},
|
|
axisKeys: { [ChartAxisDirection23.X]: "xKeyAxis", [ChartAxisDirection23.Y]: "yKeyAxis" },
|
|
themeTemplate: RANGE_AREA_SERIES_THEME,
|
|
create: (ctx) => new RangeAreaSeries(ctx)
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/series/range-bar/rangeBarModule.ts
|
|
import { CartesianChartModule as CartesianChartModule6, VERSION as VERSION20, _ModuleSupport as _ModuleSupport114 } from "ag-charts-community";
|
|
import { ChartAxisDirection as ChartAxisDirection25, DIRECTION_SWAP_AXES as DIRECTION_SWAP_AXES2 } from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/series/range-bar/rangeBarSeries.ts
|
|
import {
|
|
_ModuleSupport as _ModuleSupport112
|
|
} from "ag-charts-community";
|
|
import {
|
|
AGGREGATION_INDEX_X_MAX as AGGREGATION_INDEX_X_MAX2,
|
|
AGGREGATION_INDEX_X_MIN as AGGREGATION_INDEX_X_MIN2,
|
|
AGGREGATION_INDEX_Y_MAX as AGGREGATION_INDEX_Y_MAX3,
|
|
AGGREGATION_INDEX_Y_MIN as AGGREGATION_INDEX_Y_MIN3,
|
|
AGGREGATION_SPAN as AGGREGATION_SPAN3,
|
|
ChartAxisDirection as ChartAxisDirection24,
|
|
DebugMetrics as DebugMetrics3,
|
|
areScalingEqual as areScalingEqual2,
|
|
findMinMax as findMinMax3,
|
|
mergeDefaults as mergeDefaults8
|
|
} from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/series/range-bar/rangeBarAggregation.ts
|
|
import "ag-charts-community";
|
|
import {
|
|
aggregationDomain as aggregationDomain3,
|
|
computeExtremesAggregation as computeExtremesAggregation3,
|
|
computeExtremesAggregationPartial as computeExtremesAggregationPartial3,
|
|
simpleMemorize2 as simpleMemorize23
|
|
} from "ag-charts-core";
|
|
function aggregateRangeBarData(scale, xValues, highValues, lowValues, domainInput, smallestKeyInterval, xNeedsValueOf, yNeedsValueOf) {
|
|
const [d0, d1] = aggregationDomain3(scale, domainInput);
|
|
return computeExtremesAggregation3([d0, d1], xValues, highValues, lowValues, {
|
|
smallestKeyInterval,
|
|
xNeedsValueOf,
|
|
yNeedsValueOf
|
|
});
|
|
}
|
|
var memoizedAggregateRangeBarData = simpleMemorize23(aggregateRangeBarData);
|
|
function aggregateRangeBarDataFromDataModel(scale, dataModel, processedData, series, existingFilters) {
|
|
const xValues = dataModel.resolveKeysById(series, "xValue", processedData);
|
|
const highValues = dataModel.resolveColumnById(series, "yHighValue", processedData);
|
|
const lowValues = dataModel.resolveColumnById(series, "yLowValue", processedData);
|
|
const domainInput = dataModel.getDomain(series, "xValue", "key", processedData);
|
|
const xNeedsValueOf = dataModel.resolveColumnNeedsValueOf(series, "xValue", processedData);
|
|
const yNeedsValueOf = dataModel.resolveColumnNeedsValueOf(series, "yHighValue", processedData) ?? dataModel.resolveColumnNeedsValueOf(series, "yLowValue", processedData);
|
|
if (existingFilters) {
|
|
const [d0, d1] = aggregationDomain3(scale, domainInput);
|
|
return computeExtremesAggregation3([d0, d1], xValues, highValues, lowValues, {
|
|
smallestKeyInterval: processedData.reduced?.smallestKeyInterval,
|
|
xNeedsValueOf,
|
|
yNeedsValueOf,
|
|
existingFilters
|
|
});
|
|
}
|
|
return memoizedAggregateRangeBarData(
|
|
scale,
|
|
xValues,
|
|
highValues,
|
|
lowValues,
|
|
domainInput,
|
|
processedData.reduced?.smallestKeyInterval,
|
|
xNeedsValueOf,
|
|
yNeedsValueOf
|
|
);
|
|
}
|
|
function aggregateRangeBarDataFromDataModelPartial(scale, dataModel, processedData, series, targetRange, existingFilters) {
|
|
const xValues = dataModel.resolveKeysById(series, "xValue", processedData);
|
|
const highValues = dataModel.resolveColumnById(series, "yHighValue", processedData);
|
|
const lowValues = dataModel.resolveColumnById(series, "yLowValue", processedData);
|
|
const domainInput = dataModel.getDomain(series, "xValue", "key", processedData);
|
|
const xNeedsValueOf = dataModel.resolveColumnNeedsValueOf(series, "xValue", processedData);
|
|
const yNeedsValueOf = dataModel.resolveColumnNeedsValueOf(series, "yHighValue", processedData) ?? dataModel.resolveColumnNeedsValueOf(series, "yLowValue", processedData);
|
|
const [d0, d1] = aggregationDomain3(scale, domainInput);
|
|
return computeExtremesAggregationPartial3([d0, d1], xValues, highValues, lowValues, {
|
|
smallestKeyInterval: processedData.reduced?.smallestKeyInterval,
|
|
targetRange,
|
|
xNeedsValueOf,
|
|
yNeedsValueOf,
|
|
existingFilters
|
|
});
|
|
}
|
|
|
|
// packages/ag-charts-enterprise/src/series/range-bar/rangeBarProperties.ts
|
|
import { _ModuleSupport as _ModuleSupport111 } from "ag-charts-community";
|
|
import { Property as Property56 } from "ag-charts-core";
|
|
var { AbstractBarSeriesProperties: AbstractBarSeriesProperties3, makeSeriesTooltip: makeSeriesTooltip6, DropShadow: DropShadow2, Label: Label3 } = _ModuleSupport111;
|
|
var RangeBarSeriesLabel = class extends Label3 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.placement = "inside";
|
|
this.spacing = 0;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property56
|
|
], RangeBarSeriesLabel.prototype, "placement", 2);
|
|
__decorateClass([
|
|
Property56
|
|
], RangeBarSeriesLabel.prototype, "spacing", 2);
|
|
var RangeBarProperties = class extends AbstractBarSeriesProperties3 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.fill = "#99CCFF";
|
|
this.fillOpacity = 1;
|
|
this.stroke = "#99CCFF";
|
|
this.strokeWidth = 1;
|
|
this.strokeOpacity = 1;
|
|
this.lineDash = [0];
|
|
this.lineDashOffset = 0;
|
|
this.cornerRadius = 0;
|
|
this.shadow = new DropShadow2().set({ enabled: false });
|
|
this.label = new RangeBarSeriesLabel();
|
|
this.tooltip = makeSeriesTooltip6();
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property56
|
|
], RangeBarProperties.prototype, "xKey", 2);
|
|
__decorateClass([
|
|
Property56
|
|
], RangeBarProperties.prototype, "yLowKey", 2);
|
|
__decorateClass([
|
|
Property56
|
|
], RangeBarProperties.prototype, "yHighKey", 2);
|
|
__decorateClass([
|
|
Property56
|
|
], RangeBarProperties.prototype, "xName", 2);
|
|
__decorateClass([
|
|
Property56
|
|
], RangeBarProperties.prototype, "yName", 2);
|
|
__decorateClass([
|
|
Property56
|
|
], RangeBarProperties.prototype, "yLowName", 2);
|
|
__decorateClass([
|
|
Property56
|
|
], RangeBarProperties.prototype, "yHighName", 2);
|
|
__decorateClass([
|
|
Property56
|
|
], RangeBarProperties.prototype, "fill", 2);
|
|
__decorateClass([
|
|
Property56
|
|
], RangeBarProperties.prototype, "fillOpacity", 2);
|
|
__decorateClass([
|
|
Property56
|
|
], RangeBarProperties.prototype, "stroke", 2);
|
|
__decorateClass([
|
|
Property56
|
|
], RangeBarProperties.prototype, "strokeWidth", 2);
|
|
__decorateClass([
|
|
Property56
|
|
], RangeBarProperties.prototype, "strokeOpacity", 2);
|
|
__decorateClass([
|
|
Property56
|
|
], RangeBarProperties.prototype, "lineDash", 2);
|
|
__decorateClass([
|
|
Property56
|
|
], RangeBarProperties.prototype, "lineDashOffset", 2);
|
|
__decorateClass([
|
|
Property56
|
|
], RangeBarProperties.prototype, "cornerRadius", 2);
|
|
__decorateClass([
|
|
Property56
|
|
], RangeBarProperties.prototype, "styler", 2);
|
|
__decorateClass([
|
|
Property56
|
|
], RangeBarProperties.prototype, "itemStyler", 2);
|
|
__decorateClass([
|
|
Property56
|
|
], RangeBarProperties.prototype, "shadow", 2);
|
|
__decorateClass([
|
|
Property56
|
|
], RangeBarProperties.prototype, "label", 2);
|
|
__decorateClass([
|
|
Property56
|
|
], RangeBarProperties.prototype, "tooltip", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/series/range-bar/rangeBarSeries.ts
|
|
var {
|
|
SeriesNodePickMode: SeriesNodePickMode4,
|
|
valueProperty: valueProperty7,
|
|
keyProperty: keyProperty5,
|
|
checkCrisp,
|
|
updateLabelNode: updateLabelNode3,
|
|
SMALLEST_KEY_INTERVAL: SMALLEST_KEY_INTERVAL3,
|
|
LARGEST_KEY_INTERVAL,
|
|
diff: diff4,
|
|
prepareBarAnimationFunctions,
|
|
midpointStartingBarPosition,
|
|
resetBarSelectionsFn,
|
|
resetBarSelectionsDirect,
|
|
fixNumericExtent: fixNumericExtent5,
|
|
seriesLabelFadeInAnimation: seriesLabelFadeInAnimation2,
|
|
resetLabelFn: resetLabelFn2,
|
|
animationValidation: animationValidation4,
|
|
computeBarFocusBounds: computeBarFocusBounds4,
|
|
visibleRangeIndices: visibleRangeIndices3,
|
|
createDatumId: createDatumId5,
|
|
Rect: Rect2,
|
|
PointerEvents: PointerEvents3,
|
|
motion: motion2,
|
|
processedDataIsAnimatable: processedDataIsAnimatable4,
|
|
getItemStyles: getItemStyles2,
|
|
calculateSegments: calculateSegments3,
|
|
toHighlightString: toHighlightString3,
|
|
HighlightState: HighlightState3,
|
|
AggregationManager: AggregationManager3,
|
|
upsertNodeDatum: upsertNodeDatum3
|
|
} = _ModuleSupport112;
|
|
var RangeBarSeriesNodeEvent = class extends _ModuleSupport112.SeriesNodeEvent {
|
|
constructor(type, nativeEvent, datum, series) {
|
|
super(type, nativeEvent, datum, series);
|
|
this.xKey = series.properties.xKey;
|
|
this.yLowKey = series.properties.yLowKey;
|
|
this.yHighKey = series.properties.yHighKey;
|
|
}
|
|
};
|
|
var RangeBarSeries = class extends _ModuleSupport112.AbstractBarSeries {
|
|
constructor(moduleCtx) {
|
|
super({
|
|
moduleCtx,
|
|
pickModes: [SeriesNodePickMode4.AXIS_ALIGNED, SeriesNodePickMode4.EXACT_SHAPE_MATCH],
|
|
propertyKeys: {
|
|
x: ["xKey"],
|
|
y: ["yLowKey", "yHighKey"]
|
|
},
|
|
propertyNames: {
|
|
x: ["xName"],
|
|
y: ["yLowName", "yHighName", "yName"]
|
|
},
|
|
categoryKey: "xValue",
|
|
datumSelectionGarbageCollection: false,
|
|
animationResetFns: {
|
|
datum: resetBarSelectionsFn,
|
|
label: resetLabelFn2
|
|
}
|
|
});
|
|
this.properties = new RangeBarProperties();
|
|
this.aggregationManager = new AggregationManager3();
|
|
this.NodeEvent = RangeBarSeriesNodeEvent;
|
|
}
|
|
async processData(dataController) {
|
|
const { xKey, yLowKey, yHighKey } = this.properties;
|
|
const xScale = this.getCategoryAxis()?.scale;
|
|
const yScale = this.getValueAxis()?.scale;
|
|
const { isContinuousX, xScaleType, yScaleType } = this.getScaleInformation({ xScale, yScale });
|
|
const extraProps = [];
|
|
if (this.needsDataModelDiff() && this.processedData) {
|
|
extraProps.push(diff4(this.id, this.processedData));
|
|
}
|
|
if (!this.ctx.animationManager.isSkipped()) {
|
|
extraProps.push(animationValidation4());
|
|
}
|
|
const visibleProps = this.visible ? {} : { forceValue: 0 };
|
|
const allowNullKey = this.properties.allowNullKeys ?? false;
|
|
const { dataModel, processedData } = await this.requestDataModel(dataController, this.data, {
|
|
props: [
|
|
keyProperty5(xKey, xScaleType, { id: "xValue", allowNullKey }),
|
|
valueProperty7(yLowKey, yScaleType, { id: `yLowValue`, invalidValue: null, ...visibleProps }),
|
|
valueProperty7(yHighKey, yScaleType, { id: `yHighValue`, invalidValue: null, ...visibleProps }),
|
|
...isContinuousX ? [SMALLEST_KEY_INTERVAL3, LARGEST_KEY_INTERVAL] : [],
|
|
...extraProps
|
|
],
|
|
groupByKeys: false
|
|
});
|
|
this.smallestDataInterval = processedData.reduced?.smallestKeyInterval;
|
|
this.largestDataInterval = processedData.reduced?.largestKeyInterval;
|
|
this.aggregateData(dataModel, processedData);
|
|
this.animationState.transition("updateData");
|
|
}
|
|
aggregateData(dataModel, processedData) {
|
|
this.aggregationManager.markStale(processedData.input.count);
|
|
if (processedData.type !== "ungrouped")
|
|
return;
|
|
if (processedDataIsAnimatable4(processedData))
|
|
return;
|
|
const xAxis = this.axes[ChartAxisDirection24.X];
|
|
if (xAxis == null)
|
|
return;
|
|
const targetRange = this.estimateTargetRange();
|
|
this.aggregationManager.aggregate({
|
|
computePartial: (existingFilters) => aggregateRangeBarDataFromDataModelPartial(
|
|
xAxis.scale.type,
|
|
dataModel,
|
|
processedData,
|
|
this,
|
|
targetRange,
|
|
existingFilters
|
|
),
|
|
computeFull: (existingFilters) => aggregateRangeBarDataFromDataModel(xAxis.scale.type, dataModel, processedData, this, existingFilters),
|
|
targetRange
|
|
});
|
|
const filters = this.aggregationManager.filters;
|
|
if (filters && filters.length > 0) {
|
|
DebugMetrics3.record(
|
|
`${this.type}:aggregation`,
|
|
filters.map((f) => f.maxRange)
|
|
);
|
|
}
|
|
}
|
|
estimateTargetRange() {
|
|
const xAxis = this.axes[ChartAxisDirection24.X];
|
|
if (xAxis?.scale == null)
|
|
return 0;
|
|
const [r0, r1] = xAxis.scale.range;
|
|
return Math.abs(r1 - r0);
|
|
}
|
|
getSeriesDomain(direction) {
|
|
const { processedData, dataModel } = this;
|
|
if (!processedData || !dataModel)
|
|
return { domain: [] };
|
|
const {
|
|
keys: [keys]
|
|
} = processedData.domain;
|
|
if (direction === this.getCategoryDirection()) {
|
|
const keyDef = dataModel.resolveProcessedDataDefById(this, `xValue`);
|
|
if (keyDef?.def.type === "key" && keyDef?.def.valueType === "category") {
|
|
const sortMetadata = dataModel.getKeySortMetadata(this, "xValue", processedData);
|
|
return { domain: keys, sortMetadata };
|
|
}
|
|
return { domain: this.padBandExtent(keys) };
|
|
} else {
|
|
const yExtent = this.domainForClippedRange(direction, ["yHighValue", "yLowValue"], "xValue");
|
|
const fixedYExtent = findMinMax3(yExtent);
|
|
return { domain: fixNumericExtent5(fixedYExtent) };
|
|
}
|
|
}
|
|
getSeriesRange(_direction, visibleRange) {
|
|
return this.domainForVisibleRange(ChartAxisDirection24.Y, ["yHighValue", "yLowValue"], "xValue", visibleRange);
|
|
}
|
|
/**
|
|
* Creates shared context for node datum creation/update operations.
|
|
* This context is instantiated once and reused across all datum operations
|
|
* to minimize memory allocations. Only caches values that are expensive to
|
|
* compute - cheap property lookups use `this` directly.
|
|
*/
|
|
createNodeDatumContext(xAxis, yAxis) {
|
|
const { dataModel, processedData } = this;
|
|
if (!dataModel || !processedData)
|
|
return void 0;
|
|
const rawData = processedData.dataSources?.get(this.id)?.data;
|
|
if (rawData == null)
|
|
return void 0;
|
|
const xScale = xAxis.scale;
|
|
const yScale = yAxis.scale;
|
|
const barAlongX = this.getBarDirection() === ChartAxisDirection24.X;
|
|
const crisp = checkCrisp(
|
|
xAxis?.scale,
|
|
xAxis?.visibleRange,
|
|
this.smallestDataInterval,
|
|
this.largestDataInterval
|
|
);
|
|
const [r0, r1] = xScale.range;
|
|
const range2 = Math.abs(r1 - r0);
|
|
this.aggregationManager.ensureLevelForRange(range2);
|
|
const dataAggregationFilter = this.aggregationManager.getFilterForRange(range2);
|
|
const animationEnabled = !this.ctx.animationManager.isSkipped();
|
|
const canIncrementallyUpdate = this.contextNodeData?.nodeData != null && (processedData.changeDescription != null || !processedDataIsAnimatable4(processedData) || dataAggregationFilter != null);
|
|
const { groupOffset, barOffset, barWidth } = this.getBarDimensions();
|
|
return {
|
|
xAxis,
|
|
yAxis,
|
|
rawData,
|
|
xValues: dataModel.resolveKeysById(this, `xValue`, processedData),
|
|
yLowValues: dataModel.resolveColumnById(this, `yLowValue`, processedData),
|
|
yHighValues: dataModel.resolveColumnById(this, `yHighValue`, processedData),
|
|
xScale,
|
|
yScale,
|
|
groupOffset,
|
|
barOffset,
|
|
barWidth,
|
|
barAlongX,
|
|
crisp,
|
|
dataAggregationFilter,
|
|
animationEnabled,
|
|
xKey: this.properties.xKey,
|
|
yLowKey: this.properties.yLowKey,
|
|
yHighKey: this.properties.yHighKey,
|
|
labelEnabled: this.properties.label.enabled,
|
|
labelPlacement: this.properties.label.placement,
|
|
labelPadding: (this.properties.label.spacing + (typeof this.properties.label.padding === "number" ? this.properties.label.padding : 0)) * (this.properties.label.placement === "outside" ? 1 : -1),
|
|
canIncrementallyUpdate,
|
|
nodes: canIncrementallyUpdate ? this.contextNodeData.nodeData : [],
|
|
nodeIndex: 0
|
|
};
|
|
}
|
|
/**
|
|
* Validates and prepares state needed for node creation/update.
|
|
* Returns undefined if datum should be skipped.
|
|
*/
|
|
prepareNodeDatumState(ctx, scratch, datumIndex) {
|
|
const datum = ctx.rawData[datumIndex];
|
|
const xValue = ctx.xValues[datumIndex];
|
|
if (xValue === void 0 && !this.properties.allowNullKeys)
|
|
return void 0;
|
|
const rawLowValue = ctx.yLowValues[datumIndex];
|
|
const rawHighValue = ctx.yHighValues[datumIndex];
|
|
if (!Number.isFinite(rawLowValue?.valueOf()) || !Number.isFinite(rawHighValue?.valueOf()))
|
|
return void 0;
|
|
const [yLowValue, yHighValue] = rawLowValue < rawHighValue ? [rawLowValue, rawHighValue] : [rawHighValue, rawLowValue];
|
|
scratch.datum = datum;
|
|
scratch.xValue = xValue;
|
|
scratch.yLowValue = yLowValue;
|
|
scratch.yHighValue = yHighValue;
|
|
scratch.rawLowValue = rawLowValue;
|
|
scratch.rawHighValue = rawHighValue;
|
|
return scratch;
|
|
}
|
|
/**
|
|
* Creates a minimal skeleton node - actual values set by updateNodeDatum.
|
|
*/
|
|
createSkeletonNodeDatum(ctx, params) {
|
|
const scratch = params.nodeDatumScratch;
|
|
return {
|
|
index: params.groupedDataIndex,
|
|
series: this,
|
|
datum: scratch.datum,
|
|
datumIndex: params.datumIndex,
|
|
xValue: scratch.xValue,
|
|
yLowValue: 0,
|
|
// Will be updated by updateNodeDatum
|
|
yHighValue: 0,
|
|
// Will be updated by updateNodeDatum
|
|
yLowKey: ctx.yLowKey,
|
|
yHighKey: ctx.yHighKey,
|
|
xKey: ctx.xKey,
|
|
x: 0,
|
|
// Will be updated by updateNodeDatum
|
|
y: 0,
|
|
// Will be updated by updateNodeDatum
|
|
width: 0,
|
|
// Will be updated by updateNodeDatum
|
|
height: 0,
|
|
// Will be updated by updateNodeDatum
|
|
midPoint: { x: 0, y: 0 },
|
|
// Will be updated by updateNodeDatum
|
|
crisp: params.crisp,
|
|
labels: []
|
|
// Will be updated by updateNodeDatum
|
|
};
|
|
}
|
|
/**
|
|
* Creates a new node: skeleton + update.
|
|
*/
|
|
createNodeDatum(ctx, params, _itemId, strokeWidth) {
|
|
const prepared = this.prepareNodeDatumState(ctx, params.nodeDatumScratch, params.datumIndex);
|
|
if (!prepared)
|
|
return void 0;
|
|
const nodeData = this.createSkeletonNodeDatum(ctx, params);
|
|
this.updateNodeDatum(ctx, nodeData, params, strokeWidth, prepared);
|
|
return nodeData;
|
|
}
|
|
/**
|
|
* Updates node properties in-place.
|
|
* Shared by both create (skeleton + update) and incremental update paths.
|
|
*/
|
|
updateNodeDatum(ctx, node, params, strokeWidth, prepared) {
|
|
prepared ?? (prepared = this.prepareNodeDatumState(ctx, params.nodeDatumScratch, params.datumIndex));
|
|
if (!prepared)
|
|
return;
|
|
const mutableNode = node;
|
|
mutableNode.index = params.groupedDataIndex;
|
|
mutableNode.datum = prepared.datum;
|
|
mutableNode.datumIndex = params.datumIndex;
|
|
mutableNode.xValue = prepared.xValue;
|
|
mutableNode.yLowValue = prepared.rawLowValue;
|
|
mutableNode.yHighValue = prepared.rawHighValue;
|
|
mutableNode.crisp = params.crisp;
|
|
const y = Math.round(ctx.yScale.convert(params.yHigh));
|
|
const bottomY = Math.round(ctx.yScale.convert(params.yLow));
|
|
const height = Math.max(strokeWidth, Math.abs(bottomY - y));
|
|
const rect = {
|
|
x: ctx.barAlongX ? Math.min(y, bottomY) : params.x,
|
|
y: ctx.barAlongX ? params.x : Math.min(y, bottomY),
|
|
width: ctx.barAlongX ? height : params.width,
|
|
height: ctx.barAlongX ? params.width : height
|
|
};
|
|
mutableNode.x = rect.x;
|
|
mutableNode.y = rect.y;
|
|
mutableNode.width = rect.width;
|
|
mutableNode.height = rect.height;
|
|
const mutableMidPoint = mutableNode.midPoint;
|
|
mutableMidPoint.x = rect.x + rect.width / 2;
|
|
mutableMidPoint.y = rect.y + rect.height / 2;
|
|
const existingClipBBox = mutableNode.clipBBox;
|
|
if (existingClipBBox) {
|
|
existingClipBBox.x = rect.x;
|
|
existingClipBBox.y = rect.y;
|
|
existingClipBBox.width = rect.width;
|
|
existingClipBBox.height = rect.height;
|
|
}
|
|
const labelParams = params.labelParamsScratch;
|
|
labelParams.labels = mutableNode.labels;
|
|
labelParams.datumIndex = params.datumIndex;
|
|
labelParams.rectX = rect.x;
|
|
labelParams.rectY = rect.y;
|
|
labelParams.rectWidth = rect.width;
|
|
labelParams.rectHeight = rect.height;
|
|
labelParams.yLowValue = prepared.yLowValue;
|
|
labelParams.yHighValue = prepared.yHighValue;
|
|
labelParams.datum = prepared.datum;
|
|
this.updateLabelData(ctx, labelParams);
|
|
}
|
|
/**
|
|
* Creates node data using aggregation filters for large datasets.
|
|
*/
|
|
createNodeDataWithAggregation(ctx, xPosition, nodeDatumParamsScratch, itemId, strokeWidth, dataAggregationFilter) {
|
|
const { maxRange, indexData, midpointIndices } = dataAggregationFilter;
|
|
const [start, end] = visibleRangeIndices3(1, maxRange, ctx.xAxis.range, (index) => {
|
|
const aggIndex = index * AGGREGATION_SPAN3;
|
|
const xMaxIndex = indexData[aggIndex + AGGREGATION_INDEX_X_MAX2];
|
|
const midDatumIndex = midpointIndices[index];
|
|
if (midDatumIndex === -1)
|
|
return;
|
|
return [xPosition(midDatumIndex), xPosition(xMaxIndex) + ctx.barWidth];
|
|
});
|
|
for (let i = start; i < end; i += 1) {
|
|
const aggIndex = i * AGGREGATION_SPAN3;
|
|
const xMinIndex = indexData[aggIndex + AGGREGATION_INDEX_X_MIN2];
|
|
const xMaxIndex = indexData[aggIndex + AGGREGATION_INDEX_X_MAX2];
|
|
const yMinIndex = indexData[aggIndex + AGGREGATION_INDEX_Y_MIN3];
|
|
const yMaxIndex = indexData[aggIndex + AGGREGATION_INDEX_Y_MAX3];
|
|
const midDatumIndex = midpointIndices[i];
|
|
if (midDatumIndex === -1)
|
|
continue;
|
|
const xValue = ctx.xValues[midDatumIndex];
|
|
if (xValue === void 0 && !this.properties.allowNullKeys)
|
|
continue;
|
|
nodeDatumParamsScratch.datumIndex = midDatumIndex;
|
|
nodeDatumParamsScratch.groupedDataIndex = 0;
|
|
nodeDatumParamsScratch.x = xPosition(midDatumIndex);
|
|
nodeDatumParamsScratch.width = Math.abs(xPosition(xMinIndex) - xPosition(xMaxIndex)) + ctx.barWidth;
|
|
nodeDatumParamsScratch.yLow = ctx.yLowValues[yMinIndex];
|
|
nodeDatumParamsScratch.yHigh = ctx.yHighValues[yMaxIndex];
|
|
nodeDatumParamsScratch.crisp = false;
|
|
upsertNodeDatum3(
|
|
ctx,
|
|
nodeDatumParamsScratch,
|
|
(c, p) => this.createNodeDatum(c, p, itemId, strokeWidth),
|
|
(c, n, p) => this.updateNodeDatum(c, n, p, strokeWidth)
|
|
);
|
|
}
|
|
}
|
|
/**
|
|
* Creates node data for simple (ungrouped) data processing.
|
|
*/
|
|
createNodeDataSimple(ctx, xPosition, nodeDatumParamsScratch, itemId, strokeWidth, processedData) {
|
|
const invalidData = processedData.invalidData?.get(this.id);
|
|
let [start, end] = this.visibleRangeIndices("xValue", ctx.xAxis.range);
|
|
if (processedData.input.count < 1e3) {
|
|
start = 0;
|
|
end = processedData.input.count;
|
|
}
|
|
for (let datumIndex = start; datumIndex < end; datumIndex += 1) {
|
|
if (invalidData?.[datumIndex] === true)
|
|
continue;
|
|
nodeDatumParamsScratch.datumIndex = datumIndex;
|
|
nodeDatumParamsScratch.groupedDataIndex = 0;
|
|
nodeDatumParamsScratch.x = xPosition(datumIndex);
|
|
nodeDatumParamsScratch.width = ctx.barWidth;
|
|
nodeDatumParamsScratch.yLow = ctx.yLowValues[datumIndex];
|
|
nodeDatumParamsScratch.yHigh = ctx.yHighValues[datumIndex];
|
|
nodeDatumParamsScratch.crisp = ctx.crisp;
|
|
upsertNodeDatum3(
|
|
ctx,
|
|
nodeDatumParamsScratch,
|
|
(c, p) => this.createNodeDatum(c, p, itemId, strokeWidth),
|
|
(c, n, p) => this.updateNodeDatum(c, n, p, strokeWidth)
|
|
);
|
|
}
|
|
}
|
|
/**
|
|
* Creates node data for grouped data processing.
|
|
*/
|
|
createNodeDataGrouped(ctx, xPosition, nodeDatumParamsScratch, itemId, strokeWidth) {
|
|
const processedData = this.processedData;
|
|
for (const { datumIndex, groupIndex: groupDataIndex } of this.dataModel.forEachGroupDatum(
|
|
this,
|
|
processedData
|
|
)) {
|
|
nodeDatumParamsScratch.datumIndex = datumIndex;
|
|
nodeDatumParamsScratch.groupedDataIndex = groupDataIndex;
|
|
nodeDatumParamsScratch.x = xPosition(datumIndex);
|
|
nodeDatumParamsScratch.width = ctx.barWidth;
|
|
nodeDatumParamsScratch.yLow = ctx.yLowValues[datumIndex];
|
|
nodeDatumParamsScratch.yHigh = ctx.yHighValues[datumIndex];
|
|
nodeDatumParamsScratch.crisp = ctx.crisp;
|
|
upsertNodeDatum3(
|
|
ctx,
|
|
nodeDatumParamsScratch,
|
|
(c, p) => this.createNodeDatum(c, p, itemId, strokeWidth),
|
|
(c, n, p) => this.updateNodeDatum(c, n, p, strokeWidth)
|
|
);
|
|
}
|
|
}
|
|
populateNodeData(ctx) {
|
|
const { processedData } = this;
|
|
if (!processedData)
|
|
return;
|
|
const { yLowKey, yHighKey, strokeWidth } = this.properties;
|
|
const itemId = `${yLowKey}-${yHighKey}`;
|
|
const xPosition = (datumIndex) => {
|
|
const x = ctx.xScale.convert(ctx.xValues[datumIndex]);
|
|
if (!Number.isFinite(x))
|
|
return Number.NaN;
|
|
return Math.round(x) + ctx.groupOffset + ctx.barOffset;
|
|
};
|
|
const nodeDatumParamsScratch = {
|
|
nodeDatumScratch: {
|
|
datum: void 0,
|
|
xValue: void 0,
|
|
yLowValue: 0,
|
|
yHighValue: 0,
|
|
rawLowValue: void 0,
|
|
rawHighValue: void 0
|
|
},
|
|
labelParamsScratch: {
|
|
labels: [],
|
|
datumIndex: 0,
|
|
rectX: 0,
|
|
rectY: 0,
|
|
rectWidth: 0,
|
|
rectHeight: 0,
|
|
yLowValue: 0,
|
|
yHighValue: 0,
|
|
datum: void 0
|
|
},
|
|
datumIndex: 0,
|
|
groupedDataIndex: 0,
|
|
x: 0,
|
|
width: 0,
|
|
yLow: 0,
|
|
yHigh: 0,
|
|
crisp: false
|
|
};
|
|
if (ctx.dataAggregationFilter != null) {
|
|
this.createNodeDataWithAggregation(
|
|
ctx,
|
|
xPosition,
|
|
nodeDatumParamsScratch,
|
|
itemId,
|
|
strokeWidth,
|
|
ctx.dataAggregationFilter
|
|
);
|
|
} else if (processedData.type === "ungrouped") {
|
|
this.createNodeDataSimple(ctx, xPosition, nodeDatumParamsScratch, itemId, strokeWidth, processedData);
|
|
} else {
|
|
this.createNodeDataGrouped(ctx, xPosition, nodeDatumParamsScratch, itemId, strokeWidth);
|
|
}
|
|
}
|
|
finalizeNodeData(ctx) {
|
|
if (ctx.canIncrementallyUpdate && ctx.nodeIndex < ctx.nodes.length) {
|
|
ctx.nodes.length = ctx.nodeIndex;
|
|
}
|
|
}
|
|
initializeResult(ctx) {
|
|
const { yLowKey, yHighKey } = this.properties;
|
|
const itemId = `${yLowKey}-${yHighKey}`;
|
|
const xAxis = this.getCategoryAxis();
|
|
const yAxis = this.getValueAxis();
|
|
const segments = xAxis && yAxis && this.chart?.seriesRect ? calculateSegments3(this.properties.segmentation, xAxis, yAxis, this.chart.seriesRect, this.ctx.scene) : void 0;
|
|
return {
|
|
itemId,
|
|
nodeData: ctx.nodes,
|
|
labelData: [],
|
|
scales: this.calculateScaling(),
|
|
groupScale: this.getScaling(this.ctx.seriesStateManager.getGroupScale(this)),
|
|
visible: this.visible,
|
|
styles: getItemStyles2(this.getItemStyle.bind(this)),
|
|
segments
|
|
};
|
|
}
|
|
assembleResult(ctx, result) {
|
|
for (const node of ctx.nodes) {
|
|
result.labelData.push(...node.labels);
|
|
}
|
|
return result;
|
|
}
|
|
/**
|
|
* Updates existing label data in place or creates new labels if needed.
|
|
* This avoids array allocations during incremental updates.
|
|
* Uses positional params (no destructuring) for performance in hot path.
|
|
*/
|
|
updateLabelData(ctx, params) {
|
|
const labels = params.labels;
|
|
if (!ctx.labelEnabled) {
|
|
if (labels.length > 0) {
|
|
labels.length = 0;
|
|
}
|
|
return;
|
|
}
|
|
const { xKey, yLowKey, yHighKey, xName, yLowName, yHighName, yName, legendItemName, label } = this.properties;
|
|
const barAlongX = ctx.barAlongX;
|
|
const placement = ctx.labelPlacement;
|
|
const labelPadding = ctx.labelPadding;
|
|
const rectX = params.rectX;
|
|
const rectY = params.rectY;
|
|
const rectWidth = params.rectWidth;
|
|
const rectHeight = params.rectHeight;
|
|
const yLowX = rectX + (barAlongX ? -labelPadding : rectWidth / 2);
|
|
const yLowY = rectY + (barAlongX ? rectHeight / 2 : rectHeight + labelPadding);
|
|
let yLowTextAlign;
|
|
if (placement === "outside") {
|
|
yLowTextAlign = barAlongX ? "right" : "center";
|
|
} else {
|
|
yLowTextAlign = barAlongX ? "left" : "center";
|
|
}
|
|
let yLowTextBaseline;
|
|
if (placement === "outside") {
|
|
yLowTextBaseline = barAlongX ? "middle" : "top";
|
|
} else {
|
|
yLowTextBaseline = barAlongX ? "middle" : "bottom";
|
|
}
|
|
const yHighX = rectX + (barAlongX ? rectWidth + labelPadding : rectWidth / 2);
|
|
const yHighY = rectY + (barAlongX ? rectHeight / 2 : -labelPadding);
|
|
let yHighTextAlign;
|
|
if (placement === "outside") {
|
|
yHighTextAlign = barAlongX ? "left" : "center";
|
|
} else {
|
|
yHighTextAlign = barAlongX ? "right" : "center";
|
|
}
|
|
let yHighTextBaseline;
|
|
if (placement === "outside") {
|
|
yHighTextBaseline = barAlongX ? "middle" : "bottom";
|
|
} else {
|
|
yHighTextBaseline = barAlongX ? "middle" : "top";
|
|
}
|
|
const datum = params.datum;
|
|
const yLowValue = params.yLowValue;
|
|
const yHighValue = params.yHighValue;
|
|
const datumIndex = params.datumIndex;
|
|
const labelTextParams = { datum, xKey, yLowKey, yHighKey, xName, yLowName, yHighName, yName, legendItemName };
|
|
const yDomain = this.getSeriesDomain(ChartAxisDirection24.Y).domain;
|
|
const yLowText = this.getLabelText(
|
|
yLowValue,
|
|
datum,
|
|
yLowKey,
|
|
"y",
|
|
yDomain,
|
|
label,
|
|
{ itemType: "low", value: yLowValue, ...labelTextParams }
|
|
);
|
|
const yHighText = this.getLabelText(
|
|
yHighValue,
|
|
datum,
|
|
yHighKey,
|
|
"y",
|
|
yDomain,
|
|
label,
|
|
{ itemType: "high", value: yHighValue, ...labelTextParams }
|
|
);
|
|
if (labels.length > 0 && labels[0].itemType === "low") {
|
|
const yLowLabel = labels[0];
|
|
yLowLabel.datumIndex = datumIndex;
|
|
yLowLabel.x = yLowX;
|
|
yLowLabel.y = yLowY;
|
|
yLowLabel.textAlign = yLowTextAlign;
|
|
yLowLabel.textBaseline = yLowTextBaseline;
|
|
yLowLabel.text = yLowText;
|
|
yLowLabel.datum = datum;
|
|
} else {
|
|
labels[0] = {
|
|
datumIndex,
|
|
x: yLowX,
|
|
y: yLowY,
|
|
textAlign: yLowTextAlign,
|
|
textBaseline: yLowTextBaseline,
|
|
text: yLowText,
|
|
itemType: "low",
|
|
datum,
|
|
series: this
|
|
};
|
|
}
|
|
if (labels.length > 1 && labels[1].itemType === "high") {
|
|
const yHighLabel = labels[1];
|
|
yHighLabel.datumIndex = datumIndex;
|
|
yHighLabel.x = yHighX;
|
|
yHighLabel.y = yHighY;
|
|
yHighLabel.textAlign = yHighTextAlign;
|
|
yHighLabel.textBaseline = yHighTextBaseline;
|
|
yHighLabel.text = yHighText;
|
|
yHighLabel.datum = datum;
|
|
} else {
|
|
labels[1] = {
|
|
datumIndex,
|
|
x: yHighX,
|
|
y: yHighY,
|
|
textAlign: yHighTextAlign,
|
|
textBaseline: yHighTextBaseline,
|
|
text: yHighText,
|
|
itemType: "high",
|
|
datum,
|
|
series: this
|
|
};
|
|
}
|
|
labels.length = 2;
|
|
}
|
|
nodeFactory() {
|
|
return new Rect2();
|
|
}
|
|
getStyle(ignoreStylerCallback, highlightState) {
|
|
const {
|
|
cornerRadius,
|
|
fill,
|
|
fillOpacity,
|
|
lineDash,
|
|
lineDashOffset,
|
|
stroke: stroke3,
|
|
strokeOpacity,
|
|
strokeWidth,
|
|
styler
|
|
} = this.properties;
|
|
let stylerResult = {};
|
|
if (!ignoreStylerCallback && styler) {
|
|
const stylerParams = this.makeStylerParams(highlightState);
|
|
stylerResult = this.ctx.optionsGraphService.resolvePartial(
|
|
["series", `${this.declarationOrder}`],
|
|
this.cachedCallWithContext(styler, stylerParams) ?? {},
|
|
{ pick: false }
|
|
) ?? {};
|
|
}
|
|
return {
|
|
cornerRadius: stylerResult.cornerRadius ?? cornerRadius,
|
|
fill: stylerResult.fill ?? fill,
|
|
fillOpacity: stylerResult.fillOpacity ?? fillOpacity,
|
|
lineDash: stylerResult.lineDash ?? lineDash,
|
|
lineDashOffset: stylerResult.lineDashOffset ?? lineDashOffset,
|
|
opacity: 1,
|
|
stroke: stylerResult.stroke ?? stroke3,
|
|
strokeOpacity: stylerResult.strokeOpacity ?? strokeOpacity,
|
|
strokeWidth: stylerResult.strokeWidth ?? strokeWidth
|
|
};
|
|
}
|
|
makeStylerParams(highlightStateEnum) {
|
|
const { id: seriesId } = this;
|
|
const {
|
|
cornerRadius,
|
|
fill,
|
|
fillOpacity,
|
|
lineDash,
|
|
lineDashOffset,
|
|
stroke: stroke3,
|
|
strokeOpacity,
|
|
strokeWidth,
|
|
xKey,
|
|
yLowKey,
|
|
yHighKey
|
|
} = this.properties;
|
|
const highlightState = toHighlightString3(highlightStateEnum ?? HighlightState3.None);
|
|
return {
|
|
cornerRadius,
|
|
fill,
|
|
fillOpacity,
|
|
highlightState,
|
|
lineDash,
|
|
lineDashOffset,
|
|
seriesId,
|
|
stroke: stroke3,
|
|
strokeOpacity,
|
|
strokeWidth,
|
|
xKey,
|
|
yLowKey,
|
|
yHighKey
|
|
};
|
|
}
|
|
updateDatumSelection(opts) {
|
|
const { nodeData, datumSelection } = opts;
|
|
const data = nodeData ?? [];
|
|
if (!processedDataIsAnimatable4(this.processedData)) {
|
|
return datumSelection.update(data);
|
|
}
|
|
return datumSelection.update(data, void 0, (datum) => this.getDatumId(datum));
|
|
}
|
|
getItemStyle(datumIndex, isHighlight, highlightState) {
|
|
const { properties, dataModel, processedData } = this;
|
|
const { itemStyler } = properties;
|
|
const highlightStyle = this.getHighlightStyle(isHighlight, datumIndex, highlightState);
|
|
let style = mergeDefaults8(highlightStyle, this.getStyle(datumIndex === void 0, highlightState));
|
|
if (itemStyler && dataModel != null && processedData != null && datumIndex != null) {
|
|
const xValue = dataModel.resolveKeysById(this, `xValue`, processedData)[datumIndex];
|
|
const overrides = this.cachedDatumCallback(
|
|
createDatumId5(this.getDatumId({ xValue }), isHighlight ? "highlight" : "node"),
|
|
() => {
|
|
const params = this.makeItemStylerParams(datumIndex, isHighlight, style);
|
|
return this.callWithContext(itemStyler, params);
|
|
}
|
|
);
|
|
if (overrides) {
|
|
style = mergeDefaults8(overrides, style);
|
|
}
|
|
}
|
|
return style;
|
|
}
|
|
makeItemStylerParams(datumIndex, isHighlight, style) {
|
|
const { id: seriesId, properties, processedData } = this;
|
|
const { xKey, yHighKey, yLowKey } = properties;
|
|
const datum = processedData.dataSources.get(seriesId)?.data[datumIndex];
|
|
const activeHighlight = this.ctx.highlightManager?.getActiveHighlight();
|
|
const highlightStateString = this.getHighlightStateString(activeHighlight, isHighlight, datumIndex);
|
|
const fill = this.filterItemStylerFillParams(style.fill) ?? style.fill;
|
|
return {
|
|
seriesId,
|
|
datum,
|
|
xKey,
|
|
yHighKey,
|
|
yLowKey,
|
|
highlightState: highlightStateString,
|
|
...style,
|
|
fill
|
|
};
|
|
}
|
|
updateDatumStyles(opts) {
|
|
const highlightedDatum = this.ctx.highlightManager.getActiveHighlight();
|
|
opts.datumSelection.each((node, datum) => {
|
|
if (!opts.datumSelection.isGarbage(node)) {
|
|
const highlightState = this.getHighlightState(highlightedDatum, opts.isHighlight, datum.datumIndex);
|
|
datum.style = this.getItemStyle(datum.datumIndex, opts.isHighlight, highlightState);
|
|
}
|
|
});
|
|
}
|
|
updateDatumNodes({
|
|
datumSelection,
|
|
isHighlight
|
|
}) {
|
|
const { contextNodeData } = this;
|
|
if (!contextNodeData) {
|
|
return;
|
|
}
|
|
const highlightedDatum = this.ctx.highlightManager.getActiveHighlight();
|
|
const categoryAlongX = this.getCategoryDirection() === ChartAxisDirection24.X;
|
|
const fillBBox = this.getShapeFillBBox();
|
|
const series = this;
|
|
datumSelection.each(function updateRangeBarNode(rect, datum) {
|
|
const style = datum.style ?? contextNodeData.styles[series.getHighlightState(highlightedDatum, isHighlight, datum.datumIndex)];
|
|
rect.setStyleProperties(style, fillBBox);
|
|
rect.setStaticProperties(
|
|
"overlay",
|
|
style.cornerRadius ?? 0,
|
|
style.cornerRadius ?? 0,
|
|
style.cornerRadius ?? 0,
|
|
style.cornerRadius ?? 0,
|
|
categoryAlongX ? datum.width > 0 : datum.height > 0,
|
|
datum.crisp,
|
|
void 0
|
|
);
|
|
});
|
|
}
|
|
updateLabelSelection(opts) {
|
|
const labelData = this.properties.label.enabled ? opts.labelData : [];
|
|
return opts.labelSelection.update(labelData, (text2) => {
|
|
text2.pointerEvents = PointerEvents3.None;
|
|
});
|
|
}
|
|
updateLabelNodes(opts) {
|
|
const { isHighlight = false } = opts;
|
|
const params = {
|
|
xKey: this.properties.xKey,
|
|
xName: this.properties.xName ?? this.properties.xKey,
|
|
yName: this.properties.yName,
|
|
yLowKey: this.properties.yLowKey,
|
|
yLowName: this.properties.yLowName ?? this.properties.yLowKey,
|
|
yHighKey: this.properties.yHighKey,
|
|
yHighName: this.properties.yHighName ?? this.properties.yHighKey,
|
|
legendItemName: this.properties.legendItemName
|
|
};
|
|
const activeHighlight = this.ctx.highlightManager?.getActiveHighlight();
|
|
opts.labelSelection.each((textNode, datum) => {
|
|
textNode.fillOpacity = this.getHighlightStyle(isHighlight, datum?.datumIndex).opacity ?? 1;
|
|
updateLabelNode3(this, textNode, params, this.properties.label, datum, isHighlight, activeHighlight);
|
|
});
|
|
}
|
|
getHighlightLabelData(labelData, highlightedItem) {
|
|
if (highlightedItem.labels?.length) {
|
|
return highlightedItem.labels;
|
|
}
|
|
return super.getHighlightLabelData(labelData, highlightedItem);
|
|
}
|
|
getTooltipContent(datumIndex) {
|
|
const { id: seriesId, dataModel, processedData, properties } = this;
|
|
const { xKey, xName, yName, yLowKey, yHighKey, yLowName, yHighName, tooltip, legendItemName } = properties;
|
|
const xAxis = this.getCategoryAxis();
|
|
const yAxis = this.getValueAxis();
|
|
if (!dataModel || !processedData || !xAxis || !yAxis)
|
|
return;
|
|
const datum = processedData.dataSources.get(this.id)?.data[datumIndex];
|
|
const xValue = dataModel.resolveKeysById(this, `xValue`, processedData)[datumIndex];
|
|
const yHighValue = dataModel.resolveColumnById(this, `yHighValue`, processedData)[datumIndex];
|
|
const yLowValue = dataModel.resolveColumnById(this, `yLowValue`, processedData)[datumIndex];
|
|
const allowNullKeys = this.properties.allowNullKeys ?? false;
|
|
if (xValue === void 0 && !allowNullKeys)
|
|
return;
|
|
const format = this.getItemStyle(datumIndex, false);
|
|
const value = `${this.getAxisValueText(yAxis, "tooltip", yLowValue, datum, yLowKey, legendItemName)} - ${this.getAxisValueText(yAxis, "tooltip", yHighValue, datum, yHighKey, legendItemName)}`;
|
|
return this.formatTooltipWithContext(
|
|
tooltip,
|
|
{
|
|
heading: this.getAxisValueText(xAxis, "tooltip", xValue, datum, xKey, legendItemName),
|
|
symbol: this.legendItemSymbol(),
|
|
data: [
|
|
{
|
|
label: yName,
|
|
fallbackLabel: `${yLowName ?? yLowKey} - ${yHighName ?? yHighKey}`,
|
|
value,
|
|
missing: _ModuleSupport112.isTooltipValueMissing(yHighValue) && _ModuleSupport112.isTooltipValueMissing(yLowValue)
|
|
}
|
|
]
|
|
},
|
|
{
|
|
seriesId,
|
|
datum,
|
|
title: yName,
|
|
xKey,
|
|
xName,
|
|
yName,
|
|
yLowKey,
|
|
yHighKey,
|
|
yLowName,
|
|
yHighName,
|
|
legendItemName,
|
|
...format
|
|
}
|
|
);
|
|
}
|
|
legendItemSymbol() {
|
|
const { fill, stroke: stroke3, strokeWidth, fillOpacity, strokeOpacity, lineDash, lineDashOffset } = this.getStyle(
|
|
false,
|
|
HighlightState3.None
|
|
);
|
|
return {
|
|
marker: {
|
|
fill,
|
|
stroke: stroke3,
|
|
fillOpacity,
|
|
strokeOpacity,
|
|
strokeWidth,
|
|
lineDash,
|
|
lineDashOffset
|
|
}
|
|
};
|
|
}
|
|
getLegendData(legendType) {
|
|
if (legendType !== "category") {
|
|
return [];
|
|
}
|
|
const { id: seriesId, visible } = this;
|
|
const { yName, yLowName, yHighName, yLowKey, yHighKey, legendItemName, showInLegend } = this.properties;
|
|
const legendItemText = legendItemName ?? yName ?? `${yLowName ?? yLowKey} - ${yHighName ?? yHighKey}`;
|
|
const itemId = `${yLowKey}-${yHighKey}`;
|
|
return [
|
|
{
|
|
legendType: "category",
|
|
id: seriesId,
|
|
itemId,
|
|
seriesId,
|
|
enabled: visible,
|
|
label: { text: `${legendItemText}` },
|
|
symbol: this.legendItemSymbol(),
|
|
legendItemName,
|
|
hideInLegend: !showInLegend
|
|
}
|
|
];
|
|
}
|
|
resetDatumAnimation(data) {
|
|
resetBarSelectionsDirect([data.datumSelection]);
|
|
}
|
|
animateEmptyUpdateReady({ datumSelection, labelSelection }) {
|
|
const fns = prepareBarAnimationFunctions(midpointStartingBarPosition(this.isVertical(), "normal"), "unknown");
|
|
motion2.fromToMotion(this.id, "datums", this.ctx.animationManager, [datumSelection], fns);
|
|
seriesLabelFadeInAnimation2(
|
|
this,
|
|
"labels",
|
|
this.ctx.animationManager,
|
|
labelSelection,
|
|
this.highlightLabelSelection
|
|
);
|
|
}
|
|
animateWaitingUpdateReady(data) {
|
|
const { datumSelection: datumSelections, labelSelection, contextData, previousContextData } = data;
|
|
const dataDiff = _ModuleSupport112.calculateDataDiff(
|
|
this.id,
|
|
datumSelections,
|
|
this.getDatumId.bind(this),
|
|
contextData,
|
|
previousContextData,
|
|
this.processedData,
|
|
this.processedDataUpdated
|
|
);
|
|
this.ctx.animationManager.stopByAnimationGroupId(this.id);
|
|
const mode = previousContextData == null ? "fade" : "normal";
|
|
const fns = prepareBarAnimationFunctions(midpointStartingBarPosition(this.isVertical(), mode), "added");
|
|
motion2.fromToMotion(
|
|
this.id,
|
|
"datums",
|
|
this.ctx.animationManager,
|
|
[datumSelections],
|
|
fns,
|
|
(_, datum) => this.getDatumId(datum),
|
|
dataDiff
|
|
);
|
|
if (dataDiff?.changed || !areScalingEqual2(contextData.groupScale, previousContextData?.groupScale)) {
|
|
seriesLabelFadeInAnimation2(
|
|
this,
|
|
"labels",
|
|
this.ctx.animationManager,
|
|
labelSelection,
|
|
this.highlightLabelSelection
|
|
);
|
|
}
|
|
}
|
|
getDatumId(datum) {
|
|
return `${datum.xValue}`;
|
|
}
|
|
isLabelEnabled() {
|
|
return this.properties.label.enabled;
|
|
}
|
|
computeFocusBounds({ datumIndex }) {
|
|
return computeBarFocusBounds4(this, this.contextNodeData?.nodeData[datumIndex]);
|
|
}
|
|
hasItemStylers() {
|
|
return this.properties.styler != null || this.properties.itemStyler != null || this.properties.label.itemStyler != null;
|
|
}
|
|
};
|
|
RangeBarSeries.className = "RangeBarSeries";
|
|
RangeBarSeries.type = "range-bar";
|
|
|
|
// packages/ag-charts-enterprise/src/series/range-bar/rangeBarSeriesOptionsDef.ts
|
|
import { _ModuleSupport as _ModuleSupport113 } from "ag-charts-community";
|
|
import {
|
|
boolean as boolean10,
|
|
commonSeriesOptionsDefs as commonSeriesOptionsDefs6,
|
|
constant as constant6,
|
|
number as number4,
|
|
positiveNumberNonZero as positiveNumberNonZero2,
|
|
ratio as ratio3,
|
|
required as required6,
|
|
shapeSegmentation as shapeSegmentation3,
|
|
string as string6,
|
|
undocumented as undocumented7
|
|
} from "ag-charts-core";
|
|
var { rangeBarSeriesThemeableOptionsDef } = _ModuleSupport113;
|
|
var rangeBarSeriesOptionsDef = {
|
|
...commonSeriesOptionsDefs6,
|
|
...rangeBarSeriesThemeableOptionsDef,
|
|
type: required6(constant6("range-bar")),
|
|
xKey: required6(string6),
|
|
yLowKey: required6(string6),
|
|
yHighKey: required6(string6),
|
|
xKeyAxis: string6,
|
|
yKeyAxis: string6,
|
|
xName: string6,
|
|
yName: string6,
|
|
yLowName: string6,
|
|
yHighName: string6,
|
|
legendItemName: string6,
|
|
segmentation: shapeSegmentation3,
|
|
width: positiveNumberNonZero2,
|
|
widthRatio: ratio3
|
|
};
|
|
rangeBarSeriesOptionsDef.pickOutsideVisibleMinorAxis = undocumented7(boolean10);
|
|
rangeBarSeriesOptionsDef.focusPriority = undocumented7(number4);
|
|
|
|
// packages/ag-charts-enterprise/src/series/range-bar/rangeBarThemes.ts
|
|
import "ag-charts-community";
|
|
import {
|
|
CARTESIAN_AXIS_TYPE as CARTESIAN_AXIS_TYPE8,
|
|
FILL_GRADIENT_LINEAR_DEFAULTS as FILL_GRADIENT_LINEAR_DEFAULTS3,
|
|
FILL_IMAGE_DEFAULTS as FILL_IMAGE_DEFAULTS4,
|
|
FILL_PATTERN_DEFAULTS as FILL_PATTERN_DEFAULTS3,
|
|
LABEL_BOXING_DEFAULTS as LABEL_BOXING_DEFAULTS3,
|
|
MULTI_SERIES_HIGHLIGHT_STYLE as MULTI_SERIES_HIGHLIGHT_STYLE3,
|
|
SEGMENTATION_DEFAULTS as SEGMENTATION_DEFAULTS3
|
|
} from "ag-charts-core";
|
|
var RANGE_BAR_SERIES_THEME = {
|
|
series: {
|
|
direction: "vertical",
|
|
fill: {
|
|
$applySwitch: [
|
|
{ $path: "type" },
|
|
{ $palette: "fill" },
|
|
["gradient", FILL_GRADIENT_LINEAR_DEFAULTS3],
|
|
["image", FILL_IMAGE_DEFAULTS4],
|
|
["pattern", FILL_PATTERN_DEFAULTS3]
|
|
]
|
|
},
|
|
stroke: { $palette: "stroke" },
|
|
strokeWidth: { $isUserOption: ["./stroke", 2, 0] },
|
|
label: {
|
|
...LABEL_BOXING_DEFAULTS3,
|
|
enabled: false,
|
|
fontSize: { $ref: "fontSize" },
|
|
fontFamily: { $ref: "fontFamily" },
|
|
fontWeight: { $ref: "fontWeight" },
|
|
color: { $ref: "chartBackgroundColor" },
|
|
placement: "inside",
|
|
padding: { $isUserOption: ["./spacing", 0, 6] }
|
|
// compatibility with old `padding` property (now named `spacing`).
|
|
},
|
|
highlight: MULTI_SERIES_HIGHLIGHT_STYLE3,
|
|
segmentation: SEGMENTATION_DEFAULTS3
|
|
},
|
|
axes: {
|
|
[CARTESIAN_AXIS_TYPE8.NUMBER]: {
|
|
crosshair: { enabled: true }
|
|
}
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/series/range-bar/rangeBarModule.ts
|
|
var { predictCartesianNonPrimitiveAxis: predictCartesianNonPrimitiveAxis3 } = _ModuleSupport114;
|
|
var RangeBarSeriesModule = {
|
|
type: "series",
|
|
name: "range-bar",
|
|
chartType: "cartesian",
|
|
enterprise: true,
|
|
groupable: true,
|
|
version: VERSION20,
|
|
dependencies: [CartesianChartModule6],
|
|
options: rangeBarSeriesOptionsDef,
|
|
matchingKeys: ["xKey", "yLowKey", "yHighKey", "normalizedTo"],
|
|
predictAxis: predictCartesianNonPrimitiveAxis3,
|
|
defaultAxes: DIRECTION_SWAP_AXES2,
|
|
axisKeys: { [ChartAxisDirection25.X]: "xKeyAxis", [ChartAxisDirection25.Y]: "yKeyAxis" },
|
|
axisKeysFlipped: { [ChartAxisDirection25.X]: "yKeyAxis", [ChartAxisDirection25.Y]: "xKeyAxis" },
|
|
themeTemplate: RANGE_BAR_SERIES_THEME,
|
|
create: (ctx) => new RangeBarSeries(ctx)
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/series/waterfall/waterfallModule.ts
|
|
import { CartesianChartModule as CartesianChartModule7, VERSION as VERSION21 } from "ag-charts-community";
|
|
import { ChartAxisDirection as ChartAxisDirection27, DIRECTION_SWAP_AXES as DIRECTION_SWAP_AXES3 } from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/series/waterfall/waterfallSeries.ts
|
|
import { _ModuleSupport as _ModuleSupport116 } from "ag-charts-community";
|
|
import {
|
|
ChartAxisDirection as ChartAxisDirection26,
|
|
easeOut,
|
|
isContinuous,
|
|
mergeDefaults as mergeDefaults9
|
|
} from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/series/waterfall/waterfallSeriesProperties.ts
|
|
import { _ModuleSupport as _ModuleSupport115 } from "ag-charts-community";
|
|
import { BaseProperties as BaseProperties23, PropertiesArray as PropertiesArray4, Property as Property57 } from "ag-charts-core";
|
|
var { AbstractBarSeriesProperties: AbstractBarSeriesProperties4, makeSeriesTooltip: makeSeriesTooltip7, DropShadow: DropShadow3, Label: Label4 } = _ModuleSupport115;
|
|
var WaterfallSeriesTotal = class extends BaseProperties23 {
|
|
};
|
|
__decorateClass([
|
|
Property57
|
|
], WaterfallSeriesTotal.prototype, "totalType", 2);
|
|
__decorateClass([
|
|
Property57
|
|
], WaterfallSeriesTotal.prototype, "index", 2);
|
|
__decorateClass([
|
|
Property57
|
|
], WaterfallSeriesTotal.prototype, "axisLabel", 2);
|
|
var WaterfallSeriesItemTooltip = class extends BaseProperties23 {
|
|
};
|
|
__decorateClass([
|
|
Property57
|
|
], WaterfallSeriesItemTooltip.prototype, "renderer", 2);
|
|
var WaterfallSeriesLabel = class extends Label4 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.placement = "outside-end";
|
|
this.spacing = 0;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property57
|
|
], WaterfallSeriesLabel.prototype, "placement", 2);
|
|
__decorateClass([
|
|
Property57
|
|
], WaterfallSeriesLabel.prototype, "spacing", 2);
|
|
var WaterfallSeriesItem = class extends BaseProperties23 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.fill = "#c16068";
|
|
this.stroke = "#c16068";
|
|
this.fillOpacity = 1;
|
|
this.strokeOpacity = 1;
|
|
this.lineDash = [0];
|
|
this.lineDashOffset = 0;
|
|
this.strokeWidth = 1;
|
|
this.cornerRadius = 0;
|
|
this.shadow = new DropShadow3().set({ enabled: false });
|
|
this.label = new WaterfallSeriesLabel();
|
|
this.tooltip = new WaterfallSeriesItemTooltip();
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property57
|
|
], WaterfallSeriesItem.prototype, "name", 2);
|
|
__decorateClass([
|
|
Property57
|
|
], WaterfallSeriesItem.prototype, "fill", 2);
|
|
__decorateClass([
|
|
Property57
|
|
], WaterfallSeriesItem.prototype, "stroke", 2);
|
|
__decorateClass([
|
|
Property57
|
|
], WaterfallSeriesItem.prototype, "fillOpacity", 2);
|
|
__decorateClass([
|
|
Property57
|
|
], WaterfallSeriesItem.prototype, "strokeOpacity", 2);
|
|
__decorateClass([
|
|
Property57
|
|
], WaterfallSeriesItem.prototype, "lineDash", 2);
|
|
__decorateClass([
|
|
Property57
|
|
], WaterfallSeriesItem.prototype, "lineDashOffset", 2);
|
|
__decorateClass([
|
|
Property57
|
|
], WaterfallSeriesItem.prototype, "strokeWidth", 2);
|
|
__decorateClass([
|
|
Property57
|
|
], WaterfallSeriesItem.prototype, "cornerRadius", 2);
|
|
__decorateClass([
|
|
Property57
|
|
], WaterfallSeriesItem.prototype, "itemStyler", 2);
|
|
__decorateClass([
|
|
Property57
|
|
], WaterfallSeriesItem.prototype, "shadow", 2);
|
|
__decorateClass([
|
|
Property57
|
|
], WaterfallSeriesItem.prototype, "label", 2);
|
|
__decorateClass([
|
|
Property57
|
|
], WaterfallSeriesItem.prototype, "tooltip", 2);
|
|
var WaterfallSeriesConnectorLine = class extends BaseProperties23 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.enabled = true;
|
|
this.stroke = "black";
|
|
this.strokeOpacity = 1;
|
|
this.lineDash = [0];
|
|
this.lineDashOffset = 0;
|
|
this.strokeWidth = 2;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property57
|
|
], WaterfallSeriesConnectorLine.prototype, "enabled", 2);
|
|
__decorateClass([
|
|
Property57
|
|
], WaterfallSeriesConnectorLine.prototype, "stroke", 2);
|
|
__decorateClass([
|
|
Property57
|
|
], WaterfallSeriesConnectorLine.prototype, "strokeOpacity", 2);
|
|
__decorateClass([
|
|
Property57
|
|
], WaterfallSeriesConnectorLine.prototype, "lineDash", 2);
|
|
__decorateClass([
|
|
Property57
|
|
], WaterfallSeriesConnectorLine.prototype, "lineDashOffset", 2);
|
|
__decorateClass([
|
|
Property57
|
|
], WaterfallSeriesConnectorLine.prototype, "strokeWidth", 2);
|
|
var WaterfallSeriesItems = class extends BaseProperties23 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.positive = new WaterfallSeriesItem();
|
|
this.negative = new WaterfallSeriesItem();
|
|
this.total = new WaterfallSeriesItem();
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property57
|
|
], WaterfallSeriesItems.prototype, "positive", 2);
|
|
__decorateClass([
|
|
Property57
|
|
], WaterfallSeriesItems.prototype, "negative", 2);
|
|
__decorateClass([
|
|
Property57
|
|
], WaterfallSeriesItems.prototype, "total", 2);
|
|
var WaterfallSeriesProperties = class extends AbstractBarSeriesProperties4 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.item = new WaterfallSeriesItems();
|
|
this.totals = new PropertiesArray4(WaterfallSeriesTotal);
|
|
this.line = new WaterfallSeriesConnectorLine();
|
|
this.tooltip = makeSeriesTooltip7();
|
|
}
|
|
getStyle(itemType) {
|
|
const { fillOpacity, strokeWidth, strokeOpacity, fill, stroke: stroke3, lineDash, lineDashOffset, cornerRadius } = this.item[itemType === "subtotal" ? "total" : itemType];
|
|
return {
|
|
fill,
|
|
fillOpacity,
|
|
stroke: stroke3,
|
|
strokeWidth,
|
|
strokeOpacity,
|
|
lineDash,
|
|
lineDashOffset,
|
|
cornerRadius,
|
|
opacity: 1
|
|
};
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property57
|
|
], WaterfallSeriesProperties.prototype, "xKey", 2);
|
|
__decorateClass([
|
|
Property57
|
|
], WaterfallSeriesProperties.prototype, "yKey", 2);
|
|
__decorateClass([
|
|
Property57
|
|
], WaterfallSeriesProperties.prototype, "xName", 2);
|
|
__decorateClass([
|
|
Property57
|
|
], WaterfallSeriesProperties.prototype, "yName", 2);
|
|
__decorateClass([
|
|
Property57
|
|
], WaterfallSeriesProperties.prototype, "item", 2);
|
|
__decorateClass([
|
|
Property57
|
|
], WaterfallSeriesProperties.prototype, "totals", 2);
|
|
__decorateClass([
|
|
Property57
|
|
], WaterfallSeriesProperties.prototype, "line", 2);
|
|
__decorateClass([
|
|
Property57
|
|
], WaterfallSeriesProperties.prototype, "tooltip", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/series/waterfall/waterfallSeries.ts
|
|
var {
|
|
adjustLabelPlacement,
|
|
SeriesNodePickMode: SeriesNodePickMode5,
|
|
fixNumericExtent: fixNumericExtent6,
|
|
valueProperty: valueProperty8,
|
|
keyProperty: keyProperty6,
|
|
accumulativeValueProperty,
|
|
trailingAccumulatedValueProperty,
|
|
createDatumId: createDatumId6,
|
|
checkCrisp: checkCrisp2,
|
|
updateLabelNode: updateLabelNode4,
|
|
prepareBarAnimationFunctions: prepareBarAnimationFunctions2,
|
|
collapsedStartingBarPosition,
|
|
resetBarSelectionsDirect: resetBarSelectionsDirect2,
|
|
resetBarSelectionsFn: resetBarSelectionsFn2,
|
|
seriesLabelFadeInAnimation: seriesLabelFadeInAnimation3,
|
|
resetLabelFn: resetLabelFn3,
|
|
animationValidation: animationValidation5,
|
|
DEFAULT_CARTESIAN_DIRECTION_KEYS: DEFAULT_CARTESIAN_DIRECTION_KEYS2,
|
|
DEFAULT_CARTESIAN_DIRECTION_NAMES: DEFAULT_CARTESIAN_DIRECTION_NAMES2,
|
|
computeBarFocusBounds: computeBarFocusBounds5,
|
|
Rect: Rect3,
|
|
motion: motion3,
|
|
getItemStylesPerItemId: getItemStylesPerItemId2,
|
|
DataSet,
|
|
processedDataIsAnimatable: processedDataIsAnimatable5,
|
|
upsertNodeDatum: upsertNodeDatum4
|
|
} = _ModuleSupport116;
|
|
var WaterfallSeries = class extends _ModuleSupport116.AbstractBarSeries {
|
|
constructor(moduleCtx) {
|
|
super({
|
|
moduleCtx,
|
|
propertyKeys: DEFAULT_CARTESIAN_DIRECTION_KEYS2,
|
|
propertyNames: DEFAULT_CARTESIAN_DIRECTION_NAMES2,
|
|
categoryKey: void 0,
|
|
pickModes: [SeriesNodePickMode5.NEAREST_NODE, SeriesNodePickMode5.EXACT_SHAPE_MATCH],
|
|
pathsPerSeries: ["connector"],
|
|
pathsZIndexSubOrderOffset: [-1, -1],
|
|
animationResetFns: {
|
|
datum: resetBarSelectionsFn2,
|
|
label: resetLabelFn3
|
|
}
|
|
});
|
|
this.properties = new WaterfallSeriesProperties();
|
|
this.seriesItemTypes = /* @__PURE__ */ new Set(["positive", "negative", "total"]);
|
|
}
|
|
async processData(dataController) {
|
|
const { xKey, yKey, totals } = this.properties;
|
|
const { data } = this;
|
|
if (!this.visible)
|
|
return;
|
|
const positiveNumber11 = (v) => isContinuous(v) && Number(v) >= 0;
|
|
const negativeNumber = (v) => isContinuous(v) && Number(v) >= 0;
|
|
const totalTypeValue = (v) => v === "total" || v === "subtotal";
|
|
const propertyDefinition = { missingValue: void 0, invalidValue: void 0 };
|
|
const dataWithTotals = [];
|
|
const totalsMap = totals.reduce((result, total) => {
|
|
const totalsAtIndex = result.get(total.index);
|
|
if (totalsAtIndex) {
|
|
totalsAtIndex.push(total);
|
|
} else {
|
|
result.set(total.index, [total]);
|
|
}
|
|
return result;
|
|
}, /* @__PURE__ */ new Map());
|
|
for (const [i, datum] of data?.data.entries() ?? []) {
|
|
dataWithTotals.push(datum);
|
|
const totalsAtIndex = totalsMap.get(i);
|
|
if (totalsAtIndex) {
|
|
for (const total of totalsAtIndex) {
|
|
dataWithTotals.push({ ...total.toJson(), [xKey]: total.axisLabel });
|
|
}
|
|
}
|
|
}
|
|
const extraProps = [];
|
|
if (!this.ctx.animationManager.isSkipped()) {
|
|
extraProps.push(animationValidation5());
|
|
}
|
|
const xScale = this.getCategoryAxis()?.scale;
|
|
const yScale = this.getValueAxis()?.scale;
|
|
const { isContinuousX, xScaleType, yScaleType } = this.getScaleInformation({ xScale, yScale });
|
|
const allowNullKey = this.properties.allowNullKeys ?? false;
|
|
const { processedData } = await this.requestDataModel(
|
|
dataController,
|
|
DataSet.wrap(dataWithTotals),
|
|
{
|
|
props: [
|
|
keyProperty6(xKey, xScaleType, { id: `xValue`, allowNullKey }),
|
|
accumulativeValueProperty(yKey, yScaleType, {
|
|
...propertyDefinition,
|
|
id: `yCurrent`
|
|
}),
|
|
accumulativeValueProperty(yKey, yScaleType, {
|
|
...propertyDefinition,
|
|
missingValue: 0,
|
|
id: `yCurrentTotal`
|
|
}),
|
|
accumulativeValueProperty(yKey, yScaleType, {
|
|
...propertyDefinition,
|
|
id: `yCurrentPositive`,
|
|
validation: positiveNumber11
|
|
}),
|
|
accumulativeValueProperty(yKey, yScaleType, {
|
|
...propertyDefinition,
|
|
id: `yCurrentNegative`,
|
|
validation: negativeNumber
|
|
}),
|
|
trailingAccumulatedValueProperty(yKey, yScaleType, {
|
|
...propertyDefinition,
|
|
id: `yPrevious`
|
|
}),
|
|
valueProperty8(yKey, yScaleType, { id: `yRaw` }),
|
|
// Raw value pass-through.
|
|
valueProperty8("totalType", "category", {
|
|
id: `totalTypeValue`,
|
|
missingValue: void 0,
|
|
validation: totalTypeValue
|
|
}),
|
|
...isContinuousX ? [_ModuleSupport116.SMALLEST_KEY_INTERVAL, _ModuleSupport116.LARGEST_KEY_INTERVAL] : [],
|
|
...extraProps
|
|
]
|
|
}
|
|
);
|
|
this.smallestDataInterval = processedData.reduced?.smallestKeyInterval;
|
|
this.largestDataInterval = processedData.reduced?.largestKeyInterval;
|
|
this.updateSeriesItemTypes();
|
|
this.animationState.transition("updateData");
|
|
}
|
|
getSeriesDomain(direction) {
|
|
const { processedData, dataModel } = this;
|
|
if (!processedData || !dataModel)
|
|
return { domain: [] };
|
|
const {
|
|
keys: [keys],
|
|
values
|
|
} = processedData.domain;
|
|
if (direction === this.getCategoryDirection()) {
|
|
const keyDef = dataModel.resolveProcessedDataDefById(this, `xValue`);
|
|
if (keyDef?.def.type === "key" && keyDef?.def.valueType === "category") {
|
|
const sortMetadata = dataModel.getKeySortMetadata(this, "xValue", processedData);
|
|
return { domain: keys, sortMetadata };
|
|
}
|
|
const isDirectionY = direction === ChartAxisDirection26.Y;
|
|
const isReversed = this.getCategoryAxis().isReversed();
|
|
return { domain: this.padBandExtent(keys, isReversed !== isDirectionY) };
|
|
} else {
|
|
const yCurrIndex = dataModel.resolveProcessedDataIndexById(this, "yCurrent");
|
|
const yExtent = values[yCurrIndex];
|
|
const fixedYExtent = [Math.min(0, yExtent[0]), Math.max(0, yExtent[1])];
|
|
return { domain: fixNumericExtent6(fixedYExtent) };
|
|
}
|
|
}
|
|
getSeriesRange() {
|
|
return [Number.NaN, Number.NaN];
|
|
}
|
|
populateNodeData(ctx) {
|
|
let trailingSubtotal = 0;
|
|
const paramsScratch = {
|
|
datumIndex: 0,
|
|
datum: void 0,
|
|
xDatum: void 0,
|
|
value: void 0,
|
|
cumulativeValue: void 0,
|
|
trailingValue: void 0,
|
|
datumType: void 0
|
|
};
|
|
for (const [datumIndex, datum] of ctx.rawData.entries()) {
|
|
const datumType = ctx.totalTypeValues[datumIndex];
|
|
const isSubtotal = this.isSubtotal(datumType);
|
|
const isTotal = this.isTotal(datumType);
|
|
const isTotalOrSubtotal = isTotal || isSubtotal;
|
|
const xDatum = ctx.xValues[datumIndex];
|
|
if (xDatum === void 0 && !this.properties.allowNullKeys)
|
|
continue;
|
|
const rawValue = ctx.yRawValues[datumIndex];
|
|
const { cumulativeValue, trailingValue } = this.computeWaterfallValues(
|
|
ctx,
|
|
datumIndex,
|
|
isTotal,
|
|
isSubtotal,
|
|
trailingSubtotal
|
|
);
|
|
if (isTotalOrSubtotal) {
|
|
trailingSubtotal = cumulativeValue ?? 0;
|
|
}
|
|
const value = this.computeDisplayValue(isTotal, isSubtotal, rawValue, cumulativeValue, trailingValue);
|
|
paramsScratch.datumIndex = datumIndex;
|
|
paramsScratch.datum = datum;
|
|
paramsScratch.xDatum = xDatum;
|
|
paramsScratch.value = value;
|
|
paramsScratch.cumulativeValue = cumulativeValue;
|
|
paramsScratch.trailingValue = trailingValue;
|
|
paramsScratch.datumType = datumType;
|
|
const nodeDatum = upsertNodeDatum4(
|
|
ctx,
|
|
paramsScratch,
|
|
(c, p) => this.createNodeDatum(c, p),
|
|
(c, n, p) => this.updateNodeDatum(c, n, p)
|
|
);
|
|
if (nodeDatum) {
|
|
const pathPoint = this.createPointDatum(
|
|
ctx,
|
|
nodeDatum,
|
|
cumulativeValue,
|
|
trailingValue,
|
|
isTotalOrSubtotal
|
|
);
|
|
ctx.pointData.push(pathPoint);
|
|
}
|
|
}
|
|
}
|
|
finalizeNodeData(ctx) {
|
|
if (ctx.nodeIndex < ctx.nodes.length) {
|
|
ctx.nodes.length = ctx.nodeIndex;
|
|
}
|
|
}
|
|
initializeResult(ctx) {
|
|
return {
|
|
itemId: this.properties.yKey,
|
|
nodeData: ctx.nodes,
|
|
labelData: ctx.nodes,
|
|
pointData: [],
|
|
scales: this.calculateScaling(),
|
|
groupScale: this.getScaling(this.ctx.seriesStateManager.getGroupScale(this)),
|
|
visible: this.visible,
|
|
styles: getItemStylesPerItemId2(this.getItemStyle.bind(this), "total", "subtotal", "positive", "negative")
|
|
};
|
|
}
|
|
assembleResult(ctx, result) {
|
|
const connectorLinesEnabled = this.properties.line.enabled;
|
|
if (ctx.yCurrValues != null && connectorLinesEnabled) {
|
|
result.pointData = ctx.pointData;
|
|
}
|
|
return result;
|
|
}
|
|
createNodeDatumContext(xAxis, yAxis) {
|
|
const { dataModel, processedData } = this;
|
|
if (!dataModel || !processedData || processedData.type !== "ungrouped")
|
|
return void 0;
|
|
const categoryAxis = this.getCategoryAxis();
|
|
const valueAxis = this.getValueAxis();
|
|
if (!categoryAxis || !valueAxis)
|
|
return void 0;
|
|
const xScale = xAxis.scale;
|
|
const yScale = yAxis.scale;
|
|
const xValues = dataModel.resolveKeysById(this, `xValue`, processedData);
|
|
const yRawValues = dataModel.resolveColumnById(this, `yRaw`, processedData);
|
|
const totalTypeValues = dataModel.resolveColumnById(
|
|
this,
|
|
`totalTypeValue`,
|
|
processedData
|
|
);
|
|
const yCurrValues = dataModel.resolveColumnById(this, "yCurrent", processedData);
|
|
const yPrevValues = dataModel.resolveColumnById(this, "yPrevious", processedData);
|
|
const yCurrTotalValues = dataModel.resolveColumnById(this, "yCurrentTotal", processedData);
|
|
const rawData = processedData.dataSources.get(this.id)?.data ?? [];
|
|
const { xKey, yKey, xName, yName, line } = this.properties;
|
|
const { contextNodeData } = this;
|
|
const animationEnabled = !this.ctx.animationManager.isSkipped();
|
|
const canIncrementallyUpdate = contextNodeData?.nodeData != null && processedData.changeDescription != null;
|
|
const { barWidth } = this.getBarDimensions();
|
|
return {
|
|
xAxis,
|
|
yAxis,
|
|
xScale,
|
|
yScale,
|
|
categoryAxis,
|
|
valueAxis,
|
|
barAlongX: this.getBarDirection() === ChartAxisDirection26.X,
|
|
barWidth,
|
|
categoryAxisReversed: categoryAxis.isReversed(),
|
|
valueAxisReversed: valueAxis.isReversed(),
|
|
crisp: checkCrisp2(
|
|
categoryAxis.scale,
|
|
categoryAxis.visibleRange,
|
|
this.smallestDataInterval,
|
|
this.largestDataInterval
|
|
),
|
|
animationEnabled,
|
|
xKey,
|
|
yKey,
|
|
xName,
|
|
yName,
|
|
lineStrokeWidth: line.strokeWidth,
|
|
yDomain: this.getSeriesDomain(ChartAxisDirection26.Y).domain,
|
|
xValues,
|
|
rawData,
|
|
yRawValues,
|
|
totalTypeValues,
|
|
yCurrValues,
|
|
yPrevValues,
|
|
yCurrTotalValues,
|
|
canIncrementallyUpdate,
|
|
nodes: canIncrementallyUpdate ? contextNodeData.nodeData : [],
|
|
nodeIndex: 0,
|
|
pointData: []
|
|
};
|
|
}
|
|
computeWaterfallValues(ctx, datumIndex, isTotal, isSubtotal, trailingSubtotal) {
|
|
if (isTotal || isSubtotal) {
|
|
return {
|
|
cumulativeValue: ctx.yCurrTotalValues[datumIndex],
|
|
trailingValue: isSubtotal ? trailingSubtotal : 0
|
|
};
|
|
}
|
|
return {
|
|
cumulativeValue: ctx.yCurrValues[datumIndex],
|
|
trailingValue: ctx.yPrevValues[datumIndex]
|
|
};
|
|
}
|
|
computeDisplayValue(isTotal, isSubtotal, rawValue, cumulativeValue, trailingValue) {
|
|
if (isTotal) {
|
|
return cumulativeValue;
|
|
}
|
|
if (isSubtotal) {
|
|
return (cumulativeValue ?? 0) - (trailingValue ?? 0);
|
|
}
|
|
return rawValue;
|
|
}
|
|
/**
|
|
* Creates a skeleton WaterfallNodeDatum with minimal required fields.
|
|
* The node will be populated by updateNodeDatum.
|
|
*/
|
|
createSkeletonNodeDatum(ctx, params) {
|
|
const { xKey, yKey, crisp } = ctx;
|
|
const { datumIndex, datum, xDatum, value, cumulativeValue, datumType } = params;
|
|
const isPositive = (value ?? 0) >= 0;
|
|
const seriesItemType = this.getSeriesItemType(isPositive, datumType);
|
|
return {
|
|
index: datumIndex,
|
|
series: this,
|
|
itemType: seriesItemType,
|
|
datum,
|
|
datumIndex,
|
|
cumulativeValue: cumulativeValue ?? 0,
|
|
xValue: xDatum,
|
|
yValue: value,
|
|
yKey,
|
|
xKey,
|
|
x: 0,
|
|
y: 0,
|
|
width: 0,
|
|
height: 0,
|
|
midPoint: { x: 0, y: 0 },
|
|
crisp,
|
|
label: { text: "", x: 0, y: 0, textAlign: "center", textBaseline: "middle" }
|
|
};
|
|
}
|
|
/**
|
|
* Updates an existing WaterfallNodeDatum in-place.
|
|
* This is more efficient than recreating the entire node when only data values change.
|
|
*/
|
|
updateNodeDatum(ctx, node, params) {
|
|
const { xScale, yScale, barAlongX, barWidth, valueAxisReversed, xKey, yKey, xName, yName, yDomain, crisp } = ctx;
|
|
const { datumIndex, datum, xDatum, value, cumulativeValue, trailingValue, datumType } = params;
|
|
const mutableNode = node;
|
|
const x = Math.round(xScale.convert(xDatum));
|
|
if (!Number.isFinite(x))
|
|
return;
|
|
const isPositive = (value ?? 0) >= 0;
|
|
const seriesItemType = this.getSeriesItemType(isPositive, datumType);
|
|
const { strokeWidth, label } = this.getItemConfig(seriesItemType);
|
|
const currY = Math.round(yScale.convert(cumulativeValue));
|
|
const trailY = Math.round(yScale.convert(trailingValue));
|
|
const y = isPositive ? currY : trailY;
|
|
const bottomY = isPositive ? trailY : currY;
|
|
const barHeight = Math.max(strokeWidth, Math.abs(bottomY - y));
|
|
const rectX = barAlongX ? Math.min(y, bottomY) : x;
|
|
const rectY = barAlongX ? x : Math.min(y, bottomY);
|
|
const rectWidth = barAlongX ? barHeight : barWidth;
|
|
const rectHeight = barAlongX ? barWidth : barHeight;
|
|
mutableNode.index = datumIndex;
|
|
mutableNode.itemType = seriesItemType;
|
|
mutableNode.datum = datum;
|
|
mutableNode.datumIndex = datumIndex;
|
|
mutableNode.cumulativeValue = cumulativeValue ?? 0;
|
|
mutableNode.xValue = xDatum;
|
|
mutableNode.yValue = value;
|
|
mutableNode.x = rectX;
|
|
mutableNode.y = rectY;
|
|
mutableNode.width = rectWidth;
|
|
mutableNode.height = rectHeight;
|
|
mutableNode.crisp = crisp;
|
|
if (mutableNode.midPoint) {
|
|
mutableNode.midPoint.x = rectX + rectWidth / 2;
|
|
mutableNode.midPoint.y = rectY + rectHeight / 2;
|
|
} else {
|
|
mutableNode.midPoint = { x: rectX + rectWidth / 2, y: rectY + rectHeight / 2 };
|
|
}
|
|
if (label.enabled) {
|
|
const itemType = seriesItemType === "subtotal" ? "total" : seriesItemType;
|
|
const labelText = this.getLabelText(
|
|
value,
|
|
datum,
|
|
yKey,
|
|
"y",
|
|
yDomain,
|
|
label,
|
|
{
|
|
itemType,
|
|
value,
|
|
datum,
|
|
xKey,
|
|
yKey,
|
|
xName,
|
|
yName
|
|
}
|
|
);
|
|
const spacing = label.spacing + (typeof label.padding === "number" ? label.padding : 0);
|
|
const labelPlacement = adjustLabelPlacement({
|
|
isUpward: (value ?? -1) >= 0 !== valueAxisReversed,
|
|
isVertical: !barAlongX,
|
|
placement: label.placement,
|
|
spacing,
|
|
rect: { x: rectX, y: rectY, width: rectWidth, height: rectHeight }
|
|
});
|
|
mutableNode.label.text = labelText;
|
|
mutableNode.label.x = labelPlacement.x;
|
|
mutableNode.label.y = labelPlacement.y;
|
|
mutableNode.label.textAlign = labelPlacement.textAlign;
|
|
mutableNode.label.textBaseline = labelPlacement.textBaseline;
|
|
} else {
|
|
mutableNode.label.text = "";
|
|
}
|
|
}
|
|
/**
|
|
* Creates a WaterfallNodeDatum for a single data point.
|
|
* Creates a skeleton node and uses updateNodeDatum to populate it.
|
|
*/
|
|
createNodeDatum(ctx, params) {
|
|
const node = this.createSkeletonNodeDatum(ctx, params);
|
|
this.updateNodeDatum(ctx, node, params);
|
|
return node;
|
|
}
|
|
createPointDatum(ctx, nodeDatum, cumulativeValue, trailingValue, isTotalOrSubtotal) {
|
|
const { yScale, barAlongX, categoryAxisReversed, lineStrokeWidth } = ctx;
|
|
const currY = Math.round(yScale.convert(cumulativeValue));
|
|
const trailY = Math.round(yScale.convert(trailingValue));
|
|
const pointY = isTotalOrSubtotal ? currY : trailY;
|
|
const pixelAlignmentOffset = Math.floor(lineStrokeWidth) % 2 / 2;
|
|
const startY = categoryAxisReversed ? currY : pointY;
|
|
const stopY = categoryAxisReversed ? pointY : currY;
|
|
const rect = { x: nodeDatum.x, y: nodeDatum.y, width: nodeDatum.width, height: nodeDatum.height };
|
|
let startCoordinates;
|
|
let stopCoordinates;
|
|
if (barAlongX) {
|
|
startCoordinates = {
|
|
x: startY + pixelAlignmentOffset,
|
|
y: rect.y
|
|
};
|
|
stopCoordinates = {
|
|
x: stopY + pixelAlignmentOffset,
|
|
y: rect.y + rect.height
|
|
};
|
|
} else {
|
|
startCoordinates = {
|
|
x: rect.x,
|
|
y: startY + pixelAlignmentOffset
|
|
};
|
|
stopCoordinates = {
|
|
x: rect.x + rect.width,
|
|
y: stopY + pixelAlignmentOffset
|
|
};
|
|
}
|
|
return {
|
|
// lineTo
|
|
x: categoryAxisReversed ? stopCoordinates.x : startCoordinates.x,
|
|
y: categoryAxisReversed ? stopCoordinates.y : startCoordinates.y,
|
|
// moveTo
|
|
x2: categoryAxisReversed ? startCoordinates.x : stopCoordinates.x,
|
|
y2: categoryAxisReversed ? startCoordinates.y : stopCoordinates.y,
|
|
size: 0
|
|
};
|
|
}
|
|
updateSeriesItemTypes() {
|
|
const { dataModel, seriesItemTypes, processedData } = this;
|
|
if (!dataModel || !processedData) {
|
|
return;
|
|
}
|
|
seriesItemTypes.clear();
|
|
const yPositiveIndex = dataModel.resolveProcessedDataIndexById(this, "yCurrentPositive");
|
|
const yNegativeIndex = dataModel.resolveProcessedDataIndexById(this, "yCurrentNegative");
|
|
const totalTypeIndex = dataModel.resolveProcessedDataIndexById(this, `totalTypeValue`);
|
|
const positiveDomain = processedData.domain.values[yPositiveIndex] ?? [];
|
|
const negativeDomain = processedData.domain.values[yNegativeIndex] ?? [];
|
|
if (positiveDomain.length > 0) {
|
|
seriesItemTypes.add("positive");
|
|
}
|
|
if (negativeDomain.length > 0) {
|
|
seriesItemTypes.add("negative");
|
|
}
|
|
const itemTypes = processedData?.domain.values[totalTypeIndex];
|
|
if (!itemTypes) {
|
|
return;
|
|
}
|
|
for (const type of itemTypes) {
|
|
if (type === "total" || type === "subtotal") {
|
|
seriesItemTypes.add("total");
|
|
}
|
|
}
|
|
}
|
|
isSubtotal(datumType) {
|
|
return datumType === "subtotal";
|
|
}
|
|
isTotal(datumType) {
|
|
return datumType === "total";
|
|
}
|
|
nodeFactory() {
|
|
return new Rect3();
|
|
}
|
|
getSeriesItemType(isPositive, datumType) {
|
|
return datumType ?? (isPositive ? "positive" : "negative");
|
|
}
|
|
getItemConfig(seriesItemType) {
|
|
switch (seriesItemType) {
|
|
case "positive": {
|
|
return this.properties.item.positive;
|
|
}
|
|
case "negative": {
|
|
return this.properties.item.negative;
|
|
}
|
|
case "subtotal":
|
|
case "total": {
|
|
return this.properties.item.total;
|
|
}
|
|
}
|
|
}
|
|
updateDatumSelection(opts) {
|
|
const { nodeData, datumSelection } = opts;
|
|
const data = nodeData ?? [];
|
|
if (!processedDataIsAnimatable5(this.processedData)) {
|
|
return datumSelection.update(data);
|
|
}
|
|
return datumSelection.update(data, void 0, (datum) => createDatumId6(datum.datumIndex));
|
|
}
|
|
getItemStyle(nodeDatum, isHighlight, highlightState, itemType = "total") {
|
|
const { properties } = this;
|
|
const { datumIndex = 0, datum } = nodeDatum ?? {};
|
|
const propertyItemId = itemType === "subtotal" ? "total" : itemType;
|
|
const item = properties.item[propertyItemId];
|
|
const highlightStyle = this.getHighlightStyle(isHighlight, datumIndex, highlightState);
|
|
const baseStyle = mergeDefaults9(highlightStyle, properties.getStyle(itemType));
|
|
const { itemStyler } = item;
|
|
let style = baseStyle;
|
|
if (itemStyler != null && nodeDatum != null) {
|
|
const overrides = this.cachedDatumCallback(
|
|
createDatumId6(datumIndex, isHighlight ? "highlight" : "node"),
|
|
() => {
|
|
const params = this.makeItemStylerParams(itemType, datumIndex, datum, isHighlight, style);
|
|
return this.ctx.optionsGraphService.resolvePartial(
|
|
["series", `${this.declarationOrder}`, "item", propertyItemId],
|
|
this.callWithContext(itemStyler, params)
|
|
);
|
|
}
|
|
);
|
|
if (overrides) {
|
|
style = mergeDefaults9(overrides, style);
|
|
}
|
|
}
|
|
return style;
|
|
}
|
|
makeItemStylerParams(itemType, datumIndex, datum, isHighlight, style) {
|
|
const { id: seriesId, properties } = this;
|
|
const { xKey, yKey } = properties;
|
|
const activeHighlight = this.ctx.highlightManager?.getActiveHighlight();
|
|
const highlightStateString = this.getHighlightStateString(activeHighlight, isHighlight, datumIndex);
|
|
const fill = this.filterItemStylerFillParams(style.fill) ?? style.fill;
|
|
return {
|
|
seriesId,
|
|
itemType,
|
|
datum,
|
|
xKey,
|
|
yKey,
|
|
highlightState: highlightStateString,
|
|
...style,
|
|
fill
|
|
};
|
|
}
|
|
updateDatumStyles({
|
|
datumSelection,
|
|
isHighlight
|
|
}) {
|
|
datumSelection.each((_, datum) => {
|
|
datum.style = this.getItemStyle(datum, isHighlight, void 0, datum.itemType);
|
|
});
|
|
}
|
|
updateDatumNodes({
|
|
datumSelection,
|
|
isHighlight
|
|
}) {
|
|
const { contextNodeData } = this;
|
|
if (!contextNodeData) {
|
|
return;
|
|
}
|
|
const highlightedDatum = this.ctx.highlightManager.getActiveHighlight();
|
|
const categoryAlongX = this.getCategoryDirection() === ChartAxisDirection26.X;
|
|
const fillBBox = this.getShapeFillBBox();
|
|
datumSelection.each((rect, datum) => {
|
|
const style = datum.style ?? contextNodeData.styles[datum.itemType][this.getHighlightState(highlightedDatum, isHighlight, datum.datumIndex)];
|
|
rect.setStyleProperties(style, fillBBox);
|
|
rect.cornerRadius = style.cornerRadius ?? 0;
|
|
rect.visible = categoryAlongX ? datum.width > 0 : datum.height > 0;
|
|
rect.crisp = datum.crisp;
|
|
});
|
|
}
|
|
updateLabelSelection(opts) {
|
|
const { labelData, labelSelection } = opts;
|
|
if (labelData.length === 0) {
|
|
return labelSelection.update([]);
|
|
}
|
|
const data = labelData.filter((labelDatum) => {
|
|
const { label } = this.getItemConfig(labelDatum.itemType);
|
|
return label.enabled;
|
|
});
|
|
return labelSelection.update(data);
|
|
}
|
|
updateLabelNodes({
|
|
labelSelection,
|
|
isHighlight
|
|
}) {
|
|
const params = {
|
|
itemType: "positive",
|
|
xKey: this.properties.xKey,
|
|
xName: this.properties.xName ?? this.properties.xName,
|
|
yKey: this.properties.yKey,
|
|
yName: this.properties.yName ?? this.properties.yName
|
|
};
|
|
const activeHighlight = this.ctx.highlightManager?.getActiveHighlight();
|
|
labelSelection.each((textNode, datum) => {
|
|
params.itemType = datum.itemType;
|
|
const styleOpacity = this.getHighlightStyle(isHighlight, datum.datumIndex)?.opacity ?? 1;
|
|
textNode.visible = true;
|
|
textNode.fillOpacity = styleOpacity;
|
|
const label = this.getItemConfig(datum.itemType).label;
|
|
updateLabelNode4(this, textNode, params, label, datum.label, isHighlight, activeHighlight);
|
|
});
|
|
}
|
|
getTooltipContent(datumIndex) {
|
|
const { id: seriesId, dataModel, processedData, properties } = this;
|
|
const { xKey, xName, yKey, yName, tooltip, legendItemName } = properties;
|
|
const xAxis = this.getCategoryAxis();
|
|
const yAxis = this.getValueAxis();
|
|
if (!dataModel || !processedData || !xAxis || !yAxis)
|
|
return;
|
|
const datum = processedData.dataSources.get(this.id)?.data[datumIndex];
|
|
const xValue = dataModel.resolveKeysById(this, `xValue`, processedData)[datumIndex];
|
|
const yValue = dataModel.resolveColumnById(this, `yRaw`, processedData)[datumIndex];
|
|
const yCurrTotalValues = dataModel.resolveColumnById(this, "yCurrentTotal", processedData);
|
|
const totalTypeValues = dataModel.resolveColumnById(
|
|
this,
|
|
`totalTypeValue`,
|
|
processedData
|
|
);
|
|
const allowNullKeys = this.properties.allowNullKeys ?? false;
|
|
if (xValue === void 0 && !allowNullKeys)
|
|
return;
|
|
const datumType = totalTypeValues[datumIndex];
|
|
const isPositive = (yValue ?? 0) >= 0;
|
|
const seriesItemType = this.getSeriesItemType(isPositive, datumType);
|
|
let total;
|
|
if (this.isTotal(datumType)) {
|
|
total = yCurrTotalValues[datumIndex];
|
|
} else if (this.isSubtotal(datumType)) {
|
|
total = yCurrTotalValues[datumIndex];
|
|
for (let previousIndex = datumIndex - 1; previousIndex >= 0; previousIndex -= 1) {
|
|
if (this.isSubtotal(totalTypeValues[previousIndex])) {
|
|
total = total - yCurrTotalValues[previousIndex];
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
total = yValue;
|
|
}
|
|
const nodeDatum = this.contextNodeData?.nodeData?.[datumIndex];
|
|
const format = this.getItemStyle(nodeDatum, false, void 0, nodeDatum?.itemType);
|
|
return this.formatTooltipWithContext(
|
|
tooltip,
|
|
{
|
|
heading: this.getAxisValueText(xAxis, "tooltip", xValue, datum, xKey, legendItemName),
|
|
symbol: this.legendItemSymbol(seriesItemType),
|
|
data: [
|
|
{
|
|
label: yName,
|
|
fallbackLabel: yKey,
|
|
value: this.getAxisValueText(yAxis, "tooltip", total, datum, yKey, legendItemName),
|
|
missing: _ModuleSupport116.isTooltipValueMissing(total)
|
|
}
|
|
]
|
|
},
|
|
{ seriesId, datum, title: yName, itemType: seriesItemType, xKey, xName, yKey, yName, ...format }
|
|
);
|
|
}
|
|
legendItemSymbol(item) {
|
|
const { fill, stroke: stroke3, fillOpacity, strokeOpacity, strokeWidth, lineDash, lineDashOffset } = this.getItemConfig(item);
|
|
return {
|
|
marker: {
|
|
fill,
|
|
stroke: stroke3,
|
|
fillOpacity,
|
|
strokeOpacity,
|
|
strokeWidth,
|
|
lineDash,
|
|
lineDashOffset
|
|
}
|
|
};
|
|
}
|
|
getLegendData(legendType) {
|
|
if (legendType !== "category") {
|
|
return [];
|
|
}
|
|
const { id, seriesItemTypes } = this;
|
|
const legendData = [];
|
|
const capitalise = (text2) => text2.charAt(0).toUpperCase() + text2.substring(1);
|
|
const { showInLegend } = this.properties;
|
|
for (const item of seriesItemTypes) {
|
|
const { name } = this.getItemConfig(item);
|
|
legendData.push({
|
|
legendType: "category",
|
|
id,
|
|
itemId: createDatumId6(item),
|
|
seriesId: id,
|
|
enabled: true,
|
|
label: { text: name ?? capitalise(item) },
|
|
symbol: this.legendItemSymbol(item),
|
|
hideInLegend: !showInLegend,
|
|
isFixed: true
|
|
});
|
|
}
|
|
return legendData;
|
|
}
|
|
toggleSeriesItem() {
|
|
}
|
|
resetDatumAnimation(data) {
|
|
resetBarSelectionsDirect2([data.datumSelection]);
|
|
}
|
|
animateEmptyUpdateReady(opts) {
|
|
const { datumSelection, labelSelection, contextData } = opts;
|
|
const fns = prepareBarAnimationFunctions2(
|
|
collapsedStartingBarPosition(this.isVertical(), this.axes, "normal"),
|
|
"unknown"
|
|
);
|
|
motion3.fromToMotion(this.id, "datums", this.ctx.animationManager, [datumSelection], fns);
|
|
seriesLabelFadeInAnimation3(this, "labels", this.ctx.animationManager, labelSelection);
|
|
const { pointData } = contextData;
|
|
if (!pointData)
|
|
return;
|
|
if (this.isVertical()) {
|
|
this.animateConnectorLinesVertical(opts);
|
|
} else {
|
|
this.animateConnectorLinesHorizontal(opts);
|
|
}
|
|
}
|
|
animateConnectorLinesHorizontal(opts) {
|
|
const { pointData = [] } = opts.contextData;
|
|
const [lineNode] = opts.paths;
|
|
const { path: linePath } = lineNode;
|
|
this.updateLineNode(lineNode);
|
|
const valueAxis = this.getValueAxis();
|
|
const valueAxisReversed = valueAxis?.isReversed();
|
|
const compare = valueAxisReversed ? (v, v2) => v < v2 : (v, v2) => v > v2;
|
|
const startX = valueAxis?.scale.convert(0);
|
|
const endX = pointData.reduce(
|
|
(end, point) => {
|
|
if (compare(point.x, end)) {
|
|
end = point.x;
|
|
}
|
|
return end;
|
|
},
|
|
valueAxisReversed ? Infinity : 0
|
|
);
|
|
const scale = (value, start1, end1, start2, end2) => {
|
|
return (value - start1) / (end1 - start1) * (end2 - start2) + start2;
|
|
};
|
|
this.ctx.animationManager.animate({
|
|
id: `${this.id}_connectors`,
|
|
groupId: this.id,
|
|
phase: "initial",
|
|
from: startX,
|
|
to: endX,
|
|
ease: easeOut,
|
|
collapsable: false,
|
|
onUpdate(pointX) {
|
|
linePath.clear(true);
|
|
for (const [index, point] of pointData.entries()) {
|
|
const x = scale(pointX, startX, endX, startX, point.x);
|
|
const x2 = scale(pointX, startX, endX, startX, point.x2);
|
|
if (index !== 0) {
|
|
linePath.lineTo(x, point.y);
|
|
}
|
|
linePath.moveTo(x2, point.y2);
|
|
}
|
|
lineNode.checkPathDirty();
|
|
},
|
|
onStop: () => this.resetConnectorLinesPath(opts)
|
|
});
|
|
}
|
|
animateConnectorLinesVertical(opts) {
|
|
const { pointData = [] } = opts.contextData;
|
|
const [lineNode] = opts.paths;
|
|
const { path: linePath } = lineNode;
|
|
this.updateLineNode(lineNode);
|
|
const valueAxis = this.getValueAxis();
|
|
const valueAxisReversed = valueAxis?.isReversed();
|
|
const compare = valueAxisReversed ? (v, v2) => v > v2 : (v, v2) => v < v2;
|
|
const startY = valueAxis?.scale.convert(0);
|
|
const endY = pointData.reduce(
|
|
(end, point) => {
|
|
if (compare(point.y, end)) {
|
|
end = point.y;
|
|
}
|
|
return end;
|
|
},
|
|
valueAxisReversed ? 0 : Infinity
|
|
);
|
|
const scale = (value, start1, end1, start2, end2) => {
|
|
return (value - start1) / (end1 - start1) * (end2 - start2) + start2;
|
|
};
|
|
this.ctx.animationManager.animate({
|
|
id: `${this.id}_connectors`,
|
|
groupId: this.id,
|
|
phase: "initial",
|
|
from: startY,
|
|
to: endY,
|
|
ease: easeOut,
|
|
collapsable: false,
|
|
onUpdate(pointY) {
|
|
linePath.clear(true);
|
|
for (const [index, point] of pointData.entries()) {
|
|
const y = scale(pointY, startY, endY, startY, point.y);
|
|
const y2 = scale(pointY, startY, endY, startY, point.y2);
|
|
if (index !== 0) {
|
|
linePath.lineTo(point.x, y);
|
|
}
|
|
linePath.moveTo(point.x2, y2);
|
|
}
|
|
lineNode.checkPathDirty();
|
|
},
|
|
onStop: () => this.resetConnectorLinesPath(opts)
|
|
});
|
|
}
|
|
animateReadyResize(data) {
|
|
super.animateReadyResize(data);
|
|
this.resetConnectorLinesPath(data);
|
|
}
|
|
updatePaths(opts) {
|
|
this.resetConnectorLinesPath({ contextData: opts.contextData, paths: opts.paths });
|
|
}
|
|
resetConnectorLinesPath({
|
|
contextData,
|
|
paths
|
|
}) {
|
|
if (paths.length === 0) {
|
|
return;
|
|
}
|
|
const [lineNode] = paths;
|
|
this.updateLineNode(lineNode);
|
|
const { path: linePath } = lineNode;
|
|
linePath.clear(true);
|
|
const { pointData } = contextData;
|
|
if (!pointData) {
|
|
return;
|
|
}
|
|
for (const [index, point] of pointData.entries()) {
|
|
if (index !== 0) {
|
|
linePath.lineTo(point.x, point.y);
|
|
}
|
|
linePath.moveTo(point.x2, point.y2);
|
|
}
|
|
lineNode.checkPathDirty();
|
|
}
|
|
updateLineNode(lineNode) {
|
|
const { stroke: stroke3, strokeWidth, strokeOpacity, lineDash, lineDashOffset } = this.properties.line;
|
|
lineNode.setProperties({
|
|
fill: void 0,
|
|
stroke: stroke3,
|
|
strokeWidth,
|
|
strokeOpacity,
|
|
lineDash,
|
|
lineDashOffset,
|
|
lineJoin: "round",
|
|
pointerEvents: _ModuleSupport116.PointerEvents.None
|
|
});
|
|
}
|
|
isLabelEnabled() {
|
|
const { positive, negative, total } = this.properties.item;
|
|
return positive.label.enabled || negative.label.enabled || total.label.enabled;
|
|
}
|
|
computeFocusBounds({ datumIndex }) {
|
|
return computeBarFocusBounds5(this, this.contextNodeData?.nodeData[datumIndex]);
|
|
}
|
|
hasItemStylers() {
|
|
const { positive, negative, total } = this.properties.item;
|
|
return positive.itemStyler != null || positive.label.itemStyler != null || negative.itemStyler != null || negative.label.itemStyler != null || total.itemStyler != null || total.label.itemStyler != null;
|
|
}
|
|
};
|
|
WaterfallSeries.className = "WaterfallSeries";
|
|
WaterfallSeries.type = "waterfall";
|
|
|
|
// packages/ag-charts-enterprise/src/series/waterfall/waterfallSeriesOptionsDef.ts
|
|
import { _ModuleSupport as _ModuleSupport117 } from "ag-charts-community";
|
|
import {
|
|
arrayOfDefs,
|
|
commonSeriesOptionsDefs as commonSeriesOptionsDefs7,
|
|
constant as constant7,
|
|
positiveNumber as positiveNumber4,
|
|
positiveNumberNonZero as positiveNumberNonZero3,
|
|
required as required7,
|
|
string as string7,
|
|
union
|
|
} from "ag-charts-core";
|
|
var { waterfallSeriesThemeableOptionsDef } = _ModuleSupport117;
|
|
var waterfallSeriesOptionsDef = {
|
|
...waterfallSeriesThemeableOptionsDef,
|
|
...commonSeriesOptionsDefs7,
|
|
type: required7(constant7("waterfall")),
|
|
xKey: required7(string7),
|
|
yKey: required7(string7),
|
|
xKeyAxis: string7,
|
|
yKeyAxis: string7,
|
|
xName: string7,
|
|
yName: string7,
|
|
totals: arrayOfDefs(
|
|
{
|
|
totalType: required7(union("total", "subtotal")),
|
|
index: required7(positiveNumber4),
|
|
axisLabel: required7(string7)
|
|
},
|
|
"a total definition options array"
|
|
),
|
|
width: positiveNumberNonZero3
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/series/waterfall/waterfallThemes.ts
|
|
import "ag-charts-community";
|
|
import {
|
|
FILL_GRADIENT_LINEAR_KEYED_DEFAULTS as FILL_GRADIENT_LINEAR_KEYED_DEFAULTS2,
|
|
FILL_IMAGE_DEFAULTS as FILL_IMAGE_DEFAULTS5,
|
|
FILL_PATTERN_KEYED_DEFAULTS as FILL_PATTERN_KEYED_DEFAULTS2,
|
|
LABEL_BOXING_DEFAULTS as LABEL_BOXING_DEFAULTS4,
|
|
SINGLE_SERIES_HIGHLIGHT_STYLE
|
|
} from "ag-charts-core";
|
|
function itemTheme2(key, index) {
|
|
return {
|
|
fill: {
|
|
$applySwitch: [
|
|
{ $path: "type" },
|
|
{
|
|
$if: [
|
|
{ $eq: [{ $palette: "type" }, "user-indexed"] },
|
|
{ $path: [`/${index}`, { $palette: "fill" }, { $palette: "fills" }] },
|
|
{ $palette: `${key}.fill` }
|
|
]
|
|
},
|
|
["gradient", FILL_GRADIENT_LINEAR_KEYED_DEFAULTS2(key)],
|
|
["image", FILL_IMAGE_DEFAULTS5],
|
|
["pattern", FILL_PATTERN_KEYED_DEFAULTS2(key)]
|
|
]
|
|
},
|
|
stroke: { $palette: `${key}.stroke` },
|
|
strokeWidth: { $isUserOption: ["./stroke", 2, 0] },
|
|
label: {
|
|
...LABEL_BOXING_DEFAULTS4,
|
|
enabled: false,
|
|
fontStyle: void 0,
|
|
fontWeight: { $ref: "fontWeight" },
|
|
fontSize: { $ref: "fontSize" },
|
|
fontFamily: { $ref: "fontFamily" },
|
|
color: { $ref: "textColor" },
|
|
formatter: void 0,
|
|
placement: "outside-end",
|
|
padding: { $isUserOption: ["./spacing", 0, 6] }
|
|
// compatibility with old `padding` property (now named `spacing`).
|
|
}
|
|
};
|
|
}
|
|
var WATERFALL_SERIES_THEME = {
|
|
series: {
|
|
item: {
|
|
positive: itemTheme2("altUp", 0),
|
|
negative: itemTheme2("altDown", 1),
|
|
total: itemTheme2("neutral", 2)
|
|
},
|
|
line: {
|
|
stroke: { $palette: "neutral.stroke" },
|
|
strokeOpacity: 1,
|
|
lineDash: [0],
|
|
lineDashOffset: 0,
|
|
strokeWidth: 2
|
|
},
|
|
highlight: SINGLE_SERIES_HIGHLIGHT_STYLE
|
|
},
|
|
legend: {
|
|
enabled: true,
|
|
toggleSeries: false
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/series/waterfall/waterfallModule.ts
|
|
var WaterfallSeriesModule = {
|
|
type: "series",
|
|
name: "waterfall",
|
|
chartType: "cartesian",
|
|
enterprise: true,
|
|
solo: true,
|
|
version: VERSION21,
|
|
dependencies: [CartesianChartModule7],
|
|
options: waterfallSeriesOptionsDef,
|
|
defaultAxes: DIRECTION_SWAP_AXES3,
|
|
axisKeys: { [ChartAxisDirection27.X]: "xKeyAxis", [ChartAxisDirection27.Y]: "yKeyAxis" },
|
|
axisKeysFlipped: { [ChartAxisDirection27.X]: "yKeyAxis", [ChartAxisDirection27.Y]: "xKeyAxis" },
|
|
themeTemplate: WATERFALL_SERIES_THEME,
|
|
create: (ctx) => new WaterfallSeries(ctx)
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/navigator/navigatorOptionsDefs.ts
|
|
var navigatorHandleOptionsDef = {
|
|
width: positiveNumber5,
|
|
height: positiveNumber5,
|
|
grip: boolean11,
|
|
fill: color3,
|
|
stroke: color3,
|
|
strokeWidth: positiveNumber5,
|
|
cornerRadius: positiveNumber5
|
|
};
|
|
var commonIgnoredMiniChartProperties = [
|
|
"cursor",
|
|
"highlightStyle",
|
|
"listeners",
|
|
"nodeClickRange",
|
|
"showInLegend",
|
|
"showInMiniChart",
|
|
"tooltip",
|
|
"visible",
|
|
"xName",
|
|
"yName"
|
|
];
|
|
var barIgnoredMiniChartProperties = [
|
|
...commonIgnoredMiniChartProperties,
|
|
"errorBar",
|
|
"label",
|
|
"legendItemName"
|
|
];
|
|
var boxPlotIngnoredMiniChartProperties = [
|
|
...commonIgnoredMiniChartProperties,
|
|
"direction",
|
|
"legendItemName",
|
|
"minName",
|
|
"q1Name",
|
|
"medianName",
|
|
"q3Name",
|
|
"maxName"
|
|
];
|
|
var bubbleIgnoredMiniChartProperties = [
|
|
...commonIgnoredMiniChartProperties,
|
|
"title",
|
|
"label",
|
|
"labelKey",
|
|
"labelName",
|
|
"sizeName"
|
|
];
|
|
var heatmapIgnoredMiniChartProperties = [
|
|
...commonIgnoredMiniChartProperties,
|
|
"title",
|
|
"label",
|
|
"colorName",
|
|
"textAlign",
|
|
"verticalAlign",
|
|
"itemPadding",
|
|
"colorRange"
|
|
];
|
|
var histogramIgnoredMiniChartProperties = [
|
|
...commonIgnoredMiniChartProperties,
|
|
"label"
|
|
];
|
|
var lineIgnoredMiniChartProperties = [
|
|
...commonIgnoredMiniChartProperties,
|
|
"errorBar",
|
|
"title",
|
|
"label"
|
|
];
|
|
var rangeAreaIgnoredMiniChartProperties = [
|
|
...commonIgnoredMiniChartProperties,
|
|
"label",
|
|
"yLowName",
|
|
"yHighName"
|
|
];
|
|
var rangeBarIgnoredMiniChartProperties = [
|
|
...commonIgnoredMiniChartProperties,
|
|
"direction",
|
|
"label",
|
|
"yLowName",
|
|
"yHighName"
|
|
];
|
|
var scatterIgnoredMiniChartProperties = [
|
|
...commonIgnoredMiniChartProperties,
|
|
"errorBar",
|
|
"title",
|
|
"label",
|
|
"labelKey",
|
|
"labelName"
|
|
];
|
|
var waterfallIgnoredMiniChartProperties = [
|
|
...commonIgnoredMiniChartProperties,
|
|
"direction"
|
|
];
|
|
var navigatorOptionsDef = {
|
|
enabled: boolean11,
|
|
height: positiveNumber5,
|
|
spacing: positiveNumber5,
|
|
cornerRadius: number5,
|
|
mask: {
|
|
fill: color3,
|
|
fillOpacity: ratio4,
|
|
stroke: color3,
|
|
strokeWidth: positiveNumber5
|
|
},
|
|
minHandle: navigatorHandleOptionsDef,
|
|
maxHandle: navigatorHandleOptionsDef,
|
|
miniChart: {
|
|
enabled: boolean11,
|
|
padding: {
|
|
top: positiveNumber5,
|
|
bottom: positiveNumber5
|
|
},
|
|
label: {
|
|
enabled: boolean11,
|
|
avoidCollisions: boolean11,
|
|
spacing: positiveNumber5,
|
|
format: numberFormatValidator,
|
|
formatter: callbackOf2(textOrSegments),
|
|
interval: {
|
|
minSpacing: positiveNumber5,
|
|
maxSpacing: positiveNumber5,
|
|
values: array,
|
|
step: number5
|
|
},
|
|
...fontOptionsDef
|
|
},
|
|
series: arrayOfDefs2(
|
|
typeUnion(
|
|
{
|
|
area: without2(AreaSeriesModule.options, [...commonIgnoredMiniChartProperties, "type"]),
|
|
bar: without2(BarSeriesModule.options, [...barIgnoredMiniChartProperties, "type"]),
|
|
"box-plot": without2(BoxPlotSeriesModule.options, [...boxPlotIngnoredMiniChartProperties, "type"]),
|
|
bubble: without2(BubbleSeriesModule.options, [...bubbleIgnoredMiniChartProperties, "type"]),
|
|
candlestick: without2(CandlestickSeriesModule.options, [
|
|
...commonIgnoredMiniChartProperties,
|
|
"type"
|
|
]),
|
|
heatmap: without2(HeatmapSeriesModule.options, [...heatmapIgnoredMiniChartProperties, "type"]),
|
|
histogram: without2(HistogramSeriesModule.options, [...histogramIgnoredMiniChartProperties, "type"]),
|
|
line: without2(LineSeriesModule.options, [...lineIgnoredMiniChartProperties, "type"]),
|
|
ohlc: without2(OhlcSeriesModule.options, [...commonIgnoredMiniChartProperties, "type"]),
|
|
"range-area": without2(RangeAreaSeriesModule.options, [
|
|
...rangeAreaIgnoredMiniChartProperties,
|
|
"type"
|
|
]),
|
|
"range-bar": without2(RangeBarSeriesModule.options, [...rangeBarIgnoredMiniChartProperties, "type"]),
|
|
scatter: without2(ScatterSeriesModule.options, [...scatterIgnoredMiniChartProperties, "type"]),
|
|
waterfall: without2(WaterfallSeriesModule.options, [...waterfallIgnoredMiniChartProperties, "type"])
|
|
},
|
|
"miniChart series options"
|
|
)
|
|
)
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/navigator/navigatorTheme.ts
|
|
import "ag-charts-community";
|
|
import { FONT_SIZE_RATIO as FONT_SIZE_RATIO2 } from "ag-charts-core";
|
|
var validMiniChartSeriesTypes = [
|
|
"area",
|
|
"bar",
|
|
"bubble",
|
|
"candlestick",
|
|
"heatmap",
|
|
"histogram",
|
|
"line",
|
|
"ohlc",
|
|
"range-area",
|
|
"range-bar",
|
|
"scatter",
|
|
"waterfall"
|
|
];
|
|
var priceVolumePresetIgnoredMiniChartProperties = [
|
|
"itemStyler",
|
|
"simpleItemStyler",
|
|
"direction",
|
|
"fill",
|
|
"fillGradientDefaults",
|
|
"fillPatternDefaults",
|
|
"fillImageDefaults",
|
|
"fillOpacity",
|
|
"shadow",
|
|
"focusPriority",
|
|
"highlight",
|
|
"lineDash",
|
|
"lineDashOffset",
|
|
"strokeWidth"
|
|
];
|
|
function miniChartSeriesTheme(seriesPath, typePath) {
|
|
return {
|
|
$merge: [
|
|
{
|
|
$switch: [
|
|
typePath,
|
|
{},
|
|
[
|
|
["area", "line", "range-area"],
|
|
{
|
|
marker: {
|
|
enabled: {
|
|
$isUserOption: [
|
|
"/series/$index/marker/enabled",
|
|
{ $path: ["/series/$index/marker/enabled", false] },
|
|
false
|
|
]
|
|
}
|
|
}
|
|
}
|
|
]
|
|
]
|
|
},
|
|
{
|
|
$omit: [
|
|
{
|
|
$switch: [
|
|
typePath,
|
|
commonIgnoredMiniChartProperties,
|
|
["bar", barIgnoredMiniChartProperties],
|
|
["box-plot", boxPlotIngnoredMiniChartProperties],
|
|
["bubble", bubbleIgnoredMiniChartProperties],
|
|
["heatmap", heatmapIgnoredMiniChartProperties],
|
|
["histogram", histogramIgnoredMiniChartProperties],
|
|
[
|
|
"line",
|
|
[...lineIgnoredMiniChartProperties, ...priceVolumePresetIgnoredMiniChartProperties]
|
|
],
|
|
["range-area", rangeAreaIgnoredMiniChartProperties],
|
|
["range-bar", rangeBarIgnoredMiniChartProperties],
|
|
["scatter", scatterIgnoredMiniChartProperties],
|
|
["waterfall", waterfallIgnoredMiniChartProperties]
|
|
]
|
|
},
|
|
seriesPath
|
|
]
|
|
}
|
|
]
|
|
};
|
|
}
|
|
var NAVIGATOR_THEME = {
|
|
enabled: false,
|
|
height: { $if: [{ $path: "./miniChart/enabled" }, 40, 18] },
|
|
cornerRadius: 4,
|
|
mask: {
|
|
fill: { $ref: "foregroundColor" },
|
|
fillOpacity: 0.1,
|
|
stroke: { $ref: "borderColor" },
|
|
strokeWidth: 1
|
|
},
|
|
minHandle: {
|
|
fill: { $ref: "chartBackgroundColor" },
|
|
stroke: { $ref: "borderColor" },
|
|
strokeWidth: 1,
|
|
width: 12,
|
|
height: 24,
|
|
cornerRadius: 4
|
|
},
|
|
maxHandle: {
|
|
fill: { $ref: "chartBackgroundColor" },
|
|
stroke: { $ref: "borderColor" },
|
|
strokeWidth: 1,
|
|
width: 12,
|
|
height: 24,
|
|
cornerRadius: 4
|
|
},
|
|
miniChart: {
|
|
enabled: false,
|
|
label: {
|
|
color: { $ref: "textColor" },
|
|
fontSize: { $rem: FONT_SIZE_RATIO2.SMALLER },
|
|
fontFamily: { $ref: "fontFamily" },
|
|
fontWeight: { $ref: "fontWeight" },
|
|
spacing: 5
|
|
},
|
|
padding: {
|
|
top: 0,
|
|
bottom: 0
|
|
},
|
|
series: {
|
|
$apply: [
|
|
miniChartSeriesTheme(
|
|
{ $path: "/series/$index" },
|
|
{
|
|
$path: [
|
|
"/navigator/miniChart/series/$index/type",
|
|
{ $path: ["type", { $path: "/series/$index/type" }] }
|
|
]
|
|
}
|
|
),
|
|
{
|
|
// TODO: this should be a $switch but switches can not resolve the case value yet
|
|
$if: [
|
|
{
|
|
$or: validMiniChartSeriesTypes.map((type) => ({
|
|
$eq: [{ $path: "/series/0/type" }, type]
|
|
}))
|
|
},
|
|
{
|
|
$map: [
|
|
miniChartSeriesTheme({ $value: "$1" }, { $path: "/series/$index/type" }),
|
|
{ $path: "/series" }
|
|
]
|
|
},
|
|
void 0
|
|
]
|
|
}
|
|
]
|
|
}
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/navigator/navigatorModule.ts
|
|
var NavigatorModule = {
|
|
type: "plugin",
|
|
name: "navigator",
|
|
chartType: "cartesian",
|
|
enterprise: true,
|
|
version: VERSION22,
|
|
// removable: false, // Toggling this module causes zoom state flakiness.
|
|
options: navigatorOptionsDef,
|
|
themeTemplate: NAVIGATOR_THEME,
|
|
create: (ctx) => new Navigator(ctx)
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/scrollbar/scrollbarModule.ts
|
|
import { VERSION as VERSION23 } from "ag-charts-community";
|
|
|
|
// packages/ag-charts-enterprise/src/features/scrollbar/scrollbar.ts
|
|
import { _ModuleSupport as _ModuleSupport119 } from "ag-charts-community";
|
|
import {
|
|
AbstractModuleInstance as AbstractModuleInstance13,
|
|
ChartAxisDirection as ChartAxisDirection28,
|
|
ChartUpdateType as ChartUpdateType6,
|
|
Property as Property59,
|
|
ZIndexMap as ZIndexMap9,
|
|
clamp as clamp9
|
|
} from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/features/scrollbar/scrollbarDOMProxy.ts
|
|
import { _ModuleSupport as _ModuleSupport118 } from "ag-charts-community";
|
|
import { clamp as clamp8 } from "ag-charts-core";
|
|
var { SliderWidget: SliderWidget2 } = _ModuleSupport118;
|
|
var STEP_REPEAT_DELAY_MS = 400;
|
|
var STEP_REPEAT_INTERVAL_MS = 50;
|
|
var StepRepeater = class {
|
|
constructor(applyStep) {
|
|
this.applyStep = applyStep;
|
|
}
|
|
start(target) {
|
|
this.setTarget(target);
|
|
this.run(STEP_REPEAT_DELAY_MS);
|
|
}
|
|
updateTarget(target) {
|
|
this.setTarget(target);
|
|
if (!this.isActive()) {
|
|
this.run(STEP_REPEAT_DELAY_MS);
|
|
}
|
|
}
|
|
stop(resetTarget = true) {
|
|
this.clearTimer();
|
|
if (resetTarget) {
|
|
this.target = void 0;
|
|
}
|
|
}
|
|
setTarget(target) {
|
|
this.target = clamp8(0, target, 1);
|
|
}
|
|
run(delay) {
|
|
if (this.target == null) {
|
|
this.stop();
|
|
return;
|
|
}
|
|
const finished = this.applyStep(this.target);
|
|
if (finished) {
|
|
this.stop();
|
|
return;
|
|
}
|
|
this.schedule(delay);
|
|
}
|
|
schedule(delay) {
|
|
if (this.isActive())
|
|
return;
|
|
this.timer = setTimeout(() => {
|
|
this.timer = void 0;
|
|
this.run(STEP_REPEAT_INTERVAL_MS);
|
|
}, delay);
|
|
}
|
|
clearTimer() {
|
|
if (this.timer != null) {
|
|
clearTimeout(this.timer);
|
|
this.timer = void 0;
|
|
}
|
|
}
|
|
isActive() {
|
|
return this.timer != null;
|
|
}
|
|
};
|
|
var ScrollbarState = class {
|
|
constructor() {
|
|
this.min = 0;
|
|
this.span = 1;
|
|
this.thumbSpan = 1;
|
|
}
|
|
update(min, max, thumbSpan = this.thumbSpan) {
|
|
const span = clamp8(0, max - min, 1);
|
|
this.span = span;
|
|
this.thumbSpan = clamp8(0, thumbSpan, 1);
|
|
this.min = this.clampMin(min, span);
|
|
}
|
|
clampMin(min, span = this.span) {
|
|
return clamp8(0, min, 1 - span);
|
|
}
|
|
getThumbBounds(min = this.min, span = this.thumbSpan) {
|
|
const start = this.clampMin(min, span);
|
|
return { start, end: start + span };
|
|
}
|
|
isWithinThumb(ratio8) {
|
|
const { start, end } = this.getThumbBounds();
|
|
return ratio8 >= start && ratio8 <= end;
|
|
}
|
|
getJumpRange(ratio8) {
|
|
if (!this.canScroll())
|
|
return;
|
|
let min = this.clampMin(ratio8 - this.thumbSpan / 2, this.thumbSpan);
|
|
min = this.clampMin(min);
|
|
return { min, max: min + this.span };
|
|
}
|
|
getStepRange(ratio8) {
|
|
if (!this.canScroll())
|
|
return;
|
|
const cursor = clamp8(0, ratio8, 1);
|
|
const { start, end } = this.getThumbBounds();
|
|
if (cursor >= start && cursor <= end)
|
|
return;
|
|
const movingLeft = cursor < start;
|
|
const distance = movingLeft ? start - cursor : cursor - end;
|
|
const step = Math.min(this.span, distance);
|
|
const nextMin = this.clampMin(this.min + (movingLeft ? -step : step));
|
|
return { min: nextMin, max: nextMin + this.span };
|
|
}
|
|
canScroll() {
|
|
return this.span > 0 && this.span < 1;
|
|
}
|
|
};
|
|
var ScrollbarDOMProxy = class {
|
|
constructor(ctx, orientation, onChange, onHoverChange) {
|
|
this.ctx = ctx;
|
|
this.orientation = orientation;
|
|
this.onChange = onChange;
|
|
this.onHoverChange = onHoverChange;
|
|
this.dragStartRatio = 0;
|
|
this.interactionMode = "none";
|
|
this.state = new ScrollbarState();
|
|
this.repeater = new StepRepeater((target) => this.applyStepToward(target));
|
|
this.container = ctx.proxyInteractionService.createProxyContainer({
|
|
type: "group",
|
|
domManagerId: `scrollbar-${orientation}`,
|
|
classList: ["ag-charts-proxy-scrollbar", `ag-charts-proxy-scrollbar-${orientation}`],
|
|
ariaLabel: void 0,
|
|
role: "presentation"
|
|
});
|
|
const ariaLabelId = orientation === "horizontal" ? "ariaLabelScrollbarHorizontal" : "ariaLabelScrollbarVertical";
|
|
this.slider = ctx.proxyInteractionService.createProxyElement({
|
|
type: "slider",
|
|
domIndex: 0,
|
|
tabIndex: 0,
|
|
ariaLabel: { id: ariaLabelId },
|
|
role: "slider",
|
|
parent: this.container,
|
|
classList: ["ag-charts-proxy-scrollbar-slider"]
|
|
});
|
|
const element = this.slider.getElement();
|
|
element.ariaValueMin = "0";
|
|
element.ariaValueMax = "100";
|
|
this.slider.step = SliderWidget2.STEP_HUNDRETH;
|
|
this.slider.keyboardStep = SliderWidget2.STEP_ONE;
|
|
this.slider.orientation = orientation;
|
|
this.slider.setPreventsDefault(false);
|
|
this.slider.addListener("change", () => this.onSliderChange());
|
|
this.slider.addListener("keydown", (ev) => this.onSliderKeyDown(ev));
|
|
this.slider.addListener("drag-start", (ev) => this.onDragStart(ev));
|
|
this.slider.addListener("drag-move", (ev) => this.onDragMove(ev));
|
|
this.slider.addListener("drag-end", (ev) => this.onDragEnd(ev));
|
|
this.slider.addListener("mouseenter", (event) => this.handleHoverEvent(event));
|
|
this.slider.addListener("mousemove", (event) => this.handleHoverEvent(event));
|
|
this.slider.addListener("mouseleave", () => this.onMouseLeave());
|
|
this.thumbFocus = ctx.proxyInteractionService.createProxyElement({
|
|
type: "region",
|
|
parent: this.container,
|
|
classList: ["ag-charts-proxy-scrollbar-thumb-focus"],
|
|
role: "presentation"
|
|
});
|
|
this.thumbFocus.setAriaHidden(true);
|
|
this.thumbFocus.setPointerEvents("none");
|
|
}
|
|
destroy() {
|
|
this.interactionBounds = void 0;
|
|
this.repeater.stop();
|
|
this.container.destroy();
|
|
}
|
|
updateBounds(bounds) {
|
|
this.interactionBounds = void 0;
|
|
this.container.setBounds(bounds);
|
|
this.slider.setBounds({ x: 0, y: 0, width: bounds.width, height: bounds.height });
|
|
}
|
|
updateVisibility(visible) {
|
|
this.container.setHidden(!visible);
|
|
}
|
|
updateMinMax(min, max, thumbSpan = this.state.thumbSpan, options) {
|
|
this.state.update(min, max, thumbSpan);
|
|
const aria = this.ctx.localeManager.t("ariaValuePanRange", {
|
|
min: Math.round(min * 100) / 100,
|
|
max: Math.round(max * 100) / 100
|
|
});
|
|
const element = this.slider.getElement();
|
|
element.ariaValueText = aria;
|
|
const shouldUpdateSlider = !options?.skipSliderUpdate || Math.abs(this.slider.getValueRatio() - min) > 1e-9;
|
|
if (shouldUpdateSlider) {
|
|
this.slider.setValueRatio(min, { ariaValueText: aria });
|
|
}
|
|
}
|
|
updateThumbBounds(thumb, track, cornerRadius) {
|
|
const radius = Math.max(0, cornerRadius ?? 0);
|
|
this.thumbFocus.getElement().style.borderRadius = `${radius}px`;
|
|
this.thumbFocus.setBounds({
|
|
x: thumb.x - track.x,
|
|
y: thumb.y - track.y,
|
|
width: thumb.width,
|
|
height: thumb.height
|
|
});
|
|
}
|
|
update(min, max, options) {
|
|
this.onChange(min, max);
|
|
this.updateMinMax(min, max, void 0, options);
|
|
}
|
|
onSliderChange() {
|
|
const min = this.state.clampMin(this.slider.getValueRatio());
|
|
const max = min + this.state.span;
|
|
this.update(min, max, { skipSliderUpdate: true });
|
|
}
|
|
onSliderKeyDown(event) {
|
|
const { code } = event.sourceEvent;
|
|
const isVertical = this.orientation === "vertical";
|
|
const decrement = isVertical && code === "ArrowUp" || !isVertical && code === "ArrowLeft";
|
|
const increment = isVertical && code === "ArrowDown" || !isVertical && code === "ArrowRight";
|
|
if (!decrement && !increment)
|
|
return;
|
|
event.sourceEvent.preventDefault();
|
|
const element = this.slider.getElement();
|
|
element.step = this.slider.keyboardStep?.attributeValue ?? "1";
|
|
if (decrement) {
|
|
element.stepDown();
|
|
} else if (increment) {
|
|
element.stepUp();
|
|
}
|
|
this.onSliderChange();
|
|
}
|
|
onDragMove(event) {
|
|
event.sourceEvent.preventDefault();
|
|
if (this.interactionMode === "drag") {
|
|
const { isHorizontal: isHorizontal2, size, start } = this.getInteractionBounds() ?? {};
|
|
if (start == null || size == null)
|
|
return;
|
|
const delta3 = (isHorizontal2 ? event.originDeltaX : event.originDeltaY) / size;
|
|
const min = this.state.clampMin(this.dragStartRatio + delta3);
|
|
const max = min + this.state.span;
|
|
this.update(min, max);
|
|
return;
|
|
}
|
|
if (this.interactionMode !== "step")
|
|
return;
|
|
const pointer = this.getPointerInfo(event);
|
|
if (pointer == null || !Number.isFinite(pointer.ratio))
|
|
return;
|
|
const { ratio: ratio8, inCrossBounds } = pointer;
|
|
if (!inCrossBounds) {
|
|
this.repeater.stop();
|
|
return;
|
|
}
|
|
this.repeater.updateTarget(ratio8);
|
|
}
|
|
onDragEnd(event) {
|
|
event.sourceEvent.preventDefault();
|
|
this.interactionBounds = void 0;
|
|
this.setInteraction("none");
|
|
this.onHoverChange(false);
|
|
}
|
|
onDragStart(event) {
|
|
event.sourceEvent.preventDefault();
|
|
this.interactionBounds = void 0;
|
|
const click = this.getClickInfo(event);
|
|
if (!click?.inBounds)
|
|
return;
|
|
if (click.inThumb) {
|
|
this.dragStartRatio = this.slider.getValueRatio();
|
|
this.setInteraction("drag");
|
|
return;
|
|
}
|
|
if (event.sourceEvent.shiftKey) {
|
|
this.jumpTo(click.ratio);
|
|
this.setInteraction("none");
|
|
return;
|
|
}
|
|
this.beginStepRepeat(click.ratio);
|
|
}
|
|
onMouseLeave() {
|
|
this.onHoverChange(false);
|
|
}
|
|
getClickInfo(event) {
|
|
const ratio8 = this.getPointerRatio(event);
|
|
if (ratio8 == null)
|
|
return;
|
|
const inBounds = ratio8 >= 0 && ratio8 <= 1;
|
|
if (!inBounds)
|
|
return { ratio: 0, inBounds: false, inThumb: false };
|
|
return { ratio: ratio8, inBounds: true, inThumb: this.isWithinThumb(ratio8) };
|
|
}
|
|
getPointerRatio(event) {
|
|
return this.getPointerInfo(event)?.ratio;
|
|
}
|
|
getPointerInfo(event) {
|
|
if (event.device === "keyboard")
|
|
return;
|
|
const { isHorizontal: isHorizontal2, size, start, crossStart, crossSize } = this.getInteractionBounds();
|
|
const pos = isHorizontal2 ? event.clientX : event.clientY;
|
|
const crossPos = isHorizontal2 ? event.clientY : event.clientX;
|
|
const ratio8 = (pos - start) / size;
|
|
const inCrossBounds = crossPos >= crossStart && crossPos <= crossStart + crossSize;
|
|
return { ratio: ratio8, inCrossBounds };
|
|
}
|
|
jumpTo(ratio8) {
|
|
const next = this.state.getJumpRange(ratio8);
|
|
if (!next)
|
|
return;
|
|
this.update(next.min, next.max);
|
|
}
|
|
applyStepToward(target) {
|
|
const next = this.state.getStepRange(target);
|
|
if (!next)
|
|
return true;
|
|
this.update(next.min, next.max);
|
|
return false;
|
|
}
|
|
beginStepRepeat(ratio8) {
|
|
this.setInteraction("step");
|
|
this.repeater.start(ratio8);
|
|
}
|
|
setInteraction(mode) {
|
|
this.interactionMode = mode;
|
|
if (mode !== "step") {
|
|
this.repeater.stop();
|
|
}
|
|
}
|
|
getInteractionBounds() {
|
|
if (this.interactionBounds) {
|
|
return this.interactionBounds;
|
|
}
|
|
const { width, height, left, top } = this.container.getBoundingClientRect();
|
|
const isHorizontal2 = this.orientation === "horizontal";
|
|
const size = isHorizontal2 ? width : height;
|
|
const start = isHorizontal2 ? left : top;
|
|
const crossStart = isHorizontal2 ? top : left;
|
|
const crossSize = isHorizontal2 ? height : width;
|
|
this.interactionBounds = { isHorizontal: isHorizontal2, size, start, crossStart, crossSize };
|
|
return this.interactionBounds;
|
|
}
|
|
isWithinThumb(ratio8) {
|
|
return this.state.isWithinThumb(ratio8);
|
|
}
|
|
handleHoverEvent(event) {
|
|
if (this.interactionMode === "drag")
|
|
return;
|
|
const pointer = this.getPointerInfo(event);
|
|
if (!pointer) {
|
|
this.onHoverChange(false);
|
|
return;
|
|
}
|
|
const hovered = this.isWithinThumb(pointer.ratio);
|
|
this.onHoverChange(hovered);
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/scrollbar/scrollbarProperties.ts
|
|
import { ChangeDetectableProperties, Property as Property58, SceneChangeDetection as SceneChangeDetection5 } from "ag-charts-core";
|
|
var ScrollbarTrack = class extends ChangeDetectableProperties {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.enabled = false;
|
|
this.fillOpacity = 1;
|
|
this.strokeWidth = 1;
|
|
this.strokeOpacity = 1;
|
|
this.lineDash = [0];
|
|
this.lineDashOffset = 0;
|
|
this.cornerRadius = 0;
|
|
this.opacity = 1;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property58,
|
|
SceneChangeDetection5()
|
|
], ScrollbarTrack.prototype, "enabled", 2);
|
|
__decorateClass([
|
|
Property58,
|
|
SceneChangeDetection5()
|
|
], ScrollbarTrack.prototype, "fill", 2);
|
|
__decorateClass([
|
|
Property58,
|
|
SceneChangeDetection5()
|
|
], ScrollbarTrack.prototype, "fillOpacity", 2);
|
|
__decorateClass([
|
|
Property58,
|
|
SceneChangeDetection5()
|
|
], ScrollbarTrack.prototype, "stroke", 2);
|
|
__decorateClass([
|
|
Property58,
|
|
SceneChangeDetection5()
|
|
], ScrollbarTrack.prototype, "strokeWidth", 2);
|
|
__decorateClass([
|
|
Property58,
|
|
SceneChangeDetection5()
|
|
], ScrollbarTrack.prototype, "strokeOpacity", 2);
|
|
__decorateClass([
|
|
Property58
|
|
], ScrollbarTrack.prototype, "lineDash", 2);
|
|
__decorateClass([
|
|
Property58
|
|
], ScrollbarTrack.prototype, "lineDashOffset", 2);
|
|
__decorateClass([
|
|
Property58
|
|
], ScrollbarTrack.prototype, "cornerRadius", 2);
|
|
__decorateClass([
|
|
Property58
|
|
], ScrollbarTrack.prototype, "opacity", 2);
|
|
var ScrollbarThumbHoverStyle = class extends ChangeDetectableProperties {
|
|
};
|
|
__decorateClass([
|
|
Property58,
|
|
SceneChangeDetection5()
|
|
], ScrollbarThumbHoverStyle.prototype, "fill", 2);
|
|
__decorateClass([
|
|
Property58,
|
|
SceneChangeDetection5()
|
|
], ScrollbarThumbHoverStyle.prototype, "stroke", 2);
|
|
var ScrollbarThumb = class extends ScrollbarTrack {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.minSize = 20;
|
|
this.hoverStyle = new ScrollbarThumbHoverStyle();
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property58,
|
|
SceneChangeDetection5()
|
|
], ScrollbarThumb.prototype, "minSize", 2);
|
|
__decorateClass([
|
|
Property58
|
|
], ScrollbarThumb.prototype, "hoverStyle", 2);
|
|
var ScrollbarProperties = class extends ChangeDetectableProperties {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.enabled = false;
|
|
this.thickness = 12;
|
|
this.spacing = 4;
|
|
this.tickSpacing = 0;
|
|
this.placement = "outer";
|
|
this.visible = "auto";
|
|
this.track = new ScrollbarTrack();
|
|
this.thumb = new ScrollbarThumb();
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property58,
|
|
SceneChangeDetection5()
|
|
], ScrollbarProperties.prototype, "enabled", 2);
|
|
__decorateClass([
|
|
Property58,
|
|
SceneChangeDetection5()
|
|
], ScrollbarProperties.prototype, "thickness", 2);
|
|
__decorateClass([
|
|
Property58,
|
|
SceneChangeDetection5()
|
|
], ScrollbarProperties.prototype, "spacing", 2);
|
|
__decorateClass([
|
|
Property58,
|
|
SceneChangeDetection5()
|
|
], ScrollbarProperties.prototype, "tickSpacing", 2);
|
|
__decorateClass([
|
|
Property58,
|
|
SceneChangeDetection5()
|
|
], ScrollbarProperties.prototype, "placement", 2);
|
|
__decorateClass([
|
|
Property58,
|
|
SceneChangeDetection5()
|
|
], ScrollbarProperties.prototype, "visible", 2);
|
|
__decorateClass([
|
|
Property58
|
|
], ScrollbarProperties.prototype, "track", 2);
|
|
__decorateClass([
|
|
Property58
|
|
], ScrollbarProperties.prototype, "thumb", 2);
|
|
var HorizontalScrollbarProperties = class extends ScrollbarProperties {
|
|
};
|
|
__decorateClass([
|
|
Property58,
|
|
SceneChangeDetection5()
|
|
], HorizontalScrollbarProperties.prototype, "position", 2);
|
|
var VerticalScrollbarProperties = class extends ScrollbarProperties {
|
|
};
|
|
__decorateClass([
|
|
Property58,
|
|
SceneChangeDetection5()
|
|
], VerticalScrollbarProperties.prototype, "position", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/features/scrollbar/scrollbar.ts
|
|
var { BBox: BBox14, Group: Group7, Rect: Rect4, LayoutElement: LayoutElement3, InteractionState: InteractionState5 } = _ModuleSupport119;
|
|
var Scrollbar = class extends AbstractModuleInstance13 {
|
|
constructor(ctx) {
|
|
super();
|
|
this.ctx = ctx;
|
|
this.track = new ScrollbarTrack();
|
|
this.thumb = new ScrollbarThumb();
|
|
this.horizontal = new HorizontalScrollbarProperties();
|
|
this.vertical = new VerticalScrollbarProperties();
|
|
this.state = {
|
|
horizontal: this.createOrientationState("horizontal"),
|
|
vertical: this.createOrientationState("vertical")
|
|
};
|
|
this.cleanup.register(
|
|
ctx.scene.attachNode(this.state.horizontal.group),
|
|
ctx.scene.attachNode(this.state.vertical.group),
|
|
ctx.layoutManager.registerElement(LayoutElement3.Scrollbar, (e) => this.onLayoutStart(e)),
|
|
ctx.eventsHub.on("layout:complete", (e) => this.onLayoutComplete(e)),
|
|
ctx.eventsHub.on("zoom:change-complete", () => this.updateThumbs())
|
|
);
|
|
}
|
|
createOrientationState(orientation) {
|
|
const group = new Group7({ name: `scrollbar-${orientation}`, zIndex: ZIndexMap9.NAVIGATOR });
|
|
const track = new Rect4();
|
|
const thumb = new Rect4();
|
|
group.append(track);
|
|
group.append(thumb);
|
|
const dom = new ScrollbarDOMProxy(
|
|
this.ctx,
|
|
orientation,
|
|
(min, max) => this.handleUserChange(orientation, min, max),
|
|
(hovered) => this.handleHoverChange(orientation, hovered)
|
|
);
|
|
const properties = this.resolveProperties(orientation);
|
|
return {
|
|
orientation,
|
|
group,
|
|
track,
|
|
thumb,
|
|
dom,
|
|
properties,
|
|
position: this.getDefaultPosition(orientation),
|
|
positionHasAxis: false,
|
|
hovered: false
|
|
};
|
|
}
|
|
resolveProperties(orientation) {
|
|
return orientation === "horizontal" ? this.horizontal : this.vertical;
|
|
}
|
|
getDefaultPosition(orientation) {
|
|
return orientation === "horizontal" ? "bottom" : "left";
|
|
}
|
|
resolveAxis(orientation, configuredPosition) {
|
|
const direction = orientation === "horizontal" ? ChartAxisDirection28.X : ChartAxisDirection28.Y;
|
|
const contexts = this.ctx.axisManager.getAxisContext(direction);
|
|
if (contexts.length === 0) {
|
|
return { position: this.getDefaultPosition(orientation), positionHasAxis: false };
|
|
}
|
|
if (configuredPosition == null) {
|
|
const axis2 = contexts[0];
|
|
return { axis: axis2, position: axis2.position ?? this.getDefaultPosition(orientation), positionHasAxis: true };
|
|
}
|
|
const axis = contexts.find((ctx) => ctx.position === configuredPosition);
|
|
if (axis) {
|
|
return { axis, position: configuredPosition, positionHasAxis: true };
|
|
}
|
|
return { axis: contexts[0], position: configuredPosition, positionHasAxis: false };
|
|
}
|
|
onLayoutStart({ scrollbars, layoutBox }) {
|
|
for (const orientation of ["horizontal", "vertical"]) {
|
|
const state = this.state[orientation];
|
|
const properties = this.resolveProperties(orientation);
|
|
const { min, max } = this.getZoomRange(state.orientation);
|
|
const span = clamp9(0, max - min, 1);
|
|
const {
|
|
axis: { axisId } = {},
|
|
position,
|
|
positionHasAxis
|
|
} = this.resolveAxis(orientation, properties.position);
|
|
state.properties = properties;
|
|
state.axisId = axisId;
|
|
state.position = position;
|
|
state.positionHasAxis = positionHasAxis;
|
|
const show = this.updateVisibility(state, span);
|
|
if (!show || axisId == null)
|
|
continue;
|
|
const { thickness, spacing, placement, tickSpacing } = properties;
|
|
if (positionHasAxis) {
|
|
scrollbars[axisId] = {
|
|
enabled: show,
|
|
thickness,
|
|
spacing,
|
|
tickSpacing,
|
|
placement
|
|
};
|
|
} else {
|
|
layoutBox.shrink(spacing + thickness, position);
|
|
}
|
|
this.updateStyles(state);
|
|
}
|
|
}
|
|
onLayoutComplete(event) {
|
|
this.seriesRect = event.series.rect;
|
|
for (const orientation of ["horizontal", "vertical"]) {
|
|
const state = this.state[orientation];
|
|
const {
|
|
properties: { enabled, visible }
|
|
} = state;
|
|
if (!enabled || visible === "never") {
|
|
continue;
|
|
}
|
|
const layoutRect = this.getLayoutRect(state, orientation, event);
|
|
state.layoutRect = layoutRect;
|
|
if (!layoutRect)
|
|
continue;
|
|
this.updateTrack(state, layoutRect);
|
|
this.updateThumb(state, layoutRect);
|
|
}
|
|
}
|
|
getLayoutRect(state, orientation, event) {
|
|
const {
|
|
properties: { thickness, spacing },
|
|
position,
|
|
positionHasAxis
|
|
} = state;
|
|
const axisLayout = state.axisId ? event.axes[state.axisId] : void 0;
|
|
if (!axisLayout)
|
|
return;
|
|
const { x, y, width, height } = event.series.rect;
|
|
const isHorizontal2 = orientation === "horizontal";
|
|
if (!positionHasAxis) {
|
|
if (isHorizontal2) {
|
|
const coord2 = position === "bottom" ? y + height + spacing : y - spacing - thickness;
|
|
return new BBox14(x, coord2, width, thickness);
|
|
} else {
|
|
const coord2 = position === "right" ? x + width + spacing : x - spacing - thickness;
|
|
return new BBox14(coord2, y, thickness, height);
|
|
}
|
|
}
|
|
const { scrollbar: scrollbarLayout, translation } = axisLayout;
|
|
if (!scrollbarLayout?.enabled)
|
|
return;
|
|
const coord = isHorizontal2 ? translation.y + scrollbarLayout.offset : translation.x + scrollbarLayout.offset;
|
|
return isHorizontal2 ? new BBox14(x, coord, width, thickness) : new BBox14(coord, y, thickness, height);
|
|
}
|
|
updateStyles({ track, thumb, properties, hovered }) {
|
|
track.setStyleProperties(properties.track);
|
|
track.cornerRadius = properties.track.cornerRadius ?? 0;
|
|
track.opacity = properties.track.opacity ?? 1;
|
|
thumb.setStyleProperties(properties.thumb);
|
|
thumb.cornerRadius = properties.thumb.cornerRadius ?? 0;
|
|
thumb.opacity = properties.thumb.opacity ?? 1;
|
|
const hoverStyle = properties.thumb.hoverStyle;
|
|
thumb.fill = hovered ? hoverStyle?.fill ?? properties.thumb.fill : properties.thumb.fill;
|
|
thumb.stroke = hovered ? hoverStyle?.stroke ?? properties.thumb.stroke : properties.thumb.stroke;
|
|
}
|
|
updateTrack(state, bounds) {
|
|
state.track.x = bounds.x;
|
|
state.track.y = bounds.y;
|
|
state.track.width = bounds.width;
|
|
state.track.height = bounds.height;
|
|
state.dom.updateBounds(bounds);
|
|
}
|
|
updateThumb(state, track) {
|
|
const { min, max } = this.getZoomRange(state.orientation);
|
|
const span = clamp9(0, max - min, 1);
|
|
const show = this.updateVisibility(state, span);
|
|
if (!show || track.width <= 0 || track.height <= 0) {
|
|
return;
|
|
}
|
|
const minSize = state.properties.thumb.minSize ?? 0;
|
|
let thumbSpan;
|
|
if (state.orientation === "horizontal") {
|
|
const thumbWidth = Math.min(Math.max(minSize, track.width * span), track.width);
|
|
const start = clamp9(track.x, track.x + track.width * min, track.x + track.width - thumbWidth);
|
|
state.thumb.x = start;
|
|
state.thumb.y = track.y;
|
|
state.thumb.width = thumbWidth;
|
|
state.thumb.height = track.height;
|
|
thumbSpan = clamp9(0, thumbWidth / track.width, 1);
|
|
} else {
|
|
const thumbHeight = Math.min(Math.max(minSize, track.height * span), track.height);
|
|
const start = clamp9(track.y, track.y + track.height * min, track.y + track.height - thumbHeight);
|
|
state.thumb.x = track.x;
|
|
state.thumb.y = start;
|
|
state.thumb.width = track.width;
|
|
state.thumb.height = thumbHeight;
|
|
thumbSpan = clamp9(0, thumbHeight / track.height, 1);
|
|
}
|
|
state.dom.updateThumbBounds(state.thumb, track, state.properties.thumb.cornerRadius);
|
|
state.dom.updateMinMax(min, max, thumbSpan);
|
|
}
|
|
updateThumbs() {
|
|
if (!this.seriesRect)
|
|
return;
|
|
for (const orientation of ["horizontal", "vertical"]) {
|
|
const state = this.state[orientation];
|
|
const layoutRect = state.layoutRect;
|
|
if (!layoutRect || !state.properties.enabled || state.properties.visible === "never")
|
|
continue;
|
|
const trackBounds = orientation === "horizontal" ? new BBox14(this.seriesRect.x, layoutRect.y, this.seriesRect.width, state.properties.thickness) : new BBox14(layoutRect.x, this.seriesRect.y, state.properties.thickness, this.seriesRect.height);
|
|
this.updateThumb(state, trackBounds);
|
|
}
|
|
}
|
|
updateVisibility(state, span) {
|
|
const show = state.properties.enabled && state.axisId != null && state.properties.visible !== "never" && (state.properties.visible === "always" || span < 1);
|
|
state.group.visible = show;
|
|
state.track.visible = show;
|
|
state.thumb.visible = show;
|
|
state.dom.updateVisibility(show);
|
|
return show;
|
|
}
|
|
getZoomRange(orientation) {
|
|
const zoom = this.ctx.zoomManager.getZoom();
|
|
const isHorizontal2 = orientation === "horizontal";
|
|
const range2 = isHorizontal2 ? zoom?.x : zoom?.y;
|
|
if (!isHorizontal2 && range2 != null) {
|
|
return {
|
|
min: 1 - (range2.max ?? 1),
|
|
max: 1 - (range2.min ?? 0)
|
|
};
|
|
}
|
|
return {
|
|
min: range2?.min ?? 0,
|
|
max: range2?.max ?? 1
|
|
};
|
|
}
|
|
handleUserChange(orientation, min, max) {
|
|
if (!this.ctx.interactionManager.isState(InteractionState5.ZoomDraggable))
|
|
return;
|
|
const isHorizontal2 = orientation === "horizontal";
|
|
if (!isHorizontal2) {
|
|
[min, max] = [1 - max, 1 - min];
|
|
}
|
|
const zoom = isHorizontal2 ? { x: { min, max } } : { y: { min, max } };
|
|
this.ctx.zoomManager.updateZoom(
|
|
{
|
|
source: "user-interaction",
|
|
sourceDetail: "scrollbar"
|
|
},
|
|
zoom
|
|
);
|
|
}
|
|
handleHoverChange(orientation, hovered) {
|
|
const state = this.state[orientation];
|
|
const nextHovered = hovered && state.group.visible;
|
|
if (state.hovered === nextHovered)
|
|
return;
|
|
state.hovered = nextHovered;
|
|
this.updateStyles(state);
|
|
this.ctx.updateService.update(ChartUpdateType6.SCENE_RENDER);
|
|
}
|
|
destroy() {
|
|
super.destroy();
|
|
this.state.horizontal.dom.destroy();
|
|
this.state.vertical.dom.destroy();
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property59
|
|
], Scrollbar.prototype, "enabled", 2);
|
|
__decorateClass([
|
|
Property59
|
|
], Scrollbar.prototype, "thickness", 2);
|
|
__decorateClass([
|
|
Property59
|
|
], Scrollbar.prototype, "spacing", 2);
|
|
__decorateClass([
|
|
Property59
|
|
], Scrollbar.prototype, "tickSpacing", 2);
|
|
__decorateClass([
|
|
Property59
|
|
], Scrollbar.prototype, "placement", 2);
|
|
__decorateClass([
|
|
Property59
|
|
], Scrollbar.prototype, "visible", 2);
|
|
__decorateClass([
|
|
Property59
|
|
], Scrollbar.prototype, "track", 2);
|
|
__decorateClass([
|
|
Property59
|
|
], Scrollbar.prototype, "thumb", 2);
|
|
__decorateClass([
|
|
Property59
|
|
], Scrollbar.prototype, "horizontal", 2);
|
|
__decorateClass([
|
|
Property59
|
|
], Scrollbar.prototype, "vertical", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/features/scrollbar/scrollbarOptionsDefs.ts
|
|
import {
|
|
boolean as boolean12,
|
|
fillOptionsDef as fillOptionsDef2,
|
|
lineDashOptionsDef,
|
|
positiveNumber as positiveNumber6,
|
|
ratio as ratio5,
|
|
strokeOptionsDef,
|
|
union as union2
|
|
} from "ag-charts-core";
|
|
var scrollbarTrackOptionsDef = {
|
|
...fillOptionsDef2,
|
|
...strokeOptionsDef,
|
|
...lineDashOptionsDef,
|
|
cornerRadius: positiveNumber6,
|
|
opacity: ratio5
|
|
};
|
|
var scrollbarThumbOptionsDef = {
|
|
...scrollbarTrackOptionsDef,
|
|
minSize: positiveNumber6,
|
|
hoverStyle: {
|
|
fill: fillOptionsDef2.fill,
|
|
stroke: strokeOptionsDef.stroke
|
|
}
|
|
};
|
|
var scrollbarBaseOptionsDef = {
|
|
enabled: boolean12,
|
|
thickness: positiveNumber6,
|
|
spacing: positiveNumber6,
|
|
tickSpacing: positiveNumber6,
|
|
visible: union2("auto", "always", "never"),
|
|
placement: union2("outer", "inner"),
|
|
track: scrollbarTrackOptionsDef,
|
|
thumb: scrollbarThumbOptionsDef
|
|
};
|
|
var scrollbarHorizontalOrientationOptionsDef = {
|
|
...scrollbarBaseOptionsDef,
|
|
position: union2("top", "bottom")
|
|
};
|
|
var scrollbarVerticalOrientationOptionsDef = {
|
|
...scrollbarBaseOptionsDef,
|
|
position: union2("left", "right")
|
|
};
|
|
var scrollbarOptionsDef = {
|
|
enabled: boolean12,
|
|
thickness: positiveNumber6,
|
|
spacing: positiveNumber6,
|
|
tickSpacing: positiveNumber6,
|
|
visible: union2("auto", "always", "never"),
|
|
placement: union2("outer", "inner"),
|
|
track: scrollbarTrackOptionsDef,
|
|
thumb: scrollbarThumbOptionsDef,
|
|
horizontal: scrollbarHorizontalOrientationOptionsDef,
|
|
vertical: scrollbarVerticalOrientationOptionsDef
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/scrollbar/scrollbarTheme.ts
|
|
var SCROLLBAR_ORIENTATION_THEME = {
|
|
enabled: { $path: "../enabled" },
|
|
thickness: { $path: "../thickness" },
|
|
spacing: { $path: "../spacing" },
|
|
tickSpacing: { $path: "../tickSpacing" },
|
|
placement: { $path: "../placement" },
|
|
visible: { $path: "../visible" },
|
|
track: {
|
|
fill: { $path: "../../track/fill" },
|
|
stroke: { $path: "../../track/stroke" },
|
|
fillOpacity: { $path: "../../track/fillOpacity" },
|
|
strokeWidth: { $path: "../../track/strokeWidth" },
|
|
lineDash: { $path: "../../track/lineDash" },
|
|
lineDashOffset: { $path: "../../track/lineDashOffset" },
|
|
opacity: { $path: "../../track/opacity" },
|
|
cornerRadius: { $path: "../../track/cornerRadius" }
|
|
},
|
|
thumb: {
|
|
fill: { $path: "../../thumb/fill" },
|
|
stroke: { $path: "../../thumb/stroke" },
|
|
fillOpacity: { $path: "../../thumb/fillOpacity" },
|
|
strokeWidth: { $path: "../../thumb/strokeWidth" },
|
|
lineDash: { $path: "../../thumb/lineDash" },
|
|
lineDashOffset: { $path: "../../thumb/lineDashOffset" },
|
|
opacity: { $path: "../../thumb/opacity" },
|
|
cornerRadius: { $path: "../../thumb/cornerRadius" },
|
|
minSize: { $path: "../../thumb/minSize" },
|
|
hoverStyle: {
|
|
fill: { $path: "../../../thumb/hoverStyle/fill" },
|
|
stroke: { $path: "../../../thumb/hoverStyle/stroke" }
|
|
}
|
|
}
|
|
};
|
|
var SCROLLBAR_THEME = {
|
|
enabled: false,
|
|
thickness: 12,
|
|
spacing: 16,
|
|
tickSpacing: 0,
|
|
placement: "outer",
|
|
visible: "auto",
|
|
track: {
|
|
fill: { $foregroundBackgroundMix: 0.03 },
|
|
stroke: { $foregroundBackgroundMix: 0.177 },
|
|
strokeWidth: 1,
|
|
lineDash: [0],
|
|
lineDashOffset: 0,
|
|
opacity: 1,
|
|
cornerRadius: 6
|
|
},
|
|
thumb: {
|
|
fill: { $foregroundBackgroundMix: 0.125 },
|
|
stroke: { $foregroundBackgroundMix: 0.364 },
|
|
strokeWidth: 1,
|
|
lineDash: [0],
|
|
lineDashOffset: 0,
|
|
opacity: 1,
|
|
cornerRadius: 6,
|
|
minSize: 20,
|
|
hoverStyle: {
|
|
fill: { $mix: [{ $path: "../fill" }, { $ref: "foregroundColor" }, 0.075] },
|
|
stroke: { $mix: [{ $path: "../stroke" }, { $ref: "foregroundColor" }, 0.075] }
|
|
}
|
|
},
|
|
vertical: SCROLLBAR_ORIENTATION_THEME,
|
|
horizontal: SCROLLBAR_ORIENTATION_THEME
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/scrollbar/scrollbarModule.ts
|
|
var ScrollbarModule = {
|
|
type: "plugin",
|
|
name: "scrollbar",
|
|
chartType: "cartesian",
|
|
enterprise: true,
|
|
version: VERSION23,
|
|
options: scrollbarOptionsDef,
|
|
themeTemplate: SCROLLBAR_THEME,
|
|
create: (ctx) => new Scrollbar(ctx)
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/ranges/rangesModule.ts
|
|
import { VERSION as VERSION24 } from "ag-charts-community";
|
|
import {
|
|
and,
|
|
arrayLength,
|
|
arrayOf as arrayOf2,
|
|
arrayOfDefs as arrayOfDefs3,
|
|
boolean as boolean13,
|
|
callback as callback2,
|
|
date,
|
|
number as number6,
|
|
or,
|
|
toolbarButtonOptionsDefs
|
|
} from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/features/ranges/ranges.ts
|
|
import { _ModuleSupport as _ModuleSupport120 } from "ag-charts-community";
|
|
import { AbstractModuleInstance as AbstractModuleInstance14, ChartAxisDirection as ChartAxisDirection29, PropertiesArray as PropertiesArray5, Property as Property61 } from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/features/ranges/rangesButtonProperties.ts
|
|
import { Property as Property60 } from "ag-charts-core";
|
|
var RangesButtonProperties = class extends ToolbarButtonProperties {
|
|
};
|
|
__decorateClass([
|
|
Property60
|
|
], RangesButtonProperties.prototype, "value", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/features/ranges/ranges.ts
|
|
var { userInteraction, LayoutElement: LayoutElement4, Toolbar } = _ModuleSupport120;
|
|
var Ranges = class extends AbstractModuleInstance14 {
|
|
constructor(ctx) {
|
|
super();
|
|
this.ctx = ctx;
|
|
this.enabled = false;
|
|
this.buttons = new PropertiesArray5(RangesButtonProperties);
|
|
this.verticalSpacing = 10;
|
|
this.container = ctx.domManager.addChild("canvas-overlay", "range-buttons");
|
|
this.container.role = "presentation";
|
|
this.toolbar = new Toolbar(this.ctx, "ariaLabelRangesToolbar", "horizontal");
|
|
this.toolbar.addClass("ag-charts-range-buttons");
|
|
this.container.append(this.toolbar.getElement());
|
|
this.cleanup.register(
|
|
this.toolbar.addToolbarListener("button-pressed", this.onButtonPress.bind(this)),
|
|
ctx.layoutManager.registerElement(LayoutElement4.ToolbarBottom, this.onLayoutStart.bind(this)),
|
|
ctx.eventsHub.on("zoom:change-complete", this.onZoomChanged.bind(this)),
|
|
this.teardown.bind(this)
|
|
);
|
|
}
|
|
teardown() {
|
|
this.toolbar.getElement().remove();
|
|
this.toolbar.destroy();
|
|
}
|
|
onLayoutStart({ layoutBox }) {
|
|
const { buttons, ctx, enabled, toolbar: toolbar2, verticalSpacing } = this;
|
|
if (!enabled || !ctx.zoomManager.isZoomEnabled()) {
|
|
toolbar2.setHidden(true);
|
|
return;
|
|
}
|
|
toolbar2.setHidden(false);
|
|
toolbar2.updateButtons(buttons);
|
|
const height = toolbar2.getBounds().height;
|
|
toolbar2.setBounds({
|
|
x: layoutBox.x,
|
|
y: layoutBox.y + layoutBox.height - height,
|
|
width: layoutBox.width,
|
|
height
|
|
});
|
|
layoutBox.shrink({ bottom: height + verticalSpacing });
|
|
}
|
|
onZoomChanged() {
|
|
this.toolbar.clearActiveButton();
|
|
}
|
|
onButtonPress({ button: { index } }) {
|
|
const { zoomManager } = this.ctx;
|
|
const button = this.buttons.at(index);
|
|
if (!button)
|
|
return;
|
|
const { value } = button;
|
|
const sourcing = userInteraction(`zoom-range-button-${index}`);
|
|
if (value == null) {
|
|
zoomManager.resetZoom(sourcing);
|
|
} else if (typeof value === "number") {
|
|
zoomManager.extendToEnd(sourcing, ChartAxisDirection29.X, value);
|
|
} else if (Array.isArray(value)) {
|
|
zoomManager.updateWith(sourcing, ChartAxisDirection29.X, () => value);
|
|
} else if (typeof value === "function") {
|
|
zoomManager.updateWith(sourcing, ChartAxisDirection29.X, value);
|
|
}
|
|
this.toolbar.toggleActiveButtonByIndex(index);
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property61
|
|
], Ranges.prototype, "enabled", 2);
|
|
__decorateClass([
|
|
Property61
|
|
], Ranges.prototype, "buttons", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/features/ranges/rangesModule.ts
|
|
var DAY = 1e3 * 60 * 60 * 24;
|
|
var MONTH = DAY * 30;
|
|
var YEAR = DAY * 365;
|
|
var RangesModule = {
|
|
type: "plugin",
|
|
name: "ranges",
|
|
chartType: "cartesian",
|
|
enterprise: true,
|
|
version: VERSION24,
|
|
options: {
|
|
enabled: boolean13,
|
|
buttons: arrayOfDefs3(
|
|
{
|
|
...toolbarButtonOptionsDefs,
|
|
value: or(number6, and(arrayOf2(or(number6, date)), arrayLength(2, 2)), callback2)
|
|
},
|
|
"range button options array"
|
|
)
|
|
},
|
|
themeTemplate: {
|
|
enabled: false,
|
|
buttons: {
|
|
$shallowSimple: [
|
|
{
|
|
label: "toolbarRange1Month",
|
|
ariaLabel: "toolbarRange1MonthAria",
|
|
value: MONTH
|
|
},
|
|
{
|
|
label: "toolbarRange3Months",
|
|
ariaLabel: "toolbarRange3MonthsAria",
|
|
value: 3 * MONTH
|
|
},
|
|
{
|
|
label: "toolbarRange6Months",
|
|
ariaLabel: "toolbarRange6MonthsAria",
|
|
value: 6 * MONTH
|
|
},
|
|
{
|
|
label: "toolbarRangeYearToDate",
|
|
ariaLabel: "toolbarRangeYearToDateAria",
|
|
value: (_start, end) => [
|
|
(/* @__PURE__ */ new Date(`${new Date(end).getFullYear()}-01-01`)).getTime(),
|
|
void 0
|
|
]
|
|
},
|
|
{
|
|
label: "toolbarRange1Year",
|
|
ariaLabel: "toolbarRange1YearAria",
|
|
value: YEAR
|
|
},
|
|
{
|
|
label: "toolbarRangeAll",
|
|
ariaLabel: "toolbarRangeAllAria",
|
|
value: void 0
|
|
// Reset zoom
|
|
}
|
|
]
|
|
}
|
|
},
|
|
create: (ctx) => new Ranges(ctx)
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/status-bar/statusBarModule.ts
|
|
import { VERSION as VERSION25 } from "ag-charts-community";
|
|
import { DEFAULT_CAPTION_LAYOUT_STYLE } from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/features/status-bar/statusBar.ts
|
|
import { _ModuleSupport as _ModuleSupport121 } from "ag-charts-community";
|
|
import {
|
|
AbstractModuleInstance as AbstractModuleInstance15,
|
|
BaseProperties as BaseProperties24,
|
|
ChartAxisDirection as ChartAxisDirection30,
|
|
Property as Property62,
|
|
ZIndexMap as ZIndexMap10,
|
|
cachedTextMeasurer as cachedTextMeasurer3,
|
|
calcLineHeight as calcLineHeight5
|
|
} from "ag-charts-core";
|
|
var { LayoutElement: LayoutElement5, Group: Group8, Label: Label5, Rect: Rect5, Text } = _ModuleSupport121;
|
|
var chartConfigurations = {
|
|
ohlc: 2 /* Open */ | 4 /* Close */ | 8 /* Low */ | 16 /* High */ | 32 /* Volume */,
|
|
candlestick: 2 /* Open */ | 4 /* Close */ | 8 /* Low */ | 16 /* High */ | 32 /* Volume */,
|
|
"hollow-candlestick": 2 /* Open */ | 4 /* Close */ | 8 /* Low */ | 16 /* High */ | 32 /* Volume */,
|
|
line: 64 /* UnlabelledClose */ | 32 /* Volume */,
|
|
"step-line": 64 /* UnlabelledClose */ | 32 /* Volume */,
|
|
hlc: 128 /* NeutralClose */ | 8 /* Low */ | 16 /* High */ | 32 /* Volume */,
|
|
"high-low": 512 /* NeutralLow */ | 256 /* NeutralHigh */ | 32 /* Volume */
|
|
};
|
|
var itemIdMap = {
|
|
up: "positive",
|
|
down: "negative"
|
|
};
|
|
var neutralColorMap = {
|
|
hlc: "altNeutral"
|
|
};
|
|
var StatusBarBackground = class extends BaseProperties24 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.fill = "black";
|
|
this.fillOpacity = 1;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property62
|
|
], StatusBarBackground.prototype, "fill", 2);
|
|
__decorateClass([
|
|
Property62
|
|
], StatusBarBackground.prototype, "fillOpacity", 2);
|
|
var StatusBar = class extends AbstractModuleInstance15 {
|
|
constructor(ctx) {
|
|
super();
|
|
this.ctx = ctx;
|
|
this.enabled = false;
|
|
this.openKey = void 0;
|
|
this.highKey = void 0;
|
|
this.lowKey = void 0;
|
|
this.closeKey = void 0;
|
|
this.volumeKey = void 0;
|
|
this.title = new Label5();
|
|
this.positive = new Label5();
|
|
this.negative = new Label5();
|
|
this.neutral = new Label5();
|
|
this.altNeutral = new Label5();
|
|
this.background = new StatusBarBackground();
|
|
this.layoutStyle = "block";
|
|
this.id = "status-bar";
|
|
this.layer = new Group8({
|
|
name: "StatusBar",
|
|
zIndex: ZIndexMap10.STATUS_BAR
|
|
});
|
|
this.labelGroup = this.layer.appendChild(new _ModuleSupport121.TranslatableGroup());
|
|
this.backgroundNode = this.labelGroup.appendChild(new Rect5());
|
|
this.labels = [
|
|
{
|
|
label: "O",
|
|
configuration: 2 /* Open */,
|
|
title: this.labelGroup.appendChild(new Text()),
|
|
value: this.labelGroup.appendChild(new Text()),
|
|
id: "openValue",
|
|
key: "openKey",
|
|
domain: void 0,
|
|
formatter: new Intl.NumberFormat("en-US", {
|
|
minimumFractionDigits: 2,
|
|
maximumFractionDigits: 2
|
|
})
|
|
},
|
|
{
|
|
label: "H",
|
|
configuration: 16 /* High */,
|
|
title: this.labelGroup.appendChild(new Text()),
|
|
value: this.labelGroup.appendChild(new Text()),
|
|
id: "highValue",
|
|
key: "highKey",
|
|
domain: void 0,
|
|
formatter: new Intl.NumberFormat("en-US", {
|
|
minimumFractionDigits: 2,
|
|
maximumFractionDigits: 2
|
|
})
|
|
},
|
|
{
|
|
label: "H",
|
|
configuration: 256 /* NeutralHigh */,
|
|
title: this.labelGroup.appendChild(new Text()),
|
|
value: this.labelGroup.appendChild(new Text()),
|
|
style: "neutral",
|
|
id: "highValue",
|
|
key: "highKey",
|
|
domain: void 0,
|
|
formatter: new Intl.NumberFormat("en-US", {
|
|
minimumFractionDigits: 2,
|
|
maximumFractionDigits: 2
|
|
})
|
|
},
|
|
{
|
|
label: "L",
|
|
configuration: 8 /* Low */,
|
|
title: this.labelGroup.appendChild(new Text()),
|
|
value: this.labelGroup.appendChild(new Text()),
|
|
id: "lowValue",
|
|
key: "lowKey",
|
|
domain: void 0,
|
|
formatter: new Intl.NumberFormat("en-US", {
|
|
minimumFractionDigits: 2,
|
|
maximumFractionDigits: 2
|
|
})
|
|
},
|
|
{
|
|
label: "L",
|
|
configuration: 512 /* NeutralLow */,
|
|
title: this.labelGroup.appendChild(new Text()),
|
|
value: this.labelGroup.appendChild(new Text()),
|
|
style: "neutral",
|
|
id: "lowValue",
|
|
key: "lowKey",
|
|
domain: void 0,
|
|
formatter: new Intl.NumberFormat("en-US", {
|
|
minimumFractionDigits: 2,
|
|
maximumFractionDigits: 2
|
|
})
|
|
},
|
|
{
|
|
label: "C",
|
|
configuration: 4 /* Close */,
|
|
title: this.labelGroup.appendChild(new Text()),
|
|
value: this.labelGroup.appendChild(new Text()),
|
|
id: "closeValue",
|
|
key: "closeKey",
|
|
domain: void 0,
|
|
formatter: new Intl.NumberFormat("en-US", {
|
|
minimumFractionDigits: 2,
|
|
maximumFractionDigits: 2
|
|
})
|
|
},
|
|
{
|
|
label: "C",
|
|
configuration: 128 /* NeutralClose */,
|
|
title: this.labelGroup.appendChild(new Text()),
|
|
value: this.labelGroup.appendChild(new Text()),
|
|
id: "closeValue",
|
|
key: "closeKey",
|
|
style: "neutral",
|
|
domain: void 0,
|
|
formatter: new Intl.NumberFormat("en-US", {
|
|
minimumFractionDigits: 2,
|
|
maximumFractionDigits: 2
|
|
})
|
|
},
|
|
{
|
|
label: "",
|
|
configuration: 64 /* UnlabelledClose */,
|
|
title: this.labelGroup.appendChild(new Text()),
|
|
value: this.labelGroup.appendChild(new Text()),
|
|
style: "neutral",
|
|
id: "closeValue",
|
|
key: "closeKey",
|
|
domain: void 0,
|
|
formatter: new Intl.NumberFormat("en-US", {
|
|
notation: "compact",
|
|
minimumFractionDigits: 2,
|
|
maximumFractionDigits: 2
|
|
})
|
|
},
|
|
{
|
|
label: "Vol",
|
|
configuration: 32 /* Volume */,
|
|
title: this.labelGroup.appendChild(new Text()),
|
|
value: this.labelGroup.appendChild(new Text()),
|
|
id: "volumeValue",
|
|
key: "volumeKey",
|
|
domain: void 0,
|
|
formatter: new Intl.NumberFormat("en-US", {
|
|
notation: "compact",
|
|
minimumFractionDigits: 2,
|
|
maximumFractionDigits: 2
|
|
})
|
|
}
|
|
];
|
|
this.highlightManager = ctx.highlightManager;
|
|
this.labelGroup.visible = false;
|
|
this.cleanup.register(
|
|
ctx.scene.attachNode(this.layer),
|
|
ctx.layoutManager.registerElement(LayoutElement5.Overlay, (e) => this.startPerformLayout(e)),
|
|
ctx.eventsHub.on("layout:complete", (e) => this.onLayoutComplete(e)),
|
|
ctx.eventsHub.on("highlight:change", () => this.updateHighlight()),
|
|
ctx.eventsHub.on("data:update", (data) => {
|
|
this.chartData = data;
|
|
})
|
|
);
|
|
}
|
|
updateDomainsFromSeries() {
|
|
if (!this.enabled)
|
|
return;
|
|
const series = this.ctx.chartService.series;
|
|
if (series.length === 0)
|
|
return;
|
|
let priceDomain;
|
|
let volumeDomain;
|
|
for (const s of series) {
|
|
const domainResult = s.getDomain(ChartAxisDirection30.Y);
|
|
const yDomain = domainResult?.domain;
|
|
if (!Array.isArray(yDomain) || yDomain.length < 2)
|
|
continue;
|
|
if (s.type === "bar") {
|
|
volumeDomain = [yDomain[0], yDomain.at(-1)];
|
|
} else {
|
|
priceDomain = [yDomain[0], yDomain.at(-1)];
|
|
}
|
|
}
|
|
for (const label of this.labels) {
|
|
const key = this[label.key];
|
|
if (key == null) {
|
|
label.domain = void 0;
|
|
continue;
|
|
}
|
|
label.domain = label.key === "volumeKey" ? volumeDomain : priceDomain;
|
|
}
|
|
}
|
|
startPerformLayout({ layoutBox }) {
|
|
this.labelGroup.translationX = 0;
|
|
this.labelGroup.translationY = 0;
|
|
if (!this.enabled) {
|
|
this.labelGroup.visible = false;
|
|
return;
|
|
}
|
|
this.updateDomainsFromSeries();
|
|
const innerSpacing = 4;
|
|
const outerSpacing = 12;
|
|
const spacingAbove = 0;
|
|
const spacingBelow = 8;
|
|
this.labelGroup.translationY = layoutBox.y + spacingAbove;
|
|
const maxFontSize = Math.max(this.title.fontSize, this.positive.fontSize, this.negative.fontSize);
|
|
const lineHeight = calcLineHeight5(maxFontSize);
|
|
const labelConfigurations = chartConfigurations[this.getChartType()] ?? 0;
|
|
let left = 0;
|
|
let offsetTop;
|
|
let textVAlign = "alphabetic";
|
|
if (this.layoutStyle === "block") {
|
|
layoutBox.shrink(spacingAbove + lineHeight + spacingBelow, "top");
|
|
offsetTop = maxFontSize + (lineHeight - maxFontSize) / 2;
|
|
} else {
|
|
const { title } = this.ctx.chartService;
|
|
textVAlign = "top";
|
|
offsetTop = spacingAbove + title.padding;
|
|
if (title.enabled) {
|
|
const titleBox = title.node.getBBox();
|
|
left = titleBox.x + titleBox.width + outerSpacing;
|
|
} else {
|
|
left = title.padding;
|
|
}
|
|
}
|
|
for (const { label, configuration, title, value, domain, formatter } of this.labels) {
|
|
if (domain == null || (labelConfigurations & configuration) === 0) {
|
|
title.visible = false;
|
|
value.visible = false;
|
|
continue;
|
|
}
|
|
const positiveTextMeasurer = cachedTextMeasurer3(this.positive);
|
|
const negativeTextMeasurer = cachedTextMeasurer3(this.negative);
|
|
const maxValueWidth = Math.max(
|
|
positiveTextMeasurer.textWidth(formatter.format(domain[0])),
|
|
positiveTextMeasurer.textWidth(formatter.format(domain[1])),
|
|
negativeTextMeasurer.textWidth(formatter.format(domain[0])),
|
|
negativeTextMeasurer.textWidth(formatter.format(domain[1]))
|
|
);
|
|
title.visible = true;
|
|
value.visible = true;
|
|
const titleMetrics = cachedTextMeasurer3(this.title).measureLines(label);
|
|
title.setFont(this.title);
|
|
title.fill = this.title.color;
|
|
title.text = label;
|
|
title.textBaseline = textVAlign;
|
|
title.y = offsetTop;
|
|
title.x = left;
|
|
left += titleMetrics.width + innerSpacing;
|
|
value.textBaseline = textVAlign;
|
|
value.y = offsetTop;
|
|
value.x = left;
|
|
left += maxValueWidth + outerSpacing;
|
|
}
|
|
this.backgroundNode.x = 0;
|
|
this.backgroundNode.y = 0;
|
|
this.backgroundNode.width = left - outerSpacing;
|
|
this.backgroundNode.height = lineHeight + spacingAbove + spacingBelow;
|
|
this.backgroundNode.fill = this.background.fill;
|
|
this.backgroundNode.fillOpacity = this.background.fillOpacity;
|
|
}
|
|
onLayoutComplete(opts) {
|
|
this.labelGroup.translationX = opts.series.rect.x;
|
|
this.updateHighlight();
|
|
}
|
|
updateHighlight() {
|
|
if (!this.enabled)
|
|
return;
|
|
const activeHighlight = this.highlightManager.getActiveHighlight();
|
|
const datum = activeHighlight?.datum ?? this.chartData?.data?.at(-1);
|
|
if (datum == null) {
|
|
this.labelGroup.visible = false;
|
|
return;
|
|
}
|
|
this.labelGroup.visible = true;
|
|
const itemId = activeHighlight?.itemId;
|
|
let baseStyle = itemId == null ? void 0 : itemIdMap[itemId];
|
|
if (baseStyle == null && this.openKey != null && this.closeKey != null) {
|
|
if (datum[this.openKey] < datum[this.closeKey]) {
|
|
baseStyle = "positive";
|
|
} else {
|
|
baseStyle = "negative";
|
|
}
|
|
}
|
|
for (const { domain, value, key, formatter, style } of this.labels) {
|
|
if (domain == null)
|
|
continue;
|
|
let labelStyle = style ?? baseStyle ?? "neutral";
|
|
if (labelStyle === "neutral") {
|
|
labelStyle = neutralColorMap[this.getChartType()] ?? labelStyle;
|
|
}
|
|
const datumKey = this[key];
|
|
const datumValue = datumKey == null ? void 0 : datum?.[datumKey];
|
|
value.setFont(this[labelStyle]);
|
|
value.fill = this[labelStyle].color;
|
|
value.text = typeof datumValue === "number" ? formatter.format(datumValue) : "";
|
|
}
|
|
}
|
|
getChartType() {
|
|
let chartType = this.ctx.chartService.publicApi?.getOptions()?.chartType;
|
|
if (chartType == null || chartConfigurations[chartType] == null) {
|
|
chartType = "candlestick";
|
|
}
|
|
return chartType;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property62
|
|
], StatusBar.prototype, "enabled", 2);
|
|
__decorateClass([
|
|
Property62
|
|
], StatusBar.prototype, "openKey", 2);
|
|
__decorateClass([
|
|
Property62
|
|
], StatusBar.prototype, "highKey", 2);
|
|
__decorateClass([
|
|
Property62
|
|
], StatusBar.prototype, "lowKey", 2);
|
|
__decorateClass([
|
|
Property62
|
|
], StatusBar.prototype, "closeKey", 2);
|
|
__decorateClass([
|
|
Property62
|
|
], StatusBar.prototype, "volumeKey", 2);
|
|
__decorateClass([
|
|
Property62
|
|
], StatusBar.prototype, "title", 2);
|
|
__decorateClass([
|
|
Property62
|
|
], StatusBar.prototype, "positive", 2);
|
|
__decorateClass([
|
|
Property62
|
|
], StatusBar.prototype, "negative", 2);
|
|
__decorateClass([
|
|
Property62
|
|
], StatusBar.prototype, "neutral", 2);
|
|
__decorateClass([
|
|
Property62
|
|
], StatusBar.prototype, "altNeutral", 2);
|
|
__decorateClass([
|
|
Property62
|
|
], StatusBar.prototype, "background", 2);
|
|
__decorateClass([
|
|
Property62
|
|
], StatusBar.prototype, "layoutStyle", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/features/status-bar/statusBarModule.ts
|
|
var StatusBarModule = {
|
|
type: "plugin",
|
|
name: "statusBar",
|
|
chartType: "cartesian",
|
|
enterprise: true,
|
|
version: VERSION25,
|
|
themeTemplate: {
|
|
enabled: false,
|
|
layoutStyle: DEFAULT_CAPTION_LAYOUT_STYLE,
|
|
title: {
|
|
color: { $ref: "textColor" },
|
|
fontFamily: { $ref: "fontFamily" },
|
|
fontSize: { $ref: "fontSize" },
|
|
fontWeight: { $ref: "fontWeight" }
|
|
},
|
|
positive: {
|
|
color: { $palette: "up.stroke" },
|
|
fontFamily: { $ref: "fontFamily" },
|
|
fontSize: { $ref: "fontSize" },
|
|
fontWeight: { $ref: "fontWeight" }
|
|
},
|
|
negative: {
|
|
color: { $palette: "down.stroke" },
|
|
fontFamily: { $ref: "fontFamily" },
|
|
fontSize: { $ref: "fontSize" },
|
|
fontWeight: { $ref: "fontWeight" }
|
|
},
|
|
neutral: {
|
|
color: { $palette: "neutral.stroke" },
|
|
fontFamily: { $ref: "fontFamily" },
|
|
fontSize: { $ref: "fontSize" },
|
|
fontWeight: { $ref: "fontWeight" }
|
|
},
|
|
background: {
|
|
fill: { $ref: "chartBackgroundColor" },
|
|
fillOpacity: 0.5
|
|
},
|
|
altNeutral: {
|
|
color: "gray",
|
|
fontFamily: { $ref: "fontFamily" },
|
|
fontSize: { $ref: "fontSize" },
|
|
fontWeight: { $ref: "fontWeight" }
|
|
}
|
|
},
|
|
create: (ctx) => new StatusBar(ctx)
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/sync/syncModule.ts
|
|
import { VERSION as VERSION26 } from "ag-charts-community";
|
|
import { boolean as boolean14, string as string8, union as union3 } from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/features/sync/chartSync.ts
|
|
import { _ModuleSupport as _ModuleSupport122 } from "ag-charts-community";
|
|
import {
|
|
AsyncAwaitQueue,
|
|
BaseProperties as BaseProperties25,
|
|
ChartAxisDirection as ChartAxisDirection31,
|
|
ChartUpdateType as ChartUpdateType7,
|
|
Debug as Debug12,
|
|
Logger as Logger12,
|
|
ObserveChanges as ObserveChanges5,
|
|
Property as Property63,
|
|
arraysEqual,
|
|
definedZoomState,
|
|
findMinMax as findMinMax4,
|
|
isDate as isDate3,
|
|
isDefined as isDefined2,
|
|
isFiniteNumber,
|
|
isObjectWithStringProperty,
|
|
unique
|
|
} from "ag-charts-core";
|
|
var { CartesianAxis, ContinuousScale: ContinuousScale4, TimeScale, UnitTimeScale, TooltipManager } = _ModuleSupport122;
|
|
var debug = Debug12.create("sync");
|
|
function getDirectionKeys(series, primary, secondary) {
|
|
const primaryKeys = series.getKeys(primary);
|
|
const secondaryKeys = series.getKeys(secondary);
|
|
if (series.shouldFlipXY?.()) {
|
|
return [secondaryKeys, primaryKeys];
|
|
}
|
|
return [primaryKeys, secondaryKeys];
|
|
}
|
|
function syncedDirections(axes = "x") {
|
|
switch (axes) {
|
|
case "x":
|
|
return [ChartAxisDirection31.X];
|
|
case "y":
|
|
return [ChartAxisDirection31.Y];
|
|
case "xy":
|
|
return [ChartAxisDirection31.X, ChartAxisDirection31.Y];
|
|
}
|
|
}
|
|
function domainChanged(scale, a, b) {
|
|
if (TimeScale.is(scale) || UnitTimeScale.is(scale)) {
|
|
return !arraysEqual(
|
|
a.map((x) => x?.valueOf()),
|
|
b.map((x) => x?.valueOf())
|
|
);
|
|
} else {
|
|
return !arraysEqual(a, b);
|
|
}
|
|
}
|
|
var ChartSync = class extends BaseProperties25 {
|
|
constructor(moduleContext) {
|
|
super();
|
|
this.moduleContext = moduleContext;
|
|
this.enabled = false;
|
|
this.axes = "x";
|
|
this.nodeInteraction = true;
|
|
this.zoom = true;
|
|
this.domainMode = "id";
|
|
this.domainSync = new AsyncAwaitQueue();
|
|
}
|
|
updateSiblings(groupId) {
|
|
const { syncManager } = this.moduleContext;
|
|
for (const chart of syncManager.getGroupSiblings(groupId ?? this.groupId)) {
|
|
debug("ChartSync.updateSiblings()", chart.id, chart);
|
|
this.updateChart(chart);
|
|
}
|
|
}
|
|
updateChart(chart, updateType = ChartUpdateType7.PROCESS_DOMAIN) {
|
|
debug("ChartSync.updateChart()", chart.id, ChartUpdateType7[updateType], chart);
|
|
if (updateType === ChartUpdateType7.PROCESS_DOMAIN) {
|
|
chart.ctx.updateService.update(updateType, { forceNodeDataRefresh: true });
|
|
} else {
|
|
chart.ctx.updateService.update(updateType);
|
|
}
|
|
}
|
|
enabledZoomSync() {
|
|
const { eventsHub } = this.moduleContext;
|
|
this.disableZoomSync?.();
|
|
this.disableZoomSync = eventsHub.on("zoom:change-complete", (e) => this.onZoom(e));
|
|
}
|
|
onZoom(e) {
|
|
const { syncManager } = this.moduleContext;
|
|
for (const chart of syncManager.getGroupSiblings(this.groupId)) {
|
|
const syncModule = chart.modulesManager.getModule("sync");
|
|
if (!syncModule?.zoom)
|
|
continue;
|
|
const zoomModule = chart.modulesManager.getModule("zoom");
|
|
if (!zoomModule)
|
|
continue;
|
|
const zoom = this.prepareZoomUpdate();
|
|
if (e.source !== "sync") {
|
|
debug("ChartsSyncManager.enabledZoomSync()", chart.id, zoom);
|
|
zoomModule.updateSyncZoom(zoom);
|
|
}
|
|
}
|
|
}
|
|
enabledNodeInteractionSync() {
|
|
this.disableNodeInteractionSync?.();
|
|
const offHighlightChange = this.moduleContext.eventsHub.on(
|
|
"highlight:change",
|
|
this.onHighlightChange.bind(this)
|
|
);
|
|
const offActiveChangeListener = this.moduleContext.eventsHub.on(
|
|
"active:load-memento",
|
|
this.onActiveLoadMemento.bind(this)
|
|
);
|
|
this.disableNodeInteractionSync = () => {
|
|
offHighlightChange();
|
|
offActiveChangeListener();
|
|
};
|
|
}
|
|
onHighlightChange(event) {
|
|
const { syncManager } = this.moduleContext;
|
|
if (event.callerId.endsWith("-sync"))
|
|
return;
|
|
debug("ChartSync.onHighlightChange()", event);
|
|
const series = event.currentHighlight?.series;
|
|
const [mainDirection] = syncedDirections(this.axes);
|
|
const secondaryDirection = mainDirection === ChartAxisDirection31.X ? ChartAxisDirection31.Y : ChartAxisDirection31.X;
|
|
const [primaryKeys, secondaryKeys] = series ? getDirectionKeys(series, mainDirection, secondaryDirection) : [];
|
|
const datum = readDatum(event.currentHighlight);
|
|
let eventValue = primaryKeys?.[0] ? datum?.[primaryKeys[0]] : void 0;
|
|
let valueIsDate = false;
|
|
if (isDate3(eventValue)) {
|
|
valueIsDate = true;
|
|
eventValue = eventValue.getTime();
|
|
}
|
|
if (!event.currentHighlight?.datum) {
|
|
for (const chart of syncManager.getGroupSiblings(this.groupId)) {
|
|
const syncModule = chart.modulesManager.getModule("sync");
|
|
if (!syncModule?.nodeInteraction)
|
|
continue;
|
|
chart.ctx.highlightManager.updateHighlight(`${chart.id}-sync`, void 0, true);
|
|
chart.ctx.tooltipManager.removeTooltip(`${chart.id}-sync`, void 0, true);
|
|
}
|
|
return;
|
|
}
|
|
const useSecondaryDirectionKey = syncManager.getGroupSyncMode(this.groupId) === "multi-series";
|
|
this.findMatchingHighlightNodes(
|
|
mainDirection,
|
|
secondaryDirection,
|
|
useSecondaryDirectionKey ? secondaryKeys : [],
|
|
valueIsDate,
|
|
eventValue,
|
|
event
|
|
);
|
|
}
|
|
onActiveLoadMemento(event) {
|
|
const { activeItem, chartId } = event;
|
|
if (activeItem === void 0) {
|
|
this.moduleContext.highlightManager.updateHighlight(`${chartId}-sync`, void 0, false);
|
|
this.moduleContext.tooltipManager.removeTooltip(`${chartId}-sync`, void 0, false);
|
|
for (const chart of this.moduleContext.syncManager.getGroupSiblings(this.groupId)) {
|
|
chart.onSyncActiveClear();
|
|
}
|
|
}
|
|
}
|
|
findMatchingHighlightNodes(primaryDirection, secondaryDirection, secondaryKeys, valueIsDate, eventValue, event) {
|
|
const { syncManager } = this.moduleContext;
|
|
debug("ChartSync.findMatchingHighlightNodes()", {
|
|
mainDirection: primaryDirection,
|
|
secondaryKeys
|
|
});
|
|
for (const chart of syncManager.getGroupSiblings(this.groupId)) {
|
|
const syncModule = chart.modulesManager.getModule("sync");
|
|
if (!syncModule?.nodeInteraction)
|
|
continue;
|
|
let dispatched = false;
|
|
for (const axis of chart.axes) {
|
|
if (!CartesianAxis.is(axis) || axis.direction !== primaryDirection)
|
|
continue;
|
|
const matchingNodes = chart.series.filter((s) => {
|
|
if (!s.visible)
|
|
return false;
|
|
if (secondaryKeys.length > 0) {
|
|
const [, seriesKeys] = getDirectionKeys(s, primaryDirection, secondaryDirection);
|
|
return secondaryKeys.every((key) => seriesKeys.includes(key));
|
|
}
|
|
return true;
|
|
}).map(this.findMatchingNodes(axis, primaryDirection, valueIsDate, eventValue)).filter(isDefined2);
|
|
if (matchingNodes.length === 1 && matchingNodes[0]?.nodeDatum !== chart.ctx.highlightManager.getActiveHighlight()) {
|
|
this.dispatchHighlightUpdate(chart, matchingNodes[0].nodeDatum);
|
|
dispatched = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!dispatched) {
|
|
debug("ChartSync.findMatchingHighlightNodes() - no matching nodes", chart.id, event);
|
|
this.dispatchHighlightUpdate(chart);
|
|
}
|
|
}
|
|
}
|
|
findMatchingNodes(axis, mainDirection, valueIsDate, eventValue) {
|
|
return (series) => {
|
|
const seriesKeyAxis = series.getKeyAxis(axis.direction);
|
|
if (seriesKeyAxis !== axis.id)
|
|
return;
|
|
const nodeData = series.contextNodeData?.nodeData ?? [];
|
|
if (!nodeData?.length)
|
|
return;
|
|
const firstNode = nodeData[0];
|
|
const mainDirectionKey = `${mainDirection}Key`;
|
|
if (!isObjectWithStringProperty(firstNode, mainDirectionKey))
|
|
return;
|
|
const valueKey = firstNode[mainDirectionKey];
|
|
const nodeDatum = nodeData.find((datum) => {
|
|
const nodeValue = datum.datum[valueKey];
|
|
return valueIsDate ? nodeValue.getTime() === eventValue : nodeValue === eventValue;
|
|
});
|
|
return nodeDatum ? { series, nodeDatum } : null;
|
|
};
|
|
}
|
|
dispatchHighlightUpdate(chart, nodeDatum) {
|
|
debug("ChartSync.dispatchHighlightUpdate()", chart.id, nodeDatum);
|
|
const delayed = nodeDatum == null;
|
|
chart.ctx.highlightManager.updateHighlight(`${chart.id}-sync`, nodeDatum, delayed);
|
|
const tooltipEnabled = nodeDatum?.series.tooltipEnabled ?? chart.tooltip.enabled;
|
|
if (nodeDatum && tooltipEnabled) {
|
|
const bbox = chart.seriesAreaBoundingBox;
|
|
const canvasX = bbox.x + (nodeDatum.midPoint?.x ?? nodeDatum.point?.x ?? 0);
|
|
const canvasY = bbox.y + (nodeDatum.midPoint?.y ?? nodeDatum.point?.y ?? 0);
|
|
const tooltipMeta = TooltipManager.makeTooltipMeta(
|
|
{ type: "pointermove", canvasX, canvasY },
|
|
nodeDatum.series,
|
|
nodeDatum,
|
|
void 0
|
|
);
|
|
chart.ctx.tooltipManager.updateTooltip(
|
|
`${chart.id}-sync`,
|
|
tooltipMeta,
|
|
chart.getTooltipContent(nodeDatum.series, nodeDatum.datumIndex, nodeDatum, "tooltip")
|
|
);
|
|
} else {
|
|
chart.ctx.tooltipManager.removeTooltip(`${chart.id}-sync`, void 0, true);
|
|
}
|
|
this.updateChart(chart, ChartUpdateType7.SERIES_UPDATE);
|
|
}
|
|
async getSyncedDomain(axis) {
|
|
if (!CartesianAxis.is(axis) || this.axes !== "xy" && this.axes !== axis.direction) {
|
|
return;
|
|
}
|
|
const { groupState, directionDomains, idDomains, positionDomains } = this.updateDomainState(axis);
|
|
this.validateAxis(axis, groupState);
|
|
await this.waitForDomainsToBeReady();
|
|
if (this.domainMode === "position") {
|
|
return this.calculateDerivedDomain(axis, positionDomains);
|
|
}
|
|
if (this.domainMode === "direction") {
|
|
return this.calculateDerivedDomain(axis, directionDomains);
|
|
}
|
|
return this.calculateDerivedDomain(axis, idDomains);
|
|
}
|
|
updateDomainState(axis) {
|
|
var _a, _b, _c, _d, _e;
|
|
const { syncManager } = this.moduleContext;
|
|
const chartId = syncManager.getChart().id;
|
|
const axisId = axis.id;
|
|
const groupState = syncManager.getGroupState(this.groupId);
|
|
if (!groupState)
|
|
throw new Error("AG Charts - no GroupState for groupId: " + this.groupId);
|
|
const domainsByDirection = groupState.domains ?? (groupState.domains = {});
|
|
const directionDomains = domainsByDirection[_a = axis.direction] ?? (domainsByDirection[_a] = { derived: [], sources: {}, dirty: true });
|
|
const chartDirectionDomains = (_b = directionDomains.sources)[chartId] ?? (_b[chartId] = {});
|
|
chartDirectionDomains[axisId] = axis.dataDomain.domain;
|
|
directionDomains.dirty = true;
|
|
const domainsById = groupState.domainsById ?? (groupState.domainsById = {});
|
|
const idDomains = domainsById[axisId] ?? (domainsById[axisId] = { derived: [], sources: {}, dirty: true });
|
|
const chartIdDomains = (_c = idDomains.sources)[chartId] ?? (_c[chartId] = {});
|
|
chartIdDomains[axisId] = axis.dataDomain.domain;
|
|
idDomains.dirty = true;
|
|
const domainsByPosition = groupState.domainsByPosition ?? (groupState.domainsByPosition = {});
|
|
const positionDomains = domainsByPosition[_d = axis.position] ?? (domainsByPosition[_d] = { derived: [], sources: {}, dirty: true });
|
|
const chartPositionDomains = (_e = positionDomains.sources)[chartId] ?? (_e[chartId] = {});
|
|
chartPositionDomains[axisId] = axis.dataDomain.domain;
|
|
positionDomains.dirty = true;
|
|
return { groupState, directionDomains, idDomains, positionDomains };
|
|
}
|
|
validateAxis(axis, groupState) {
|
|
const multiSeries = this.moduleContext.syncManager.getGroupSyncMode(this.groupId) === "multi-series";
|
|
if (!syncedDirections(this.axes).includes(axis.direction))
|
|
return;
|
|
if (multiSeries) {
|
|
this.validateMultiSeries(axis, groupState);
|
|
} else {
|
|
this.validateSingleSeries(axis, groupState);
|
|
}
|
|
}
|
|
validateMultiSeries(axis, groupState) {
|
|
const { min, max, nice, reverse } = axis;
|
|
const matchingKeys = new Set(axis.boundSeries.flatMap((s) => s.getKeys(axis.direction)));
|
|
for (const member of groupState.members) {
|
|
const { axes, modulesManager } = member;
|
|
const syncModule = modulesManager.getModule("sync");
|
|
const memberSyncDirections = syncedDirections(syncModule?.axes);
|
|
const keyMatchedAxes = axes.filter((a) => memberSyncDirections.includes(a.direction)).filter((a) => a.boundSeries.some((s) => s.getKeys(a.direction).some((k) => matchingKeys.has(k))));
|
|
if (keyMatchedAxes.length === 0)
|
|
continue;
|
|
const [firstAxis] = keyMatchedAxes;
|
|
if (firstAxis.min !== min || firstAxis.max !== max || firstAxis.nice !== nice || firstAxis.reverse !== reverse) {
|
|
Logger12.warnOnce(
|
|
"To allow synchronization, ensure that all synchronized axes with matching keys have matching min, max, nice, and reverse properties."
|
|
);
|
|
this.enabled = false;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
validateSingleSeries(axis, groupState) {
|
|
const members = groupState.members;
|
|
const [{ axes: syncAxes }] = members;
|
|
const { direction, min, max, nice, reverse } = axis;
|
|
for (const nextAxis of syncAxes) {
|
|
if (direction !== nextAxis.direction)
|
|
continue;
|
|
if (nice !== nextAxis.nice || reverse !== nextAxis.reverse || min !== nextAxis.min && (isFiniteNumber(min) || isFiniteNumber(nextAxis.min)) || max !== nextAxis.max && (isFiniteNumber(max) || isFiniteNumber(nextAxis.max))) {
|
|
Logger12.warnOnce(
|
|
"To allow synchronization, ensure that all charts have matching min, max, nice, and reverse properties on the synchronized axes."
|
|
);
|
|
this.enabled = false;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
calculateDerivedDomain(axis, domains) {
|
|
if (!domains.dirty)
|
|
return domains.derived;
|
|
let previousDerived = domains.derived;
|
|
const newDerivedBySource = Object.values(domains.sources).map((d) => Object.values(d));
|
|
let newDerived;
|
|
if (ContinuousScale4.is(axis.scale)) {
|
|
newDerived = newDerivedBySource.flat(2);
|
|
} else {
|
|
newDerived = newDerivedBySource.flat().toSorted((a, b) => a.length > b.length ? -1 : 1).flat();
|
|
}
|
|
domains.derived = unique(newDerived);
|
|
if (ContinuousScale4.is(axis.scale)) {
|
|
previousDerived = findMinMax4(previousDerived);
|
|
domains.derived = findMinMax4(domains.derived);
|
|
}
|
|
domains.dirty = false;
|
|
if (domainChanged(axis.scale, previousDerived, domains.derived)) {
|
|
debug(axis.id, "updated", { before: previousDerived, after: domains.derived });
|
|
this.updateSiblings();
|
|
}
|
|
return domains.derived;
|
|
}
|
|
removeAxis(axis) {
|
|
if (!CartesianAxis.is(axis) || this.axes !== "xy" && this.axes !== axis.direction) {
|
|
return;
|
|
}
|
|
const { syncManager } = this.moduleContext;
|
|
const syncGroup = syncManager.getGroupState(this.groupId);
|
|
const chartId = syncManager.getChart().id;
|
|
const axisId = axis.id;
|
|
delete syncGroup?.domains?.[axis.direction]?.sources?.[chartId]?.[axisId];
|
|
delete syncGroup?.domainsByPosition?.[axis.position]?.sources?.[chartId]?.[axisId];
|
|
delete syncGroup?.domainsById?.[axisId]?.sources?.[chartId]?.[axisId];
|
|
}
|
|
async waitForDomainsToBeReady() {
|
|
const { syncManager } = this.moduleContext;
|
|
let count = 0;
|
|
while (syncManager.getGroupMembers(this.groupId).some((c) => c.syncStatus === "init")) {
|
|
debug("ChartSync.waitForDomainsToBeReady() - waiting for all domains to be calculated", this.groupId);
|
|
await this.domainSync.waitForCompletion();
|
|
count++;
|
|
}
|
|
if (count > 0) {
|
|
debug("ChartSync.waitForDomainsToBeReady() - waited for", count, "iterations");
|
|
}
|
|
this.domainSync.notify();
|
|
}
|
|
prepareZoomUpdate() {
|
|
const { zoomManager } = this.moduleContext;
|
|
const zoom = zoomManager.getZoom();
|
|
if (this.axes === "x") {
|
|
delete zoom?.y;
|
|
} else if (this.axes === "y") {
|
|
delete zoom?.x;
|
|
}
|
|
return definedZoomState(zoom);
|
|
}
|
|
onEnabledChange() {
|
|
const { syncManager, highlightManager } = this.moduleContext;
|
|
if (this.enabled) {
|
|
syncManager.subscribe(this.groupId);
|
|
highlightManager.unhighlightDelay = 0;
|
|
} else {
|
|
syncManager.unsubscribe(this.groupId);
|
|
highlightManager.unhighlightDelay = 100;
|
|
}
|
|
this.updateSiblings();
|
|
this.onNodeInteractionChange();
|
|
this.onZoomChange();
|
|
}
|
|
onGroupIdChange(newValue, oldValue) {
|
|
if (!this.enabled || newValue === oldValue)
|
|
return;
|
|
const { syncManager } = this.moduleContext;
|
|
syncManager.unsubscribe(oldValue);
|
|
syncManager.subscribe(newValue);
|
|
this.updateSiblings(oldValue);
|
|
this.updateSiblings(newValue);
|
|
}
|
|
onAxesChange() {
|
|
if (!this.enabled)
|
|
return;
|
|
const { syncManager } = this.moduleContext;
|
|
this.updateChart(syncManager.getChart());
|
|
}
|
|
onNodeInteractionChange() {
|
|
if (this.enabled && this.nodeInteraction) {
|
|
this.enabledNodeInteractionSync();
|
|
} else {
|
|
this.disableNodeInteractionSync?.();
|
|
}
|
|
}
|
|
onZoomChange() {
|
|
if (this.enabled && this.zoom) {
|
|
this.enabledZoomSync();
|
|
} else {
|
|
this.disableZoomSync?.();
|
|
}
|
|
}
|
|
destroy() {
|
|
const { syncManager } = this.moduleContext;
|
|
syncManager.unsubscribe(this.groupId);
|
|
this.updateSiblings();
|
|
this.disableZoomSync?.();
|
|
}
|
|
};
|
|
ChartSync.className = "Sync";
|
|
__decorateClass([
|
|
Property63,
|
|
ObserveChanges5((target) => target.onEnabledChange())
|
|
], ChartSync.prototype, "enabled", 2);
|
|
__decorateClass([
|
|
Property63,
|
|
ObserveChanges5((target, newValue, oldValue) => target.onGroupIdChange(newValue, oldValue))
|
|
], ChartSync.prototype, "groupId", 2);
|
|
__decorateClass([
|
|
Property63,
|
|
ObserveChanges5((target) => target.onAxesChange())
|
|
], ChartSync.prototype, "axes", 2);
|
|
__decorateClass([
|
|
Property63,
|
|
ObserveChanges5((target) => target.onNodeInteractionChange())
|
|
], ChartSync.prototype, "nodeInteraction", 2);
|
|
__decorateClass([
|
|
Property63,
|
|
ObserveChanges5((target) => target.onZoomChange())
|
|
], ChartSync.prototype, "zoom", 2);
|
|
__decorateClass([
|
|
Property63,
|
|
ObserveChanges5((target) => target.onAxesChange())
|
|
], ChartSync.prototype, "domainMode", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/features/sync/syncModule.ts
|
|
var SyncModule = {
|
|
type: "plugin",
|
|
name: "sync",
|
|
chartType: "cartesian",
|
|
enterprise: true,
|
|
version: VERSION26,
|
|
options: {
|
|
enabled: boolean14,
|
|
groupId: string8,
|
|
axes: union3("x", "y", "xy"),
|
|
nodeInteraction: boolean14,
|
|
zoom: boolean14
|
|
},
|
|
themeTemplate: { enabled: false },
|
|
create: (ctx) => new ChartSync(ctx)
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/zoom/zoomModule.ts
|
|
import { VERSION as VERSION27 } from "ag-charts-community";
|
|
import {
|
|
arrayOfDefs as arrayOfDefs4,
|
|
boolean as boolean15,
|
|
or as or2,
|
|
positiveNumber as positiveNumber7,
|
|
ratio as ratio6,
|
|
strictUnion as strictUnion2,
|
|
string as string9,
|
|
toolbarButtonOptionsDefs as toolbarButtonOptionsDefs2,
|
|
undocumented as undocumented8,
|
|
union as union4
|
|
} from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/features/zoom/zoom.ts
|
|
import { _ModuleSupport as _ModuleSupport133 } from "ag-charts-community";
|
|
import {
|
|
AbstractModuleInstance as AbstractModuleInstance16,
|
|
ActionOnSet as ActionOnSet9,
|
|
ChartAxisDirection as ChartAxisDirection40,
|
|
ChartUpdateType as ChartUpdateType8,
|
|
Property as Property67,
|
|
ProxyProperty as ProxyProperty3,
|
|
UNIT_MAX as UNIT_MAX4,
|
|
UNIT_MIN as UNIT_MIN4,
|
|
debounce as debounce3,
|
|
definedZoomState as definedZoomState11,
|
|
entries as entries10,
|
|
roundTo
|
|
} from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/features/zoom/scenes/zoomRect.ts
|
|
import { _ModuleSupport as _ModuleSupport123 } from "ag-charts-community";
|
|
import { ZIndexMap as ZIndexMap11 } from "ag-charts-core";
|
|
var VALID_COLOR = "#2196f3";
|
|
var INVALID_COLOR = "#8a8a8a";
|
|
var ZoomRect = class extends _ModuleSupport123.Rect {
|
|
constructor() {
|
|
super();
|
|
this.fill = VALID_COLOR;
|
|
this.fillOpacity = 0.2;
|
|
this.zIndex = ZIndexMap11.ZOOM_SELECTION;
|
|
}
|
|
updateValid() {
|
|
this.fill = VALID_COLOR;
|
|
}
|
|
updateInvalid() {
|
|
this.fill = INVALID_COLOR;
|
|
}
|
|
};
|
|
ZoomRect.className = "ZoomRect";
|
|
|
|
// packages/ag-charts-enterprise/src/features/zoom/zoomAutoScale.ts
|
|
import "ag-charts-community";
|
|
import {
|
|
BaseProperties as BaseProperties26,
|
|
ChartAxisDirection as ChartAxisDirection32,
|
|
Property as Property64,
|
|
isFiniteNumber as isFiniteNumber2,
|
|
objectsEqual,
|
|
strictObjectKeys
|
|
} from "ag-charts-core";
|
|
var ZoomAutoScalingProperties = class extends BaseProperties26 {
|
|
constructor() {
|
|
super();
|
|
this.enabled = false;
|
|
this.padding = 0;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property64
|
|
], ZoomAutoScalingProperties.prototype, "enabled", 2);
|
|
__decorateClass([
|
|
Property64
|
|
], ZoomAutoScalingProperties.prototype, "padding", 2);
|
|
var ZoomAutoScaler = class {
|
|
constructor(properties, zoomManager, deps, eventsHub, eventsCleanup) {
|
|
this.properties = properties;
|
|
this.zoomManager = zoomManager;
|
|
this.deps = deps;
|
|
this.manuallyAdjusted = false;
|
|
eventsCleanup.register(
|
|
eventsHub.on("zoom:save-memento", (e) => this.onSaveMemento(e)),
|
|
eventsHub.on("zoom:load-memento", (e) => this.onLoadMemento(e)),
|
|
eventsHub.on("zoom:change-request", (e) => this.onChangeRequest(e))
|
|
);
|
|
}
|
|
get enabled() {
|
|
return this.deps.enabled && this.properties.enabled && !this.manuallyAdjusted;
|
|
}
|
|
onManualAdjustment(direction) {
|
|
if (direction === ChartAxisDirection32.Y) {
|
|
this.manuallyAdjusted = true;
|
|
}
|
|
}
|
|
onChangeRequest(event) {
|
|
const hasYAxisChange = this.hasYAxisChange(event);
|
|
if (event.sourceDetail === "scrollbar" && hasYAxisChange) {
|
|
this.manuallyAdjusted = true;
|
|
}
|
|
if (event.isReset && hasYAxisChange) {
|
|
this.manuallyAdjusted = false;
|
|
}
|
|
if (this.enabled) {
|
|
const constrainedZoom = this.autoScaleYZoom(event.state);
|
|
if (constrainedZoom) {
|
|
event.constrainChanges(constrainedZoom);
|
|
}
|
|
}
|
|
}
|
|
hasYAxisChange(event) {
|
|
for (const id of event.changedAxes) {
|
|
if (event.state[id]?.direction === ChartAxisDirection32.Y) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
onSaveMemento(event) {
|
|
event.memento.autoScaledAxes = this.enabled ? ["y"] : void 0;
|
|
}
|
|
onLoadMemento(event) {
|
|
const { zoom, memento, navigatorModule, zoomModule } = event;
|
|
if (!navigatorModule || zoomModule) {
|
|
let yAutoScale = memento?.autoScaledAxes?.includes("y");
|
|
if (memento?.rangeY) {
|
|
yAutoScale ?? (yAutoScale = false);
|
|
zoom.y = this.zoomManager.rangeToRatioDirection(ChartAxisDirection32.Y, memento.rangeY) ?? {
|
|
min: 0,
|
|
max: 1
|
|
};
|
|
} else if (memento?.ratioY) {
|
|
yAutoScale ?? (yAutoScale = false);
|
|
zoom.y = {
|
|
min: memento.ratioY.start ?? 0,
|
|
max: memento.ratioY.end ?? 1
|
|
};
|
|
} else {
|
|
yAutoScale ?? (yAutoScale = true);
|
|
const autoZoomY = yAutoScale ? this.getAutoScaleYZoom(zoom.x) : void 0;
|
|
zoom.y = autoZoomY ?? { min: 0, max: 1 };
|
|
}
|
|
if (yAutoScale != void 0) {
|
|
this.manuallyAdjusted = !yAutoScale;
|
|
}
|
|
}
|
|
}
|
|
getAutoScaleYZoom(zoomX) {
|
|
if (!this.enabled)
|
|
return;
|
|
const { padding: padding2 } = this.properties;
|
|
let yZoom;
|
|
if (this.deps.enableIndependentAxes) {
|
|
yZoom = this.primaryAxisZoom(ChartAxisDirection32.Y, zoomX, { padding: padding2 });
|
|
} else {
|
|
yZoom = this.combinedAxisZoom(ChartAxisDirection32.Y, zoomX, { padding: padding2 });
|
|
}
|
|
if (zoomX.min === 0 && zoomX.max === 1) {
|
|
return yZoom == null ? void 0 : { min: 0, max: 1 };
|
|
} else {
|
|
return yZoom;
|
|
}
|
|
}
|
|
autoScaleYZoom(changes) {
|
|
const zoom = this.zoomManager.getZoom();
|
|
if (zoom && changes) {
|
|
const state = this.zoomManager.getAxisZooms();
|
|
for (const dir of [ChartAxisDirection32.X, ChartAxisDirection32.Y]) {
|
|
for (const id of strictObjectKeys(changes)) {
|
|
if (state[id]?.direction === dir) {
|
|
zoom[dir] = changes[id];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (zoom?.x == null)
|
|
return;
|
|
const zoomY = this.getAutoScaleYZoom(zoom.x);
|
|
if (zoomY == null || objectsEqual(zoom.y, zoomY))
|
|
return;
|
|
return this.zoomManager.toCoreZoomState({ x: zoom.x, y: zoomY });
|
|
}
|
|
zoomBounds(xAxis, yAxis, zoom, padding2) {
|
|
const xScale = xAxis.scale;
|
|
const xScaleRange = xScale.range;
|
|
xScale.range = [0, 1];
|
|
const yScale = yAxis.scale;
|
|
const yScaleRange = yScale.range;
|
|
yScale.range = [0, 1];
|
|
let min = 1;
|
|
let minPadding = false;
|
|
let max = 0;
|
|
let maxPadding = false;
|
|
for (const series of yAxis.boundSeries) {
|
|
if (!series.visible)
|
|
continue;
|
|
const { connectsToYAxis } = series;
|
|
const yValues = series.getRange(ChartAxisDirection32.Y, [zoom.min, zoom.max]);
|
|
for (const yValue of yValues) {
|
|
const y = yScale.convert(yValue);
|
|
if (!Number.isFinite(y))
|
|
continue;
|
|
if (y < min) {
|
|
min = y;
|
|
minPadding = !connectsToYAxis || yValue < 0;
|
|
}
|
|
if (y > max) {
|
|
max = y;
|
|
maxPadding = !connectsToYAxis || yValue > 0;
|
|
}
|
|
}
|
|
}
|
|
if (isFiniteNumber2(yAxis.min)) {
|
|
min = 0;
|
|
}
|
|
if (isFiniteNumber2(yAxis.max)) {
|
|
max = 1;
|
|
}
|
|
xScale.range = xScaleRange;
|
|
yScale.range = yScaleRange;
|
|
if (min >= max)
|
|
return;
|
|
const totalPadding = (minPadding ? padding2 : 0) + (maxPadding ? padding2 : 0);
|
|
const paddedDelta = Math.min((max - min) * (1 + totalPadding), 1);
|
|
if (paddedDelta <= 0)
|
|
return;
|
|
if (minPadding && maxPadding) {
|
|
const mid = (max + min) / 2;
|
|
min = mid - paddedDelta / 2;
|
|
max = mid + paddedDelta / 2;
|
|
} else if (!minPadding && maxPadding) {
|
|
max = min + paddedDelta;
|
|
} else if (minPadding && !maxPadding) {
|
|
min = max - paddedDelta;
|
|
}
|
|
if (min < 0) {
|
|
max += -min;
|
|
min = 0;
|
|
} else if (max > 1) {
|
|
min -= max - 1;
|
|
max = 1;
|
|
}
|
|
return { min, max };
|
|
}
|
|
primaryAxisZoom(direction, zoom, { padding: padding2 = 0 } = {}) {
|
|
const crossDirection = direction === ChartAxisDirection32.X ? ChartAxisDirection32.Y : ChartAxisDirection32.X;
|
|
const xAxis = this.zoomManager.getPrimaryAxis(crossDirection);
|
|
const yAxis = this.zoomManager.getPrimaryAxis(direction);
|
|
if (xAxis == null || yAxis == null)
|
|
return;
|
|
return this.zoomBounds(xAxis, yAxis, zoom, padding2);
|
|
}
|
|
combinedAxisZoom(direction, zoom, { padding: padding2 = 0 } = {}) {
|
|
const axes = this.zoomManager.getAxes();
|
|
const crossDirection = direction === ChartAxisDirection32.X ? ChartAxisDirection32.Y : ChartAxisDirection32.X;
|
|
const seriesXAxes = /* @__PURE__ */ new Map();
|
|
for (const xAxis of axes) {
|
|
if (xAxis.direction !== crossDirection)
|
|
continue;
|
|
for (const series of xAxis.boundSeries) {
|
|
seriesXAxes.set(series, xAxis);
|
|
}
|
|
}
|
|
let min = 1;
|
|
let max = 0;
|
|
for (const yAxis of axes) {
|
|
if (yAxis.direction !== direction)
|
|
continue;
|
|
for (const series of yAxis.boundSeries) {
|
|
const xAxis = seriesXAxes.get(series);
|
|
if (xAxis == null)
|
|
continue;
|
|
const bounds = this.zoomBounds(xAxis, yAxis, zoom, padding2);
|
|
if (bounds == null)
|
|
return;
|
|
min = Math.min(min, bounds.min);
|
|
max = Math.max(max, bounds.max);
|
|
}
|
|
}
|
|
const delta3 = 1e-6;
|
|
if (min < delta3)
|
|
min = 0;
|
|
if (max > 1 - delta3)
|
|
max = 1;
|
|
if (min > max)
|
|
return;
|
|
return { min, max };
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/zoom/zoomAxisDragger.ts
|
|
import { ChartAxisDirection as ChartAxisDirection33, definedZoomState as definedZoomState3 } from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/features/zoom/zoomUtils.ts
|
|
import "ag-charts-community";
|
|
import { UNIT_MAX, UNIT_MIN, clamp as clamp10, definedZoomState as definedZoomState2, isNumberEqual as isNumberEqual8, jsonDiff as jsonDiff2 } from "ag-charts-core";
|
|
var UNIT_SIZE = UNIT_MAX - UNIT_MIN;
|
|
var DEFAULT_ANCHOR_POINT_X = "end";
|
|
var DEFAULT_ANCHOR_POINT_Y = "middle";
|
|
var ZOOM_VALID_CHECK_DEBOUNCE = 300;
|
|
var constrain = (value, min = UNIT_MIN, max = UNIT_MAX) => clamp10(min, value, max);
|
|
function dx(zoom) {
|
|
return zoom.x.max - zoom.x.min;
|
|
}
|
|
function dy(zoom) {
|
|
return zoom.y.max - zoom.y.min;
|
|
}
|
|
function isZoomRangeEqual(left, right) {
|
|
return isNumberEqual8(left.min, right.min) && isNumberEqual8(left.max, right.max);
|
|
}
|
|
function isZoomEqual(left, right) {
|
|
return isZoomRangeEqual(left.x, right.x) && isZoomRangeEqual(left.y, right.y);
|
|
}
|
|
function isMaxZoom(zoom) {
|
|
return isZoomEqual(zoom, definedZoomState2());
|
|
}
|
|
function pointToRatio(bbox, x, y) {
|
|
if (!bbox)
|
|
return { x: 0, y: 0 };
|
|
const constrainedX = constrain(x - bbox.x, 0, bbox.x + bbox.width);
|
|
const constrainedY = constrain(y - bbox.y, 0, bbox.y + bbox.height);
|
|
const rx = 1 / bbox.width * constrainedX;
|
|
const ry = 1 - 1 / bbox.height * constrainedY;
|
|
return { x: constrain(rx), y: constrain(ry) };
|
|
}
|
|
function translateZoom(zoom, x, y) {
|
|
return {
|
|
x: { min: zoom.x.min + x, max: zoom.x.max + x },
|
|
y: { min: zoom.y.min + y, max: zoom.y.max + y }
|
|
};
|
|
}
|
|
function scaleZoom(zoom, sx, sy) {
|
|
return {
|
|
x: { min: zoom.x.min, max: zoom.x.min + dx(zoom) * sx },
|
|
y: { min: zoom.y.min, max: zoom.y.min + dy(zoom) * sy }
|
|
};
|
|
}
|
|
function scaleZoomCenter(zoom, sx, sy) {
|
|
const dx_ = dx(zoom);
|
|
const dy_ = dy(zoom);
|
|
const cx = zoom.x.min + dx_ / 2;
|
|
const cy = zoom.y.min + dy_ / 2;
|
|
return {
|
|
x: { min: cx - dx_ * sx / 2, max: cx + dx_ * sx / 2 },
|
|
y: { min: cy - dy_ * sy / 2, max: cy + dy_ * sy / 2 }
|
|
};
|
|
}
|
|
function scaleZoomAxisWithAnchor(newState, oldState, anchor, origin) {
|
|
const { min, max } = oldState;
|
|
const center = min + (max - min) / 2;
|
|
const diff8 = newState.max - newState.min;
|
|
switch (anchor) {
|
|
case "start":
|
|
return { min, max: oldState.min + diff8 };
|
|
case "end":
|
|
return { min: oldState.max - diff8, max };
|
|
case "middle":
|
|
return { min: center - diff8 / 2, max: center + diff8 / 2 };
|
|
case "pointer":
|
|
return scaleZoomAxisWithPoint(newState, oldState, origin ?? center);
|
|
default:
|
|
return { min, max };
|
|
}
|
|
}
|
|
function scaleZoomAxisWithPoint(newState, oldState, origin) {
|
|
const newDelta = newState.max - newState.min;
|
|
const oldDelta = oldState.max - oldState.min;
|
|
const scaledOrigin = origin * (1 - (oldDelta - newDelta));
|
|
const translation = origin - scaledOrigin;
|
|
const min = newState.min + translation;
|
|
const max = newState.max + translation;
|
|
return { min, max };
|
|
}
|
|
function multiplyZoom(zoom, nx, ny) {
|
|
return {
|
|
x: { min: zoom.x.min * nx, max: zoom.x.max * nx },
|
|
y: { min: zoom.y.min * ny, max: zoom.y.max * ny }
|
|
};
|
|
}
|
|
function constrainZoom(zoom) {
|
|
return {
|
|
x: constrainAxis(zoom.x),
|
|
y: constrainAxis(zoom.y)
|
|
};
|
|
}
|
|
function constrainAxis(axis) {
|
|
const size = axis.max - axis.min;
|
|
let min = axis.max > UNIT_MAX ? UNIT_MAX - size : axis.min;
|
|
let max = axis.min < UNIT_MIN ? size : axis.max;
|
|
min = Math.max(UNIT_MIN, min);
|
|
max = Math.min(UNIT_MAX, max);
|
|
return { min, max };
|
|
}
|
|
function canResetZoom(zoomManager) {
|
|
const current = zoomManager.getCoreZoom();
|
|
const restore = zoomManager.getRestoredZoom();
|
|
return jsonDiff2(current, restore) != null;
|
|
}
|
|
|
|
// packages/ag-charts-enterprise/src/features/zoom/zoomAxisDragger.ts
|
|
var ZoomAxisDragger = class {
|
|
update(event, direction, anchor, bbox, zoom, axisZoom) {
|
|
this.oldZoom ?? (this.oldZoom = definedZoomState3(
|
|
direction === ChartAxisDirection33.X ? { ...zoom, x: axisZoom } : { ...zoom, y: axisZoom }
|
|
));
|
|
this.updateCoords(event.offsetX, event.offsetY);
|
|
return this.updateZoom(direction, anchor, bbox);
|
|
}
|
|
stop() {
|
|
this.coords = void 0;
|
|
this.oldZoom = void 0;
|
|
}
|
|
updateCoords(x, y) {
|
|
if (this.coords) {
|
|
this.coords.x2 = x;
|
|
this.coords.y2 = y;
|
|
} else {
|
|
this.coords = { x1: x, y1: y, x2: x, y2: y };
|
|
}
|
|
}
|
|
updateZoom(direction, anchor, bbox) {
|
|
const { coords, oldZoom } = this;
|
|
let newZoom = definedZoomState3(oldZoom);
|
|
if (!coords || !oldZoom) {
|
|
if (direction === ChartAxisDirection33.X)
|
|
return newZoom.x;
|
|
return newZoom.y;
|
|
}
|
|
const origin = pointToRatio(bbox, coords.x1, coords.y1);
|
|
const target = pointToRatio(bbox, coords.x2, coords.y2);
|
|
if (direction === ChartAxisDirection33.X) {
|
|
const scaleX = (target.x - origin.x) * dx(oldZoom);
|
|
newZoom.x.max += scaleX;
|
|
newZoom.x = scaleZoomAxisWithAnchor(newZoom.x, oldZoom.x, anchor, origin.x);
|
|
newZoom = constrainZoom(newZoom);
|
|
return newZoom.x;
|
|
}
|
|
const scaleY = (target.y - origin.y) * dy(oldZoom);
|
|
newZoom.y.max -= scaleY;
|
|
newZoom.y = scaleZoomAxisWithAnchor(newZoom.y, oldZoom.y, anchor, origin.y);
|
|
newZoom = constrainZoom(newZoom);
|
|
return newZoom.y;
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/zoom/zoomContextMenu.ts
|
|
import { _ModuleSupport as _ModuleSupport126 } from "ag-charts-community";
|
|
import { definedZoomState as definedZoomState4 } from "ag-charts-core";
|
|
var { userInteraction: userInteraction2 } = _ModuleSupport126;
|
|
var ZoomContextMenu = class {
|
|
constructor(eventsHub, contextMenuRegistry, zoomManager, getModuleProperties, getRect, updateZoom, isZoomValid) {
|
|
this.eventsHub = eventsHub;
|
|
this.contextMenuRegistry = contextMenuRegistry;
|
|
this.zoomManager = zoomManager;
|
|
this.getModuleProperties = getModuleProperties;
|
|
this.getRect = getRect;
|
|
this.updateZoom = updateZoom;
|
|
this.isZoomValid = isZoomValid;
|
|
}
|
|
registerActions(enabled) {
|
|
const { contextMenuRegistry } = this;
|
|
const action = enabled ? "show" : "hide";
|
|
contextMenuRegistry.toggle("zoom-to-cursor", action);
|
|
contextMenuRegistry.toggle("pan-to-cursor", action);
|
|
contextMenuRegistry.toggle("reset-zoom", action);
|
|
if (!enabled) {
|
|
return;
|
|
}
|
|
contextMenuRegistry.builtins.items["zoom-to-cursor"].action = this.onZoomToHere.bind(this);
|
|
contextMenuRegistry.builtins.items["pan-to-cursor"].action = this.onPanToHere.bind(this);
|
|
contextMenuRegistry.builtins.items["reset-zoom"].action = this.onResetZoom.bind(this);
|
|
const shouldEnableZoomToHere = (event) => {
|
|
const rect = this.getRect();
|
|
if (!rect)
|
|
return true;
|
|
const origin = pointToRatio(rect, event.x, event.y);
|
|
return this.iterateFindNextZoomAtPoint(origin) != null;
|
|
};
|
|
const shouldEnablePanToHere = () => {
|
|
return !isMaxZoom(definedZoomState4(this.zoomManager.getZoom()));
|
|
};
|
|
const removeListener = this.eventsHub.on("context-menu:setup", (event) => {
|
|
contextMenuRegistry.builtins.items["zoom-to-cursor"].enabled = shouldEnableZoomToHere(event);
|
|
contextMenuRegistry.builtins.items["pan-to-cursor"].enabled = shouldEnablePanToHere();
|
|
contextMenuRegistry.builtins.items["reset-zoom"].enabled = canResetZoom(this.zoomManager);
|
|
});
|
|
return () => {
|
|
removeListener();
|
|
contextMenuRegistry.toggle("zoom-to-cursor", "hide");
|
|
contextMenuRegistry.toggle("pan-to-cursor", "hide");
|
|
contextMenuRegistry.toggle("reset-zoom", "hide");
|
|
};
|
|
}
|
|
computeOrigin(event) {
|
|
const rect = this.getRect();
|
|
const { enabled } = this.getModuleProperties();
|
|
if (!enabled || !rect || !event?.target || !(event instanceof MouseEvent))
|
|
return;
|
|
const relativeRect = { x: 0, y: 0, width: rect.width, height: rect.height };
|
|
return pointToRatio(relativeRect, event.offsetX, event.offsetY);
|
|
}
|
|
onZoomToHere({ event }) {
|
|
const origin = this.computeOrigin(event);
|
|
if (!origin)
|
|
return;
|
|
const zoom = this.iterateFindNextZoomAtPoint(origin);
|
|
if (zoom == null)
|
|
return;
|
|
this.updateZoom(userInteraction2("contextmenu-zoom-to-cursor"), zoom);
|
|
}
|
|
onPanToHere({ event }) {
|
|
const origin = this.computeOrigin(event);
|
|
if (!origin)
|
|
return;
|
|
const zoom = definedZoomState4(this.zoomManager.getZoom());
|
|
const scaleX = dx(zoom);
|
|
const scaleY = dy(zoom);
|
|
const scaledOriginX = origin.x * scaleX;
|
|
const scaledOriginY = origin.y * scaleY;
|
|
const halfSize = UNIT_SIZE / 2;
|
|
let newZoom = {
|
|
x: { min: origin.x - halfSize, max: origin.x + halfSize },
|
|
y: { min: origin.y - halfSize, max: origin.y + halfSize }
|
|
};
|
|
newZoom = scaleZoomCenter(newZoom, scaleX, scaleY);
|
|
newZoom = translateZoom(newZoom, zoom.x.min - origin.x + scaledOriginX, zoom.y.min - origin.y + scaledOriginY);
|
|
this.updateZoom(userInteraction2("contextmenu-pan-to-cursor"), constrainZoom(newZoom));
|
|
}
|
|
onResetZoom(_actionEvent) {
|
|
this.zoomManager.resetZoom(userInteraction2("contextmenu-reset"));
|
|
}
|
|
iterateFindNextZoomAtPoint(origin) {
|
|
const { scrollingStep } = this.getModuleProperties();
|
|
for (let i = scrollingStep; i <= 1 - scrollingStep; i += scrollingStep) {
|
|
const zoom = this.getNextZoomAtPoint(origin, i);
|
|
if (this.isZoomValid(zoom)) {
|
|
return zoom;
|
|
}
|
|
}
|
|
}
|
|
getNextZoomAtPoint(origin, step) {
|
|
const { isScalingX, isScalingY } = this.getModuleProperties();
|
|
const zoom = definedZoomState4(this.zoomManager.getZoom());
|
|
const scaledOriginX = origin.x * dx(zoom);
|
|
const scaledOriginY = origin.y * dy(zoom);
|
|
const halfSize = UNIT_SIZE / 2;
|
|
let newZoom = {
|
|
x: { min: origin.x - halfSize, max: origin.x + halfSize },
|
|
y: { min: origin.y - halfSize, max: origin.y + halfSize }
|
|
};
|
|
newZoom = scaleZoomCenter(
|
|
newZoom,
|
|
isScalingX ? dx(zoom) * step : UNIT_SIZE,
|
|
isScalingY ? dy(zoom) * step : UNIT_SIZE
|
|
);
|
|
newZoom = translateZoom(newZoom, zoom.x.min - origin.x + scaledOriginX, zoom.y.min - origin.y + scaledOriginY);
|
|
return constrainZoom(newZoom);
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/zoom/zoomDOMProxy.ts
|
|
import { _ModuleSupport as _ModuleSupport127 } from "ag-charts-community";
|
|
import { ChartAxisDirection as ChartAxisDirection34, boxEmpty } from "ag-charts-core";
|
|
var ZoomDOMProxy = class {
|
|
constructor(axesHandlers) {
|
|
this.axesHandlers = axesHandlers;
|
|
this.axes = [];
|
|
this.overlappingAxisIds = /* @__PURE__ */ new Set();
|
|
}
|
|
destroy() {
|
|
for (const a of this.axes) {
|
|
a.div.destroy();
|
|
}
|
|
}
|
|
update(enabled, enableAxisDragging, enableAxisScrolling, ctx, seriesRect) {
|
|
this.seriesRect = seriesRect;
|
|
const disabled = !enabled || !enableAxisDragging && !enableAxisScrolling;
|
|
for (const ax of this.axes) {
|
|
ax.div.setHidden(disabled);
|
|
}
|
|
if (disabled)
|
|
return;
|
|
const { X, Y } = ChartAxisDirection34;
|
|
const axesCtx = [...ctx.axisManager.getAxisContext(X), ...ctx.axisManager.getAxisContext(Y)];
|
|
const { removed, added } = this.diffAxisIds(axesCtx);
|
|
if (removed.length > 0) {
|
|
this.axes = this.axes.filter((entry) => {
|
|
if (removed.includes(entry.axisId)) {
|
|
entry.div.destroy();
|
|
this.overlappingAxisIds.delete(entry.axisId);
|
|
if (this.hoveredAxisId === entry.axisId)
|
|
this.hoveredAxisId = void 0;
|
|
if (this.activeAxisId === entry.axisId)
|
|
this.activeAxisId = void 0;
|
|
return false;
|
|
}
|
|
return true;
|
|
});
|
|
}
|
|
for (const newAxisCtx of added) {
|
|
const { axisId, direction } = newAxisCtx;
|
|
this.axes.push(this.initAxis(ctx, axisId, this.axesHandlers, direction));
|
|
}
|
|
for (const axis of this.axes) {
|
|
const axisCtx = axesCtx.find((ac) => ac.axisId === axis.axisId);
|
|
const bbox = axisCtx.getCanvasBounds();
|
|
axis.div.setHidden(boxEmpty(bbox));
|
|
if (bbox == void 0) {
|
|
axis.bounds = void 0;
|
|
} else {
|
|
axis.div.setBounds(bbox);
|
|
axis.bounds = new _ModuleSupport127.BBox(bbox.x, bbox.y, bbox.width, bbox.height);
|
|
}
|
|
}
|
|
this.updateOverlappingAxisPointerEvents(enableAxisDragging, enableAxisScrolling);
|
|
}
|
|
setAxisCursor(cursor) {
|
|
this.cursor = cursor;
|
|
for (const axis of this.axes) {
|
|
axis.div.setCursor(this.getCursor(axis.direction));
|
|
}
|
|
}
|
|
toggleAxisDraggingCursor(direction, enabled) {
|
|
for (const axis of this.axes) {
|
|
if (axis.direction !== direction)
|
|
continue;
|
|
axis.div.setCursor(enabled ? this.getCursor(direction) : void 0);
|
|
}
|
|
}
|
|
updateOverlappingAxisPointerEvents(enableAxisDragging, enableAxisScrolling) {
|
|
this.overlappingAxisIds.clear();
|
|
const shouldEnableInteraction = (enableAxisDragging || enableAxisScrolling) && this.seriesRect;
|
|
for (const axis of this.axes) {
|
|
if (!shouldEnableInteraction) {
|
|
axis.div.setPointerEvents(void 0);
|
|
continue;
|
|
}
|
|
const isOverlapping = Boolean(axis.bounds?.collidesBBox(this.seriesRect));
|
|
if (isOverlapping) {
|
|
this.overlappingAxisIds.add(axis.axisId);
|
|
axis.div.setPointerEvents("none");
|
|
} else {
|
|
axis.div.setPointerEvents(void 0);
|
|
}
|
|
}
|
|
this.cleanupAxisState();
|
|
}
|
|
cleanupAxisState() {
|
|
if (this.hoveredAxisId && !this.overlappingAxisIds.has(this.hoveredAxisId)) {
|
|
this.hoveredAxisId = void 0;
|
|
}
|
|
if (this.activeAxisId && !this.overlappingAxisIds.has(this.activeAxisId)) {
|
|
this.activeAxisId = void 0;
|
|
}
|
|
}
|
|
pickAxisAtPoint(point) {
|
|
for (const axis of this.axes) {
|
|
if (!this.overlappingAxisIds.has(axis.axisId))
|
|
continue;
|
|
if (axis.bounds?.containsPoint(point.canvasX, point.canvasY)) {
|
|
return { axisId: axis.axisId, direction: axis.direction };
|
|
}
|
|
}
|
|
return void 0;
|
|
}
|
|
setHoveredAxis(axisId) {
|
|
if (this.overlappingAxisIds.has(axisId)) {
|
|
this.hoveredAxisId = axisId;
|
|
}
|
|
}
|
|
clearHoveredAxis() {
|
|
if (!this.activeAxisId) {
|
|
this.hoveredAxisId = void 0;
|
|
}
|
|
}
|
|
beginDelegatedAxisDrag(axisId) {
|
|
if (!this.overlappingAxisIds.has(axisId))
|
|
return false;
|
|
this.activeAxisId = axisId;
|
|
this.hoveredAxisId = void 0;
|
|
return true;
|
|
}
|
|
endDelegatedAxisDrag(axisId) {
|
|
if (this.activeAxisId === axisId) {
|
|
this.activeAxisId = void 0;
|
|
}
|
|
this.hoveredAxisId = void 0;
|
|
}
|
|
hasOverlappingAxes() {
|
|
return this.overlappingAxisIds.size > 0;
|
|
}
|
|
getHoveredAxis() {
|
|
if (!this.hoveredAxisId)
|
|
return void 0;
|
|
const axis = this.axes.find((a) => a.axisId === this.hoveredAxisId);
|
|
return axis ? { axisId: axis.axisId, direction: axis.direction } : void 0;
|
|
}
|
|
getCursor(direction) {
|
|
if (this.cursor)
|
|
return this.cursor;
|
|
return direction === ChartAxisDirection34.X ? "ew-resize" : "ns-resize";
|
|
}
|
|
initAxis(ctx, axisId, handlers, direction) {
|
|
const where = "afterend";
|
|
const div = ctx.proxyInteractionService.createProxyElement({ type: "region", domManagerId: axisId, where });
|
|
div.setCursor(this.getCursor(direction));
|
|
div.addListener("drag-start", (e) => {
|
|
if (e.device === "touch") {
|
|
e.sourceEvent.preventDefault();
|
|
}
|
|
this.activeAxisId = axisId;
|
|
handlers.onAxisDragStart(direction);
|
|
});
|
|
div.addListener("drag-move", (event) => handlers.onAxisDragMove(axisId, direction, event));
|
|
div.addListener("drag-end", () => {
|
|
this.activeAxisId = void 0;
|
|
this.hoveredAxisId = void 0;
|
|
handlers.onAxisDragEnd();
|
|
});
|
|
div.addListener("dblclick", () => handlers.onAxisDoubleClick(axisId, direction));
|
|
div.addListener("wheel", (event) => handlers.onAxisWheel(direction, event));
|
|
return { axisId, div, direction };
|
|
}
|
|
diffAxisIds(axesCtx) {
|
|
const myIds = this.axes.map((entry) => entry.axisId);
|
|
const ctxIds = axesCtx.map((ctx) => ctx.axisId);
|
|
const removed = myIds.filter((id) => !ctxIds.includes(id));
|
|
const added = axesCtx.filter((ac) => !myIds.includes(ac.axisId));
|
|
return { removed, added };
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/zoom/zoomOnDataChange.ts
|
|
import { _ModuleSupport as _ModuleSupport128 } from "ag-charts-community";
|
|
import { BaseProperties as BaseProperties27, ChartAxisDirection as ChartAxisDirection35, Logger as Logger13, Property as Property65, clamp as clamp11, definedZoomState as definedZoomState5 } from "ag-charts-core";
|
|
var { userInteraction: userInteraction3 } = _ModuleSupport128;
|
|
function shouldIgnoreDataUpdate(zoom) {
|
|
return zoom.x.min === 0 && zoom.x.max === 1 && zoom.y.min === 0 && zoom.y.max === 1;
|
|
}
|
|
function shouldStickToEnd(properties, zoom) {
|
|
return properties.stickToEnd && zoom.x.max === 1;
|
|
}
|
|
function toVisibleMinMax(axisId, domainMinMax, ratios) {
|
|
const { domainMin, domainMax } = domainMinMax;
|
|
const span = domainMax - domainMin;
|
|
return {
|
|
axisId,
|
|
visibleMin: domainMin + span * ratios.min,
|
|
visibleMax: domainMin + span * ratios.max
|
|
};
|
|
}
|
|
function fromVisibleMinMax(domainMinMax, visibleMinMax) {
|
|
const { domainMin, domainMax } = domainMinMax;
|
|
const { visibleMin, visibleMax } = visibleMinMax;
|
|
const span = domainMax - domainMin;
|
|
return {
|
|
direction: "x",
|
|
min: clamp11(0, (visibleMin - domainMin) / span, 1),
|
|
max: clamp11(0, (visibleMax - domainMin) / span, 1)
|
|
};
|
|
}
|
|
var ZoomOnDataChangeProperties = class extends BaseProperties27 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.strategy = "preserveDomain";
|
|
// TODO(olegat): change default to 'true'
|
|
this.stickToEnd = false;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property65
|
|
], ZoomOnDataChangeProperties.prototype, "strategy", 2);
|
|
__decorateClass([
|
|
Property65
|
|
], ZoomOnDataChangeProperties.prototype, "stickToEnd", 2);
|
|
var ZoomOnDataChange = class {
|
|
constructor(onConstrainChangesCallback, properties, ctx, eventsCleanup) {
|
|
this.onConstrainChangesCallback = onConstrainChangesCallback;
|
|
this.properties = properties;
|
|
this.ctx = ctx;
|
|
const onFirstDraw = () => {
|
|
ctx.eventsHub.off("layout:complete", onFirstDraw);
|
|
eventsCleanup.register(
|
|
ctx.eventsHub.on("data:load", (e) => this.onDataLoad(e)),
|
|
ctx.eventsHub.on("data:update", (e) => this.onDataUpdate(e))
|
|
);
|
|
};
|
|
eventsCleanup.register(
|
|
ctx.eventsHub.on("layout:complete", onFirstDraw),
|
|
ctx.eventsHub.on("zoom:change-request", (e) => this.onZoomChangeRequest(e))
|
|
);
|
|
}
|
|
destroy() {
|
|
}
|
|
onDataLoad(_e) {
|
|
this.performUpdateStrategy();
|
|
}
|
|
onDataUpdate(_e) {
|
|
this.performUpdateStrategy();
|
|
}
|
|
onZoomChangeRequest(e) {
|
|
if (e.sourceDetail === "internal-requiredWidth") {
|
|
this.desiredChanges = void 0;
|
|
}
|
|
const changes = this.popDesiredChanges();
|
|
if (changes) {
|
|
e.constrainChanges(changes);
|
|
this.onConstrainChangesCallback(e);
|
|
}
|
|
}
|
|
/**
|
|
* Convert ambiguous axes-scale (number | Date | string) into a strictly numerical scale, so that we can use
|
|
* interpolation to implement preserveDomain in an axes-scale agnostic way.
|
|
*/
|
|
computeDomainMinMax(axisId) {
|
|
const ctx = this.ctx.axisManager.getAxisIdContext(axisId);
|
|
if (!ctx?.continuous || ctx.scale.domain.length === 0)
|
|
return;
|
|
const [min, max] = ctx.scale.getDomainMinMax();
|
|
if (typeof min === "number" && typeof max === "number") {
|
|
return { domainMin: min, domainMax: max };
|
|
} else if (min instanceof Date && max instanceof Date) {
|
|
return { domainMin: min.getTime(), domainMax: max.getTime() };
|
|
} else {
|
|
Logger13.error(`Unexpected range types: start (${typeof min}), end (${typeof max})`);
|
|
}
|
|
}
|
|
popDesiredChanges() {
|
|
const { desiredChanges } = this;
|
|
if (!desiredChanges)
|
|
return;
|
|
this.desiredChanges = void 0;
|
|
switch (desiredChanges.type) {
|
|
case "domain": {
|
|
const changes = {};
|
|
for (const entry of desiredChanges.domains) {
|
|
const domainMinMax = this.computeDomainMinMax(entry.axisId);
|
|
if (domainMinMax) {
|
|
changes[entry.axisId] = fromVisibleMinMax(domainMinMax, entry);
|
|
}
|
|
}
|
|
return changes;
|
|
}
|
|
case "stickToEnd": {
|
|
const { axisId, difference } = desiredChanges;
|
|
const domainMinMax = this.computeDomainMinMax(axisId);
|
|
if (domainMinMax) {
|
|
const visibleMinMax = {
|
|
axisId,
|
|
visibleMin: domainMinMax.domainMax - difference,
|
|
visibleMax: domainMinMax.domainMax
|
|
};
|
|
return { [axisId]: fromVisibleMinMax(domainMinMax, visibleMinMax) };
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
const unreachable = (a) => a;
|
|
return unreachable(desiredChanges);
|
|
}
|
|
}
|
|
performUpdateStrategy() {
|
|
const zoom = definedZoomState5(this.ctx.zoomManager.getZoom());
|
|
if (shouldIgnoreDataUpdate(zoom)) {
|
|
return;
|
|
} else if (shouldStickToEnd(this.properties, zoom)) {
|
|
return this.performStickToEnd();
|
|
}
|
|
switch (this.properties.strategy) {
|
|
case "reset":
|
|
return this.ctx.zoomManager.resetZoom(userInteraction3("onDataChange-reset"));
|
|
case "preserveRatios":
|
|
return;
|
|
case "preserveDomain":
|
|
return this.performPreserveDomain();
|
|
default:
|
|
const unreachable = (a) => a;
|
|
return unreachable(this.properties.strategy);
|
|
}
|
|
}
|
|
performPreserveDomain() {
|
|
this.desiredChanges = { type: "domain", domains: [] };
|
|
const xaxes = this.ctx.zoomManager.getAxes().filter((a) => a.direction === ChartAxisDirection35.X);
|
|
for (const { id: axisId } of xaxes) {
|
|
const domainMinMax = this.computeDomainMinMax(axisId);
|
|
if (domainMinMax) {
|
|
const ratios = this.ctx.zoomManager.getAxisZoom(axisId);
|
|
const entry = toVisibleMinMax(axisId, domainMinMax, ratios);
|
|
this.desiredChanges.domains.push(entry);
|
|
}
|
|
}
|
|
}
|
|
performStickToEnd() {
|
|
const axisId = this.ctx.zoomManager.getPrimaryAxisId(ChartAxisDirection35.X);
|
|
if (!axisId)
|
|
return;
|
|
const domainMinMax = this.computeDomainMinMax(axisId);
|
|
if (!domainMinMax)
|
|
return;
|
|
const ratios = this.ctx.zoomManager.getAxisZoom(axisId);
|
|
if (!ratios)
|
|
return;
|
|
const { visibleMin, visibleMax } = toVisibleMinMax(axisId, domainMinMax, ratios);
|
|
const difference = visibleMax - visibleMin;
|
|
this.desiredChanges = { type: "stickToEnd", axisId, difference };
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/zoom/zoomPanner.ts
|
|
import "ag-charts-community";
|
|
import {
|
|
ChartAxisDirection as ChartAxisDirection36,
|
|
UNIT_MAX as UNIT_MAX2,
|
|
UNIT_MIN as UNIT_MIN2,
|
|
definedZoomState as definedZoomState6,
|
|
entries as entries6,
|
|
getWindow as getWindow3
|
|
} from "ag-charts-core";
|
|
var maxZoomCoords = 16;
|
|
var decelerationValues = {
|
|
off: 1,
|
|
short: 0.01,
|
|
long: 2e-3
|
|
};
|
|
var ZoomPanner = class {
|
|
constructor() {
|
|
this.deceleration = 1;
|
|
this.zoomCoordsHistoryIndex = 0;
|
|
this.coordsHistory = [];
|
|
}
|
|
get decelerationValue() {
|
|
const { deceleration } = this;
|
|
return Math.max(
|
|
typeof deceleration === "number" ? deceleration : decelerationValues[deceleration] ?? 1,
|
|
1e-4
|
|
);
|
|
}
|
|
addListener(_type, fn) {
|
|
this.onUpdate = fn;
|
|
return () => {
|
|
this.onUpdate = void 0;
|
|
};
|
|
}
|
|
stopInteractions() {
|
|
if (this.inertiaHandle != null) {
|
|
cancelAnimationFrame(this.inertiaHandle);
|
|
this.inertiaHandle = void 0;
|
|
}
|
|
}
|
|
update(event) {
|
|
this.updateCoords(event.currentX, event.currentY);
|
|
const { x1 = 0, y1 = 0, x2 = 0, y2 = 0 } = this.coords ?? {};
|
|
this.onUpdate?.({
|
|
type: "update",
|
|
deltaX: this.isPanningX() ? x1 - x2 : 0,
|
|
deltaY: this.isPanningY() ? y1 - y2 : 0
|
|
});
|
|
}
|
|
start(direction) {
|
|
this.direction = direction;
|
|
this.coordsMonitorTimeout = setInterval(this.recordCurrentZoomCoords.bind(this), 16);
|
|
}
|
|
stop() {
|
|
const { coordsHistory } = this;
|
|
let deltaX = 0;
|
|
let deltaY = 0;
|
|
let deltaT = 0;
|
|
if (coordsHistory.length > 0) {
|
|
const arrayIndex = this.zoomCoordsHistoryIndex % maxZoomCoords;
|
|
let index1 = arrayIndex - 1;
|
|
if (index1 < 0)
|
|
index1 = coordsHistory.length - 1;
|
|
let index0 = arrayIndex;
|
|
if (index0 >= coordsHistory.length)
|
|
index0 = 0;
|
|
const coords1 = coordsHistory[index1];
|
|
const coords0 = coordsHistory[index0];
|
|
deltaX = this.isPanningX() ? coords1.x - coords0.x : 0;
|
|
deltaY = this.isPanningY() ? coords1.y - coords0.y : 0;
|
|
deltaT = coords1.t - coords0.t;
|
|
}
|
|
this.coords = void 0;
|
|
this.direction = void 0;
|
|
clearInterval(this.coordsMonitorTimeout);
|
|
this.coordsMonitorTimeout = void 0;
|
|
this.zoomCoordsHistoryIndex = 0;
|
|
this.coordsHistory.length = 0;
|
|
if (deltaT > 0 && this.decelerationValue < 1) {
|
|
const xVelocity = deltaX / deltaT;
|
|
const yVelocity = deltaY / deltaT;
|
|
const velocity = Math.hypot(xVelocity, yVelocity);
|
|
const angle = Math.atan2(yVelocity, xVelocity);
|
|
const t0 = performance.now();
|
|
this.inertiaHandle = getWindow3().requestAnimationFrame((t) => {
|
|
this.animateInertia(t, t, t0, velocity, angle);
|
|
});
|
|
}
|
|
}
|
|
recordCurrentZoomCoords() {
|
|
const { coords, coordsHistory, zoomCoordsHistoryIndex } = this;
|
|
if (!coords)
|
|
return;
|
|
const { x2: x, y2: y } = coords;
|
|
const t = Date.now();
|
|
coordsHistory[zoomCoordsHistoryIndex % maxZoomCoords] = { x, y, t };
|
|
this.zoomCoordsHistoryIndex += 1;
|
|
}
|
|
animateInertia(t, prevT, t0, velocity, angle) {
|
|
const friction = 1 - this.decelerationValue;
|
|
const maxS = -velocity / Math.log(friction);
|
|
const s0 = velocity * (friction ** (prevT - t0) - 1) / Math.log(friction);
|
|
const s1 = velocity * (friction ** (t - t0) - 1) / Math.log(friction);
|
|
this.onUpdate?.({
|
|
type: "update",
|
|
deltaX: this.isPanningX() ? -Math.cos(angle) * (s1 - s0) : 0,
|
|
deltaY: this.isPanningY() ? -Math.sin(angle) * (s1 - s0) : 0
|
|
});
|
|
if (s1 >= maxS - 1)
|
|
return;
|
|
this.inertiaHandle = requestAnimationFrame((nextT) => {
|
|
this.animateInertia(nextT, t, t0, velocity, angle);
|
|
});
|
|
}
|
|
updateCoords(x, y) {
|
|
if (this.coords) {
|
|
this.coords = { x1: this.coords.x2, y1: this.coords.y2, x2: x, y2: y };
|
|
} else {
|
|
this.coords = { x1: x, y1: y, x2: x, y2: y };
|
|
}
|
|
}
|
|
isPanningX() {
|
|
return this.direction == null || this.direction === ChartAxisDirection36.X;
|
|
}
|
|
isPanningY() {
|
|
return this.direction == null || this.direction === ChartAxisDirection36.Y;
|
|
}
|
|
translateZooms(bbox, currentZooms, deltaX, deltaY) {
|
|
const offset = pointToRatio(bbox, bbox.x + Math.abs(deltaX), bbox.y + bbox.height - Math.abs(deltaY));
|
|
const offsetX = Math.sign(deltaX) * offset.x;
|
|
const offsetY = -Math.sign(deltaY) * offset.y;
|
|
const newZooms = {};
|
|
for (const [axisId, currentZoom] of entries6(currentZooms)) {
|
|
if (currentZoom == null)
|
|
continue;
|
|
if (currentZoom.min === UNIT_MIN2 && currentZoom.max === UNIT_MAX2) {
|
|
continue;
|
|
}
|
|
const { direction } = currentZoom;
|
|
let zoom = definedZoomState6({ [direction]: currentZoom });
|
|
zoom = constrainZoom(translateZoom(zoom, offsetX * dx(zoom), offsetY * dy(zoom)));
|
|
const { min, max } = zoom[direction];
|
|
newZooms[axisId] = { direction, min, max };
|
|
}
|
|
return newZooms;
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/zoom/zoomScrollPanner.ts
|
|
import "ag-charts-community";
|
|
import { ChartAxisDirection as ChartAxisDirection37, definedZoomState as definedZoomState7, entries as entries7 } from "ag-charts-core";
|
|
var DELTA_SCALE = 200;
|
|
var ZoomScrollPanner = class {
|
|
update(event, step, bbox, zooms) {
|
|
const deltaX = event.deltaX * step * DELTA_SCALE;
|
|
return this.translateZooms(bbox, zooms, deltaX);
|
|
}
|
|
translateZooms(bbox, currentZooms, deltaX) {
|
|
const newZooms = {};
|
|
const offset = pointToRatio(bbox, bbox.x + Math.abs(deltaX), 0);
|
|
const offsetX = deltaX < 0 ? -offset.x : offset.x;
|
|
for (const [axisId, value] of entries7(currentZooms)) {
|
|
if (value?.direction !== ChartAxisDirection37.X)
|
|
continue;
|
|
const { direction, min, max } = value;
|
|
let zoom = definedZoomState7({ x: { min, max } });
|
|
zoom = constrainZoom(translateZoom(zoom, offsetX * dx(zoom), 0));
|
|
newZooms[axisId] = { direction, min: zoom.x.min, max: zoom.x.max };
|
|
}
|
|
return newZooms;
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/zoom/zoomScroller.ts
|
|
import "ag-charts-community";
|
|
import { ChartAxisDirection as ChartAxisDirection38, definedZoomState as definedZoomState8, entries as entries8 } from "ag-charts-core";
|
|
var ZoomScroller = class {
|
|
updateAxes(event, props, bbox, zooms) {
|
|
const sourceEvent = event.sourceEvent;
|
|
const newZooms = {};
|
|
const { anchorPointX, anchorPointY, isScalingX, isScalingY, scrollingStep } = props;
|
|
const origin = pointToRatio(
|
|
bbox,
|
|
sourceEvent.offsetX ?? sourceEvent.clientX,
|
|
sourceEvent.offsetY ?? sourceEvent.clientY
|
|
);
|
|
for (const [axisId, value] of entries8(zooms)) {
|
|
if (value == null)
|
|
continue;
|
|
const { direction, min, max } = value;
|
|
let newZoom = { min, max };
|
|
const delta3 = scrollingStep * event.deltaY * (max - min);
|
|
if (direction === ChartAxisDirection38.X && isScalingX) {
|
|
newZoom.max += delta3;
|
|
newZoom = scaleZoomAxisWithAnchor(newZoom, value, anchorPointX, origin.x);
|
|
} else if (direction === ChartAxisDirection38.Y && isScalingY) {
|
|
newZoom.max += delta3;
|
|
newZoom = scaleZoomAxisWithAnchor(newZoom, value, anchorPointY, origin.y);
|
|
} else {
|
|
continue;
|
|
}
|
|
if (newZoom.max < newZoom.min)
|
|
continue;
|
|
const constrained = constrainAxis(newZoom);
|
|
newZooms[axisId] = { direction, min: constrained.min, max: constrained.max };
|
|
}
|
|
return newZooms;
|
|
}
|
|
update(event, props, bbox, oldZoom) {
|
|
const { anchorPointX, anchorPointY, isScalingX, isScalingY, scrollingStep } = props;
|
|
const canvasX = event.offsetX + bbox.x;
|
|
const canvasY = event.offsetY + bbox.y;
|
|
const origin = pointToRatio(bbox, canvasX, canvasY);
|
|
const dir = event.deltaY;
|
|
let newZoom = definedZoomState8(oldZoom);
|
|
newZoom.x.max += isScalingX ? scrollingStep * dir * dx(oldZoom) : 0;
|
|
newZoom.y.max += isScalingY ? scrollingStep * dir * dy(oldZoom) : 0;
|
|
if (newZoom.x.max < newZoom.x.min || newZoom.y.max < newZoom.y.min)
|
|
return;
|
|
if (isScalingX) {
|
|
newZoom.x = scaleZoomAxisWithAnchor(newZoom.x, oldZoom.x, anchorPointX, origin.x);
|
|
}
|
|
if (isScalingY) {
|
|
newZoom.y = scaleZoomAxisWithAnchor(newZoom.y, oldZoom.y, anchorPointY, origin.y);
|
|
}
|
|
newZoom = constrainZoom(newZoom);
|
|
return newZoom;
|
|
}
|
|
updateDelta(delta3, props, oldZoom) {
|
|
const { anchorPointX, anchorPointY, isScalingX, isScalingY, scrollingStep } = props;
|
|
let newZoom = definedZoomState8(oldZoom);
|
|
newZoom.x.max += isScalingX ? scrollingStep * -delta3 * dx(oldZoom) : 0;
|
|
newZoom.y.max += isScalingY ? scrollingStep * -delta3 * dy(oldZoom) : 0;
|
|
if (isScalingX) {
|
|
newZoom.x = scaleZoomAxisWithAnchor(newZoom.x, oldZoom.x, anchorPointX);
|
|
}
|
|
if (isScalingY) {
|
|
newZoom.y = scaleZoomAxisWithAnchor(newZoom.y, oldZoom.y, anchorPointY);
|
|
}
|
|
newZoom = constrainZoom(newZoom);
|
|
return newZoom;
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/zoom/zoomSelector.ts
|
|
import { definedZoomState as definedZoomState9 } from "ag-charts-core";
|
|
var ZoomSelector = class {
|
|
constructor(rect, getZoom, isZoomValid) {
|
|
this.rect = rect;
|
|
this.getZoom = getZoom;
|
|
this.isZoomValid = isZoomValid;
|
|
this.rect.visible = false;
|
|
}
|
|
update(event, props, bbox) {
|
|
const canvasX = event.currentX + (bbox?.x ?? 0);
|
|
const canvasY = event.currentY + (bbox?.y ?? 0);
|
|
this.rect.visible = true;
|
|
this.updateCoords(canvasX, canvasY, props, bbox);
|
|
this.updateRect(bbox);
|
|
}
|
|
stop(innerBBox, bbox, currentZoom) {
|
|
let zoom = definedZoomState9();
|
|
if (!innerBBox || !bbox)
|
|
return zoom;
|
|
if (this.coords) {
|
|
zoom = this.createZoomFromCoords(bbox, currentZoom);
|
|
}
|
|
const multiplyX = bbox.width / innerBBox.width;
|
|
const multiplyY = bbox.height / innerBBox.height;
|
|
zoom = constrainZoom(multiplyZoom(zoom, multiplyX, multiplyY));
|
|
this.reset();
|
|
if (this.isZoomValid(zoom)) {
|
|
return zoom;
|
|
}
|
|
}
|
|
reset() {
|
|
this.coords = void 0;
|
|
this.rect.visible = false;
|
|
}
|
|
didUpdate() {
|
|
return this.rect.visible && this.rect.width > 0 && this.rect.height > 0;
|
|
}
|
|
updateCoords(x, y, props, bbox) {
|
|
if (!this.coords) {
|
|
this.coords = { x1: x, y1: y, x2: x, y2: y };
|
|
return;
|
|
}
|
|
const { coords } = this;
|
|
coords.x2 = x;
|
|
coords.y2 = y;
|
|
if (!bbox)
|
|
return;
|
|
const { isScalingX, isScalingY, keepAspectRatio } = props;
|
|
const normal = this.getNormalisedDimensions();
|
|
if (keepAspectRatio && isScalingX && isScalingY) {
|
|
const aspectRatio = bbox.width / bbox.height;
|
|
if (coords.y2 < coords.y1) {
|
|
coords.y2 = Math.min(coords.y1 - normal.width / aspectRatio, coords.y1);
|
|
} else {
|
|
coords.y2 = Math.max(coords.y1 + normal.width / aspectRatio, coords.y1);
|
|
}
|
|
}
|
|
if (!isScalingX) {
|
|
coords.x1 = bbox.x;
|
|
coords.x2 = bbox.x + bbox.width;
|
|
}
|
|
if (!isScalingY) {
|
|
coords.y1 = bbox.y;
|
|
coords.y2 = bbox.y + bbox.height;
|
|
}
|
|
}
|
|
updateRect(bbox) {
|
|
if (!bbox)
|
|
return;
|
|
const { rect } = this;
|
|
const normal = this.getNormalisedDimensions();
|
|
const { width, height } = normal;
|
|
let { x, y } = normal;
|
|
x = Math.max(x, bbox.x);
|
|
x -= Math.max(0, x + width - (bbox.x + bbox.width));
|
|
y = Math.max(y, bbox.y);
|
|
y -= Math.max(0, y + height - (bbox.y + bbox.height));
|
|
rect.x = x;
|
|
rect.y = y;
|
|
rect.width = width;
|
|
rect.height = height;
|
|
const zoom = this.createZoomFromCoords(bbox, this.getZoom());
|
|
if (this.isZoomValid(zoom)) {
|
|
rect.updateValid();
|
|
} else {
|
|
rect.updateInvalid();
|
|
}
|
|
}
|
|
createZoomFromCoords(bbox, currentZoom) {
|
|
const oldZoom = definedZoomState9(currentZoom);
|
|
const normal = this.getNormalisedDimensions();
|
|
const origin = pointToRatio(bbox, normal.x, normal.y + normal.height);
|
|
const xFactor = normal.width / bbox.width;
|
|
const yFactor = normal.height / bbox.height;
|
|
let newZoom = scaleZoom(oldZoom, xFactor, yFactor);
|
|
const translateX = origin.x * dx(oldZoom);
|
|
const translateY = origin.y * dy(oldZoom);
|
|
newZoom = translateZoom(newZoom, translateX, translateY);
|
|
newZoom = constrainZoom(newZoom);
|
|
return newZoom;
|
|
}
|
|
getNormalisedDimensions() {
|
|
const { x1 = 0, y1 = 0, x2 = 0, y2 = 0 } = this.coords ?? {};
|
|
const x = Math.min(x1, x2);
|
|
const y = Math.min(y1, y2);
|
|
const width = x1 <= x2 ? x2 - x1 : x1 - x2;
|
|
const height = y1 <= y2 ? y2 - y1 : y1 - y2;
|
|
return { x, y, width, height };
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/zoom/zoomToolbar.ts
|
|
import { _ModuleSupport as _ModuleSupport132 } from "ag-charts-community";
|
|
import {
|
|
ActionOnSet as ActionOnSet8,
|
|
BaseProperties as BaseProperties28,
|
|
ChartAxisDirection as ChartAxisDirection39,
|
|
CleanupRegistry as CleanupRegistry6,
|
|
PropertiesArray as PropertiesArray6,
|
|
Property as Property66,
|
|
UNIT_MAX as UNIT_MAX3,
|
|
UNIT_MIN as UNIT_MIN3,
|
|
createElement as createElement7,
|
|
debounce,
|
|
definedZoomState as definedZoomState10,
|
|
entries as entries9
|
|
} from "ag-charts-core";
|
|
var { userInteraction: userInteraction4, NativeWidget: NativeWidget2, Toolbar: Toolbar2 } = _ModuleSupport132;
|
|
var ZoomButtonProperties = class extends ToolbarButtonProperties {
|
|
};
|
|
__decorateClass([
|
|
Property66
|
|
], ZoomButtonProperties.prototype, "value", 2);
|
|
__decorateClass([
|
|
Property66
|
|
], ZoomButtonProperties.prototype, "section", 2);
|
|
var ZoomToolbar = class extends BaseProperties28 {
|
|
constructor(ctx, getModuleProperties, updateZoom, updateAxisZoom, resetZoom, isZoomValid) {
|
|
super();
|
|
this.ctx = ctx;
|
|
this.getModuleProperties = getModuleProperties;
|
|
this.updateZoom = updateZoom;
|
|
this.updateAxisZoom = updateAxisZoom;
|
|
this.resetZoom = resetZoom;
|
|
this.isZoomValid = isZoomValid;
|
|
this.enabled = false;
|
|
this.buttons = new PropertiesArray6(ZoomButtonProperties);
|
|
this.visible = "hover";
|
|
this.verticalSpacing = 10;
|
|
this.detectionRange = 38;
|
|
this.cleanup = new CleanupRegistry6();
|
|
this.toggleButtonsDebounced = debounce(this.toggleButtons.bind(this), ZOOM_VALID_CHECK_DEBOUNCE, {
|
|
leading: true,
|
|
trailing: true
|
|
});
|
|
this.container = new NativeWidget2(createElement7("div"));
|
|
this.container.addClass("ag-charts-zoom-buttons");
|
|
ctx.domManager.addChild("canvas-overlay", "zoom-buttons", this.container.getElement());
|
|
this.toolbar = new Toolbar2(ctx, "ariaLabelZoomToolbar", "horizontal");
|
|
this.container.addChild(this.toolbar);
|
|
this.toolbar.getElement().style.transform = `translateY(54px)`;
|
|
this.toolbar.setHidden(!this.enabled);
|
|
this.toggleVisibility(this.visible === "always");
|
|
this.cleanup.register(
|
|
this.toolbar.addToolbarListener("button-pressed", this.onButtonPress.bind(this)),
|
|
this.toolbar.addToolbarListener("button-focused", this.onButtonFocus.bind(this)),
|
|
ctx.widgets.containerWidget.addListener("mousemove", this.onHover.bind(this)),
|
|
ctx.widgets.containerWidget.addListener("mouseleave", this.onLeave.bind(this)),
|
|
ctx.eventsHub.on("layout:complete", this.onLayoutComplete.bind(this)),
|
|
this.teardown.bind(this)
|
|
);
|
|
}
|
|
destroy() {
|
|
this.cleanup.flush();
|
|
}
|
|
toggleVisibleZoomed(maxZoom) {
|
|
if (this.visible !== "zoomed")
|
|
return;
|
|
this.toggleVisibility(!maxZoom);
|
|
}
|
|
teardown() {
|
|
this.ctx.domManager.removeChild("canvas-overlay", "zoom-buttons");
|
|
this.container.destroy();
|
|
}
|
|
onLayoutComplete(event) {
|
|
if (!this.enabled)
|
|
return;
|
|
const { buttons, container } = this;
|
|
const { rect } = event.series;
|
|
for (const b of buttons) {
|
|
if (b.tooltip == null && b.label == null) {
|
|
const map = {
|
|
"pan-end": "toolbarZoomPanEnd",
|
|
"pan-left": "toolbarZoomPanLeft",
|
|
"pan-right": "toolbarZoomPanRight",
|
|
"pan-start": "toolbarZoomPanStart",
|
|
"zoom-in": "toolbarZoomZoomIn",
|
|
"zoom-out": "toolbarZoomZoomOut",
|
|
reset: "toolbarZoomReset"
|
|
};
|
|
b.tooltip = map[b.value];
|
|
}
|
|
}
|
|
this.toolbar.updateButtons(buttons);
|
|
this.toggleButtonsDebounced();
|
|
const height = container.getBounds().height;
|
|
container.setBounds({ y: rect.y + rect.height - height });
|
|
}
|
|
onHover(event) {
|
|
if (!this.enabled || this.visible !== "hover" || this.toolbar.isHidden())
|
|
return;
|
|
const {
|
|
container,
|
|
detectionRange,
|
|
ctx: { scene }
|
|
} = this;
|
|
const {
|
|
currentY,
|
|
sourceEvent: { target }
|
|
} = event;
|
|
const element = container.getElement();
|
|
const detectionY = element.offsetTop - detectionRange;
|
|
const visible = currentY > detectionY && currentY < scene.canvas.element.offsetHeight || target === element;
|
|
this.toggleVisibility(visible);
|
|
}
|
|
onLeave() {
|
|
if (this.visible !== "hover")
|
|
return;
|
|
this.toggleVisibility(false);
|
|
}
|
|
toggleVisibility(visible, immediate = false) {
|
|
const { container, toolbar: toolbar2, verticalSpacing } = this;
|
|
toolbar2.toggleClass("ag-charts-zoom-buttons__toolbar--hidden", !visible);
|
|
const element = toolbar2.getElement();
|
|
element.style.transitionDuration = immediate ? "0s" : "";
|
|
element.style.transform = visible ? "translateY(0)" : `translateY(${container.getBounds().height + verticalSpacing}px)`;
|
|
}
|
|
toggleButtons() {
|
|
const zoom = definedZoomState10(this.ctx.zoomManager.getZoom());
|
|
if (this.previousZoom && isZoomEqual(this.previousZoom, zoom))
|
|
return;
|
|
this.previousZoom = zoom;
|
|
for (const [index, button] of this.buttons.entries()) {
|
|
let enabled = true;
|
|
switch (button?.value) {
|
|
case "pan-start":
|
|
enabled = zoom.x.min > UNIT_MIN3;
|
|
break;
|
|
case "pan-end":
|
|
enabled = zoom.x.max < UNIT_MAX3;
|
|
break;
|
|
case "pan-left":
|
|
enabled = zoom.x.min > UNIT_MIN3;
|
|
break;
|
|
case "pan-right":
|
|
enabled = zoom.x.max < UNIT_MAX3;
|
|
break;
|
|
case "zoom-out":
|
|
enabled = !isMaxZoom(zoom);
|
|
break;
|
|
case "zoom-in":
|
|
enabled = this.isZoomValid(
|
|
this.getNextZoomStateUnified("zoom-in", zoom, this.getModuleProperties())
|
|
);
|
|
break;
|
|
case "reset":
|
|
enabled = canResetZoom(this.ctx.zoomManager);
|
|
break;
|
|
}
|
|
this.toolbar.toggleButtonEnabledByIndex(index, enabled);
|
|
}
|
|
}
|
|
onButtonPress({ button }) {
|
|
if (!this.enabled || this.toolbar.isHidden())
|
|
return;
|
|
const props = this.getModuleProperties();
|
|
if (props.independentAxes && button.value !== "reset") {
|
|
const axisZooms = this.ctx.zoomManager.getAxisZooms();
|
|
for (const [axisId, value] of entries9(axisZooms)) {
|
|
if (value == null)
|
|
continue;
|
|
const { direction, min, max } = value;
|
|
this.onButtonPressAxis(button, props, axisId, direction, { min, max });
|
|
}
|
|
} else {
|
|
this.onButtonPressUnified(button, props);
|
|
}
|
|
}
|
|
onButtonFocus(_event) {
|
|
this.toggleVisibility(true, true);
|
|
}
|
|
onButtonPressAxis(event, props, axisId, direction, zoom) {
|
|
const { isScalingX, isScalingY, scrollingStep } = props;
|
|
let newZoom = { ...zoom };
|
|
const delta3 = zoom.max - zoom.min;
|
|
switch (event.value) {
|
|
case "pan-start":
|
|
newZoom.max = delta3;
|
|
newZoom.min = 0;
|
|
break;
|
|
case "pan-end":
|
|
newZoom.min = newZoom.max - delta3;
|
|
newZoom.max = UNIT_MAX3;
|
|
break;
|
|
case "pan-left":
|
|
newZoom.min -= delta3 * scrollingStep;
|
|
newZoom.max -= delta3 * scrollingStep;
|
|
break;
|
|
case "pan-right":
|
|
newZoom.min += delta3 * scrollingStep;
|
|
newZoom.max += delta3 * scrollingStep;
|
|
break;
|
|
case "zoom-in":
|
|
case "zoom-out": {
|
|
const isDirectionX = direction === ChartAxisDirection39.X;
|
|
const isScalingDirection = isDirectionX && isScalingX || !isDirectionX && isScalingY;
|
|
let scale = event.value === "zoom-in" ? 1 - scrollingStep : 1 + scrollingStep;
|
|
if (!isScalingDirection)
|
|
scale = 1;
|
|
const placement = isDirectionX ? this.getAnchorPointX(props) : this.getAnchorPointY(props);
|
|
newZoom.max = newZoom.min + (newZoom.max - newZoom.min) * scale;
|
|
newZoom = scaleZoomAxisWithAnchor(newZoom, zoom, placement);
|
|
break;
|
|
}
|
|
}
|
|
this.updateAxisZoom(userInteraction4(`zoom-button-${event.value}`), axisId, direction, constrainAxis(newZoom));
|
|
}
|
|
onButtonPressUnified(event, props) {
|
|
const { scrollingStep } = props;
|
|
const oldZoom = definedZoomState10(this.ctx.zoomManager.getZoom());
|
|
let zoom = definedZoomState10(oldZoom);
|
|
switch (event.value) {
|
|
case "reset":
|
|
this.resetZoom("zoom-button-reset");
|
|
return;
|
|
case "pan-start":
|
|
zoom.x.max = dx(zoom);
|
|
zoom.x.min = 0;
|
|
break;
|
|
case "pan-end":
|
|
zoom.x.min = UNIT_MAX3 - dx(zoom);
|
|
zoom.x.max = UNIT_MAX3;
|
|
break;
|
|
case "pan-left":
|
|
zoom = translateZoom(zoom, -dx(zoom) * scrollingStep, 0);
|
|
break;
|
|
case "pan-right":
|
|
zoom = translateZoom(zoom, dx(zoom) * scrollingStep, 0);
|
|
break;
|
|
case "zoom-in":
|
|
case "zoom-out": {
|
|
zoom = this.getNextZoomStateUnified(event.value, oldZoom, props);
|
|
break;
|
|
}
|
|
}
|
|
this.updateZoom(userInteraction4(`zoom-button-${event.value}`), constrainZoom(zoom));
|
|
}
|
|
getNextZoomStateUnified(button, oldZoom, props) {
|
|
const { isScalingX, isScalingY, scrollingStep } = props;
|
|
const scale = button === "zoom-in" ? 1 - scrollingStep : 1 + scrollingStep;
|
|
const zoom = scaleZoom(oldZoom, isScalingX ? scale : 1, isScalingY ? scale : 1);
|
|
zoom.x = scaleZoomAxisWithAnchor(zoom.x, oldZoom.x, this.getAnchorPointX(props));
|
|
zoom.y = scaleZoomAxisWithAnchor(zoom.y, oldZoom.y, this.getAnchorPointY(props));
|
|
return zoom;
|
|
}
|
|
getAnchorPointX(props) {
|
|
const anchorPointX = this.anchorPointX ?? props.anchorPointX;
|
|
return anchorPointX === "pointer" ? DEFAULT_ANCHOR_POINT_X : anchorPointX;
|
|
}
|
|
getAnchorPointY(props) {
|
|
const anchorPointY = this.anchorPointY ?? props.anchorPointY;
|
|
return anchorPointY === "pointer" ? DEFAULT_ANCHOR_POINT_Y : anchorPointY;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property66,
|
|
ActionOnSet8({
|
|
changeValue(enabled) {
|
|
this.toolbar?.setHidden(!enabled);
|
|
}
|
|
})
|
|
], ZoomToolbar.prototype, "enabled", 2);
|
|
__decorateClass([
|
|
Property66
|
|
], ZoomToolbar.prototype, "buttons", 2);
|
|
__decorateClass([
|
|
Property66,
|
|
ActionOnSet8({
|
|
changeValue(visible, oldValue) {
|
|
if (oldValue == null)
|
|
return;
|
|
const always = visible === "always";
|
|
const zoomed = visible === "zoomed" && this.previousZoom != null && !isMaxZoom(this.previousZoom);
|
|
this.toggleVisibility(always || zoomed);
|
|
}
|
|
})
|
|
], ZoomToolbar.prototype, "visible", 2);
|
|
__decorateClass([
|
|
Property66
|
|
], ZoomToolbar.prototype, "anchorPointX", 2);
|
|
__decorateClass([
|
|
Property66
|
|
], ZoomToolbar.prototype, "anchorPointY", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/features/zoom/zoomTwoFingers.ts
|
|
var N = 1e6;
|
|
function clientToNormal({ min, max }, a, Rx, Rw) {
|
|
if (Rw === 0)
|
|
return 0;
|
|
return N * ((a - Rx) / Rw * (max - min) + min);
|
|
}
|
|
function solveTwoUnknowns(x1, x2, a1, a2, Rx, Rw) {
|
|
[x1, x2] = [Math.min(x1, x2), Math.max(x1, x2)];
|
|
[a1, a2] = [Math.min(a1, a2), Math.max(a1, a2)];
|
|
const t1 = N * (a1 - Rx) / Rw;
|
|
const t2 = N * (a2 - Rx) / Rw;
|
|
const c = (a1 - Rx) / (a2 - Rx);
|
|
const min = (x1 - c * x2) / (N - t1 + c * (t2 - N));
|
|
const max = (x2 + (t2 - N) * min) / t2;
|
|
return { min, max };
|
|
}
|
|
function isRangeOverlapping(centerA, radiusA, centerB, radiusB) {
|
|
if (radiusA === 0)
|
|
radiusA = 30;
|
|
if (radiusB === 0)
|
|
radiusB = 30;
|
|
const minA = centerA - radiusA;
|
|
const maxA = centerA + radiusA;
|
|
const minB = centerB - radiusB;
|
|
const maxB = centerB + radiusB;
|
|
return !(maxA < minB || maxB < minA);
|
|
}
|
|
var ZoomTwoFingers = class {
|
|
constructor() {
|
|
this.touchStart = {
|
|
origins: [
|
|
{ identifier: 0, normalX: Number.NaN, normalY: Number.NaN },
|
|
{ identifier: 0, normalX: Number.NaN, normalY: Number.NaN }
|
|
]
|
|
};
|
|
this.initialZoom = { x: { min: 0, max: 1 }, y: { min: 0, max: 1 } };
|
|
this.previous = { a1: Number.NaN, a2: Number.NaN, b1: Number.NaN, b2: Number.NaN };
|
|
}
|
|
start(event, target, zoom) {
|
|
if (event.sourceEvent.targetTouches.length !== 2)
|
|
return false;
|
|
event.sourceEvent.preventDefault();
|
|
const targetTouches = Array.from(event.sourceEvent.targetTouches);
|
|
const { x: Rx, y: Ry, width: Rw, height: Rh } = target.getBoundingClientRect();
|
|
this.initialZoom.x.min = zoom.x?.min ?? 0;
|
|
this.initialZoom.x.max = zoom.x?.max ?? 1;
|
|
this.initialZoom.y.min = zoom.y?.min ?? 0;
|
|
this.initialZoom.y.max = zoom.y?.max ?? 1;
|
|
for (const t of this.touchStart.origins) {
|
|
t.identifier = 0;
|
|
}
|
|
this.previous.a1 = Number.NaN;
|
|
this.previous.a2 = Number.NaN;
|
|
this.previous.b1 = Number.NaN;
|
|
this.previous.b2 = Number.NaN;
|
|
for (const i of [0, 1]) {
|
|
const a = targetTouches[i].clientX;
|
|
const b = Ry + Rh - targetTouches[i].clientY;
|
|
this.touchStart.origins[i].identifier = targetTouches[i].identifier;
|
|
this.touchStart.origins[i].normalX = clientToNormal(this.initialZoom.x, a, Rx, Rw);
|
|
this.touchStart.origins[i].normalY = clientToNormal(this.initialZoom.y, b, Ry, Rh);
|
|
}
|
|
const [tA, tB] = targetTouches;
|
|
const [oA, oB] = this.touchStart.origins;
|
|
const xOverlap = isRangeOverlapping(tA.clientX, tA.radiusX, tB.clientX, tB.radiusX);
|
|
const yOverlap = isRangeOverlapping(tA.clientY, tA.radiusY, tB.clientY, tB.radiusY);
|
|
if (yOverlap)
|
|
oA.normalY = oB.normalY = (oA.normalY + oB.normalY) / 2;
|
|
if (xOverlap)
|
|
oA.normalX = oB.normalX = (oA.normalX + oB.normalX) / 2;
|
|
return true;
|
|
}
|
|
update(event, target) {
|
|
event.sourceEvent.preventDefault();
|
|
const targetTouches = Array.from(event.sourceEvent.targetTouches);
|
|
const { x: Rx, y: Ry, width: Rw, height: Rh } = target.getBoundingClientRect();
|
|
const { origins } = this.touchStart;
|
|
const touches = [0, 1].map((i) => targetTouches.find((t) => t.identifier === origins[i].identifier));
|
|
const x1 = origins[0].normalX;
|
|
const x2 = origins[1].normalX;
|
|
const a1 = touches[0].clientX;
|
|
const a2 = touches[1].clientX;
|
|
const y1 = origins[0].normalY;
|
|
const y2 = origins[1].normalY;
|
|
const b1 = Ry + Rh - touches[0].clientY;
|
|
const b2 = Ry + Rh - touches[1].clientY;
|
|
return this.twitchTolerantZoomPan4(x1, x2, a1, a2, y1, y2, b1, b2, Rx, Ry, Rw, Rh);
|
|
}
|
|
end(event) {
|
|
const identifiers = Array.from(event.sourceEvent.targetTouches).map((t) => t.identifier);
|
|
return !identifiers.includes(this.touchStart.origins[0].identifier) || !identifiers.includes(this.touchStart.origins[1].identifier);
|
|
}
|
|
// Small touch deltas on an axis, which can defined as one fingers moving ±1 pixel and the other not moving, can
|
|
// cause the canvas to flicker between two zoompan views.
|
|
//
|
|
// For example, consider two fingers moving upwards slowly on the Y-axis with the following events (Y=0 is the top
|
|
// of the screen):
|
|
//
|
|
// [0]: { finger1: { clientY: 101 }, finger2: { clientY: 201 } }
|
|
// [1]: { finger1: { clientY: 101 }, finger2: { clientY: 200 } }
|
|
// [2]: { finger1: { clientY: 100 }, finger2: { clientY: 200 } }
|
|
//
|
|
// The following transitions cause these changes to the zoompan respectively.
|
|
//
|
|
// [0] => [1] : yMin decreases, yMax increases
|
|
// [1] => [2] : yMin increases, yMax decreases
|
|
//
|
|
// At highly-zoomed views, this sudden shift in yMin/yMax in the [1] => [2] transition is very noticeable. When many
|
|
// of these kind of a transitions occur, the chart flickers between pan states instead of smoothly panning. Note
|
|
// however that, if we didn't receive event [1], our transition would like this:
|
|
//
|
|
// [0] => [2] : yMin increases, yMax increases
|
|
//
|
|
// ... which is a smooth panning transition. Therefore to prevent flickering, we skip event [1].
|
|
twitchTolerantZoomPan4(x1, x2, a1, a2, y1, y2, b1, b2, Rx, Ry, Rw, Rh) {
|
|
const { initialZoom, previous } = this;
|
|
const x = twitchTolerantZoomPan2(x1, x2, a1, a2, previous, "a1", "a2", Rx, Rw, initialZoom.x);
|
|
const y = twitchTolerantZoomPan2(y1, y2, b1, b2, previous, "b1", "b2", Ry, Rh, initialZoom.y);
|
|
return { x, y };
|
|
}
|
|
};
|
|
function twitchTolerantZoomPan2(x1, x2, a1, a2, previous, previousKey1, previousKey2, Rx, Rw, initialZoom) {
|
|
if (x1 == x2) {
|
|
const xn1 = clientToNormal(initialZoom, a1, Rx, Rw);
|
|
const xn2 = clientToNormal(initialZoom, a2, Rx, Rw);
|
|
const xavg = (xn1 + xn2) / 2;
|
|
const dzoom = (x1 - xavg) / N;
|
|
return { min: initialZoom.min + dzoom, max: initialZoom.max + dzoom };
|
|
} else {
|
|
const a1prev = previous[previousKey1];
|
|
const a2prev = previous[previousKey2];
|
|
const dx2 = Math.abs(a1 - a1prev) + Math.abs(a2 - a2prev);
|
|
if (dx2 <= 1) {
|
|
a1 = a1prev;
|
|
a2 = a2prev;
|
|
} else {
|
|
previous[previousKey1] = a1;
|
|
previous[previousKey2] = a2;
|
|
}
|
|
return solveTwoUnknowns(x1, x2, a1, a2, Rx, Rw);
|
|
}
|
|
}
|
|
|
|
// packages/ag-charts-enterprise/src/features/zoom/zoomWheelSequencer.ts
|
|
import { debounce as debounce2 } from "ag-charts-core";
|
|
var ZoomWheelSequencer = class {
|
|
constructor() {
|
|
this.isFirstWheelEvent = true;
|
|
this.debouncedWheelReset = debounce2(() => {
|
|
this.isFirstWheelEvent = true;
|
|
this.wasFirstWheelEventZoomCapped = void 0;
|
|
}, 100);
|
|
}
|
|
onWheel(event, callback4) {
|
|
if (event.sourceEvent.cancelable === false) {
|
|
return;
|
|
}
|
|
const result = callback4();
|
|
if (result === "abort")
|
|
return;
|
|
const isZoomCapped = result === "capped";
|
|
if (this.firstWheelEventDirection != null && this.firstWheelEventDirection !== event.deltaY < 0) {
|
|
this.isFirstWheelEvent = true;
|
|
}
|
|
if (this.isFirstWheelEvent) {
|
|
this.wasFirstWheelEventZoomCapped = isZoomCapped;
|
|
this.firstWheelEventDirection = event.deltaY < 0;
|
|
if (!isZoomCapped) {
|
|
event.sourceEvent.preventDefault();
|
|
}
|
|
} else if (this.wasFirstWheelEventZoomCapped === false) {
|
|
event.sourceEvent.preventDefault();
|
|
}
|
|
this.isFirstWheelEvent = false;
|
|
this.debouncedWheelReset();
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/features/zoom/zoom.ts
|
|
var { userInteraction: userInteraction5, InteractionState: InteractionState6 } = _ModuleSupport133;
|
|
var round = (value) => roundTo(value, 10);
|
|
var CURSOR_ID = "zoom-cursor";
|
|
var TOOLTIP_ID = "zoom-tooltip";
|
|
var Zoom = class extends AbstractModuleInstance16 {
|
|
constructor(ctx) {
|
|
super();
|
|
this.ctx = ctx;
|
|
this.enabled = false;
|
|
this.enableAxisDragging = true;
|
|
this.enableAxisScrolling = true;
|
|
this.enableDoubleClickToReset = true;
|
|
this.enablePanning = true;
|
|
this.enableScrolling = true;
|
|
this.enableSelecting = false;
|
|
this.enableTwoFingerZoom = true;
|
|
this.panKey = "alt";
|
|
this.axes = "x";
|
|
this.scrollingStep = UNIT_SIZE / 10;
|
|
this.keepAspectRatio = false;
|
|
this.minVisibleItems = 2;
|
|
this.anchorPointX = DEFAULT_ANCHOR_POINT_X;
|
|
this.anchorPointY = DEFAULT_ANCHOR_POINT_Y;
|
|
this.autoScaling = new ZoomAutoScalingProperties();
|
|
this.axisDraggingMode = "zoom";
|
|
this.buttons = new ZoomToolbar(
|
|
this.ctx,
|
|
this.getModuleProperties.bind(this),
|
|
this.updateZoom.bind(this),
|
|
this.updateAxisZoom.bind(this),
|
|
this.resetZoom.bind(this),
|
|
this.isZoomValid.bind(this)
|
|
);
|
|
this.onDataChange = new ZoomOnDataChangeProperties();
|
|
// Zoom methods
|
|
this.axisDragger = new ZoomAxisDragger();
|
|
this.panner = new ZoomPanner();
|
|
this.scroller = new ZoomScroller();
|
|
this.scrollPanner = new ZoomScrollPanner();
|
|
this.twoFingers = new ZoomTwoFingers();
|
|
this.deceleration = "short";
|
|
// State
|
|
this.dragState = 0 /* None */;
|
|
this.isState = (state) => this.ctx.interactionManager.isState(state);
|
|
this.destroyContextMenuActions = void 0;
|
|
this.wheelSequencer = new ZoomWheelSequencer();
|
|
this.previousZoomValid = true;
|
|
this.previousAxisZoomValid = {
|
|
[ChartAxisDirection40.X]: true,
|
|
[ChartAxisDirection40.Y]: true
|
|
};
|
|
this.toggleAxisDraggingCursorsDebounced = debounce3(
|
|
this.toggleAxisDraggingCursors.bind(this),
|
|
ZOOM_VALID_CHECK_DEBOUNCE,
|
|
{
|
|
leading: true,
|
|
trailing: true
|
|
}
|
|
);
|
|
const selectionRect = new ZoomRect();
|
|
this.selector = new ZoomSelector(selectionRect, this.getZoom.bind(this), this.isZoomValid.bind(this));
|
|
this.contextMenu = new ZoomContextMenu(
|
|
ctx.eventsHub,
|
|
ctx.contextMenuRegistry,
|
|
ctx.zoomManager,
|
|
this.getModuleProperties.bind(this),
|
|
() => this.paddedRect,
|
|
this.updateZoom.bind(this),
|
|
this.isZoomValid.bind(this)
|
|
);
|
|
const minVisibleItemsCallback = (event) => {
|
|
if (this.minVisibleItems > 0) {
|
|
const restrictions = event.stateAsDefinedZoom();
|
|
event.constrainZoom(this.constrainZoom(restrictions));
|
|
}
|
|
};
|
|
this.dataChangeHandler = new ZoomOnDataChange(
|
|
minVisibleItemsCallback,
|
|
this.onDataChange,
|
|
this.ctx,
|
|
this.cleanup
|
|
);
|
|
this.domProxy = new ZoomDOMProxy({
|
|
onAxisDragStart: (direction) => this.onAxisDragStart(direction),
|
|
onAxisDragMove: (id, direction, event) => this.onAxisDragMove(id, direction, event),
|
|
onAxisDragEnd: () => this.onAxisDragEnd(),
|
|
onAxisDoubleClick: (id) => this.onAxisDoubleClick(id),
|
|
onAxisWheel: (direction, event) => this.onAxisWheel(direction, event)
|
|
});
|
|
if (ctx.widgets.seriesDragInterpreter) {
|
|
this.cleanup.register(
|
|
ctx.widgets.seriesDragInterpreter.events.on("dblclick", (event) => this.onSeriesAreaDoubleClick(event)),
|
|
ctx.widgets.seriesDragInterpreter.events.on("drag-move", (event) => this.onSeriesAreaDragMove(event)),
|
|
ctx.widgets.seriesDragInterpreter.events.on("drag-start", (event) => this.onSeriesAreaDragStart(event)),
|
|
ctx.widgets.seriesDragInterpreter.events.on("drag-end", () => this.onSeriesAreaDragEnd())
|
|
);
|
|
}
|
|
this.cleanup.register(
|
|
ctx.scene.attachNode(selectionRect),
|
|
ctx.eventsHub.on("series-area:hover", (event) => this.onSeriesAreaHoverEvent(event)),
|
|
ctx.eventsHub.on("series-area:click", (event) => this.onSeriesAreaClickEvent(event)),
|
|
ctx.eventsHub.on("series:keynav-zoom", (event) => this.onNavZoom(event)),
|
|
ctx.widgets.seriesWidget.addListener("wheel", (event) => this.onWheel(event)),
|
|
ctx.widgets.seriesWidget.addListener("touchstart", (event, current) => this.onTouchStart(event, current)),
|
|
ctx.widgets.seriesWidget.addListener("touchmove", (event, current) => this.onTouchMove(event, current)),
|
|
ctx.widgets.seriesWidget.addListener("touchend", (event) => this.onTouchEnd(event)),
|
|
ctx.widgets.seriesWidget.addListener("touchcancel", (event) => this.onTouchEnd(event)),
|
|
ctx.updateService.addListener("process-data", (event) => this.onProcessData(event)),
|
|
ctx.eventsHub.on("layout:complete", (event) => this.onLayoutComplete(event)),
|
|
ctx.eventsHub.on("zoom:change-request", (event) => this.onZoomChangeRequested(event)),
|
|
ctx.eventsHub.on("zoom:pan-start", (event) => this.onZoomPanStart(event)),
|
|
this.panner.addListener("update", (event) => this.onPanUpdate(event)),
|
|
() => this.teardown()
|
|
);
|
|
this.autoScaler = new ZoomAutoScaler(this.autoScaling, ctx.zoomManager, this, ctx.eventsHub, this.cleanup);
|
|
}
|
|
teardown() {
|
|
this.ctx.zoomManager.setZoomModuleEnabled(false);
|
|
this.buttons.destroy();
|
|
this.destroyContextMenuActions?.();
|
|
this.domProxy.destroy();
|
|
this.dataChangeHandler.destroy();
|
|
}
|
|
onEnabledChange(enabled) {
|
|
this.ctx.zoomManager.setZoomModuleEnabled(enabled);
|
|
if (this.contextMenu) {
|
|
this.destroyContextMenuActions?.();
|
|
this.destroyContextMenuActions = this.contextMenu.registerActions(enabled);
|
|
}
|
|
}
|
|
isIgnoredTouch(event) {
|
|
if (event?.device !== "touch") {
|
|
return false;
|
|
}
|
|
if (this.ctx.chartService.touch.dragAction !== "drag") {
|
|
return true;
|
|
}
|
|
if (this.enableSelecting) {
|
|
return false;
|
|
}
|
|
if (!this.enablePanning) {
|
|
return true;
|
|
}
|
|
return isMaxZoom(this.getZoom());
|
|
}
|
|
onSeriesAreaDoubleClick(event) {
|
|
const { enabled, enableDoubleClickToReset } = this;
|
|
if (!enabled || !enableDoubleClickToReset)
|
|
return;
|
|
if (event?.preventZoomDblClick || !this.isState(InteractionState6.ZoomClickable))
|
|
return;
|
|
this.resetZoom("zoom-seriesarea-dblclick");
|
|
}
|
|
onSeriesAreaHoverEvent(event) {
|
|
if (!this.shouldHandleAxisHover(event)) {
|
|
this.clearHoveredAxis();
|
|
return;
|
|
}
|
|
const axis = this.domProxy.pickAxisAtPoint(event);
|
|
if (axis) {
|
|
this.domProxy.setHoveredAxis(axis.axisId);
|
|
this.ctx.domManager.updateCursor(CURSOR_ID, this.domProxy.getCursor(axis.direction));
|
|
} else {
|
|
this.clearHoveredAxis();
|
|
}
|
|
}
|
|
onSeriesAreaClickEvent(event) {
|
|
if (!this.shouldHandleAxisClick(event))
|
|
return;
|
|
const axis = this.domProxy.pickAxisAtPoint(event);
|
|
if (axis && event.sourceEvent?.type === "dblclick") {
|
|
this.onAxisDoubleClick(axis.axisId);
|
|
}
|
|
}
|
|
shouldHandleAxisHover(event) {
|
|
const { enabled, enableAxisDragging, enableAxisScrolling, dragState } = this;
|
|
return enabled && (enableAxisDragging || enableAxisScrolling) && !event.consumed && !this.activeAxis && dragState === 0 /* None */ && this.domProxy.hasOverlappingAxes();
|
|
}
|
|
shouldHandleAxisClick(event) {
|
|
const { enabled, enableAxisDragging, enableAxisScrolling, enableDoubleClickToReset } = this;
|
|
return enabled && !this.activeAxis && !event.consumed && (enableAxisDragging || enableAxisScrolling || enableDoubleClickToReset);
|
|
}
|
|
clearHoveredAxis() {
|
|
if (this.activeAxis)
|
|
return;
|
|
this.domProxy.clearHoveredAxis();
|
|
if (this.dragState === 0 /* None */) {
|
|
this.ctx.domManager.updateCursor(CURSOR_ID);
|
|
}
|
|
}
|
|
tryBeginAxisDelegation(event) {
|
|
const hoveredAxis = this.domProxy.getHoveredAxis();
|
|
if (!this.enabled || !this.enableAxisDragging || !hoveredAxis) {
|
|
return false;
|
|
}
|
|
if (!this.domProxy.beginDelegatedAxisDrag(hoveredAxis.axisId)) {
|
|
return false;
|
|
}
|
|
this.activeAxis = hoveredAxis;
|
|
this.onAxisDragStart(hoveredAxis.direction);
|
|
const cursor = this.dragState === 2 /* Pan */ ? "grabbing" : this.domProxy.getCursor(hoveredAxis.direction);
|
|
this.ctx.domManager.updateCursor(CURSOR_ID, cursor);
|
|
if (event.device === "touch") {
|
|
event.sourceEvent.preventDefault();
|
|
}
|
|
return true;
|
|
}
|
|
onSeriesAreaDragStart(event) {
|
|
const {
|
|
enabled,
|
|
enablePanning,
|
|
enableSelecting,
|
|
ctx: { domManager, zoomManager }
|
|
} = this;
|
|
if (!enabled || !this.isState(InteractionState6.ZoomDraggable) || this.dragState !== 0 /* None */ || this.isIgnoredTouch(event)) {
|
|
return;
|
|
}
|
|
this.panner.stopInteractions();
|
|
if (this.tryBeginAxisDelegation(event)) {
|
|
return;
|
|
}
|
|
let newDragState = 0 /* None */;
|
|
const panKeyPressed = this.isPanningKeyPressed(event.sourceEvent);
|
|
if (enablePanning && (!enableSelecting || panKeyPressed)) {
|
|
domManager.updateCursor(CURSOR_ID, "grabbing");
|
|
newDragState = 2 /* Pan */;
|
|
this.panner.start();
|
|
} else if (enableSelecting && !panKeyPressed) {
|
|
newDragState = 3 /* Select */;
|
|
}
|
|
if ((this.dragState = newDragState) !== 0 /* None */) {
|
|
zoomManager.fireZoomPanStartEvent("zoom");
|
|
}
|
|
}
|
|
onSeriesAreaDragMove(event) {
|
|
const {
|
|
dragState,
|
|
enabled,
|
|
paddedRect,
|
|
panner,
|
|
selector,
|
|
ctx: { interactionManager, tooltipManager, updateService }
|
|
} = this;
|
|
if (this.activeAxis) {
|
|
this.onAxisDragMove(this.activeAxis.axisId, this.activeAxis.direction, event);
|
|
return;
|
|
}
|
|
if (!enabled || !paddedRect || !this.isState(InteractionState6.ZoomDraggable) || this.isIgnoredTouch(event)) {
|
|
return;
|
|
}
|
|
interactionManager.pushState(_ModuleSupport133.InteractionState.ZoomDrag);
|
|
if (event.device === "touch") {
|
|
event.sourceEvent.preventDefault();
|
|
}
|
|
switch (dragState) {
|
|
case 2 /* Pan */:
|
|
panner.update(event);
|
|
break;
|
|
case 3 /* Select */:
|
|
selector.update(event, this.getModuleProperties(), paddedRect);
|
|
break;
|
|
case 0 /* None */:
|
|
return;
|
|
}
|
|
tooltipManager.updateTooltip(TOOLTIP_ID);
|
|
updateService.update(ChartUpdateType8.PERFORM_LAYOUT, { skipAnimations: true });
|
|
}
|
|
onSeriesAreaDragEnd() {
|
|
const {
|
|
ctx: { interactionManager }
|
|
} = this;
|
|
if (this.activeAxis) {
|
|
this.handleAxisDragEnd();
|
|
return;
|
|
}
|
|
interactionManager.popState(_ModuleSupport133.InteractionState.ZoomDrag);
|
|
if (!this.enabled || this.dragState === 0 /* None */)
|
|
return;
|
|
this.handleRegularDragEnd();
|
|
this.resetDragState();
|
|
}
|
|
handleAxisDragEnd() {
|
|
this.onAxisDragEnd();
|
|
this.domProxy.endDelegatedAxisDrag(this.activeAxis.axisId);
|
|
this.activeAxis = void 0;
|
|
this.clearHoveredAxis();
|
|
}
|
|
handleRegularDragEnd() {
|
|
const { panner, selector } = this;
|
|
switch (this.dragState) {
|
|
case 2 /* Pan */:
|
|
panner.stop();
|
|
break;
|
|
case 3 /* Select */:
|
|
if (selector.didUpdate()) {
|
|
const newZoom = selector.stop(this.seriesRect, this.paddedRect, this.getZoom());
|
|
if (newZoom) {
|
|
this.updateZoom(userInteraction5("zoom-seriesarea-selector"), newZoom);
|
|
} else {
|
|
this.ctx.updateService.update();
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
resetDragState() {
|
|
this.dragState = 0 /* None */;
|
|
this.ctx.domManager.updateCursor(CURSOR_ID);
|
|
this.ctx.tooltipManager.removeTooltip(TOOLTIP_ID);
|
|
}
|
|
onAxisDoubleClick(id) {
|
|
const {
|
|
enabled,
|
|
enableDoubleClickToReset,
|
|
ctx: { zoomManager }
|
|
} = this;
|
|
if (!enabled || !enableDoubleClickToReset || !this.isState(InteractionState6.ZoomClickable))
|
|
return;
|
|
this.previousAxisZoomValid = { [ChartAxisDirection40.X]: true, [ChartAxisDirection40.Y]: true };
|
|
zoomManager.resetAxisZoom({ source: "user-interaction", sourceDetail: "zoom-axis-dblclick" }, id);
|
|
}
|
|
onAxisDragStart(direction) {
|
|
const {
|
|
axisDraggingMode,
|
|
domProxy,
|
|
enabled,
|
|
enableAxisDragging,
|
|
panner,
|
|
ctx: { zoomManager }
|
|
} = this;
|
|
if (!enabled || !enableAxisDragging)
|
|
return;
|
|
panner.stopInteractions();
|
|
if (axisDraggingMode === "pan") {
|
|
domProxy.setAxisCursor("grabbing");
|
|
this.dragState = 2 /* Pan */;
|
|
this.panner.start(direction);
|
|
zoomManager.fireZoomPanStartEvent("zoom");
|
|
} else {
|
|
this.dragState = 1 /* Axis */;
|
|
}
|
|
}
|
|
onAxisDragMove(axisId, direction, event) {
|
|
const {
|
|
anchorPointX,
|
|
anchorPointY,
|
|
axisDragger,
|
|
dragState,
|
|
enabled,
|
|
enableAxisDragging,
|
|
seriesRect,
|
|
shouldFlipXY,
|
|
ctx: { interactionManager, tooltipManager, updateService, zoomManager }
|
|
} = this;
|
|
if (!enabled || !enableAxisDragging || !seriesRect)
|
|
return;
|
|
interactionManager.pushState(_ModuleSupport133.InteractionState.ZoomDrag);
|
|
if (event.device === "touch") {
|
|
event.sourceEvent.preventDefault();
|
|
}
|
|
const zoom = this.getZoom();
|
|
if (dragState === 2 /* Pan */) {
|
|
this.panner.update({ currentX: event.offsetX, currentY: event.offsetY });
|
|
} else {
|
|
let anchor = direction === ChartAxisDirection40.X ? anchorPointX : anchorPointY;
|
|
if (shouldFlipXY)
|
|
anchor = direction === ChartAxisDirection40.X ? anchorPointY : anchorPointX;
|
|
const axisZoom = zoomManager.getAxisZoom(axisId);
|
|
const newZoom = axisDragger.update(event, direction, anchor, seriesRect, zoom, axisZoom);
|
|
this.autoScaler.onManualAdjustment(direction);
|
|
this.updateAxisZoom(
|
|
userInteraction5("zoom-axis-drag"),
|
|
axisId,
|
|
direction,
|
|
newZoom,
|
|
{ directional: true }
|
|
);
|
|
}
|
|
tooltipManager.updateTooltip(TOOLTIP_ID);
|
|
updateService.update(ChartUpdateType8.PERFORM_LAYOUT, { skipAnimations: true });
|
|
}
|
|
onAxisDragEnd() {
|
|
const {
|
|
axisDraggingMode,
|
|
axisDragger,
|
|
dragState,
|
|
domProxy,
|
|
enabled,
|
|
enableAxisDragging,
|
|
ctx: { domManager, interactionManager, tooltipManager }
|
|
} = this;
|
|
interactionManager.popState(_ModuleSupport133.InteractionState.ZoomDrag);
|
|
if (!enabled || !enableAxisDragging || dragState === 0 /* None */)
|
|
return;
|
|
this.dragState = 0 /* None */;
|
|
if (axisDraggingMode === "pan") {
|
|
domProxy.setAxisCursor("grab");
|
|
this.panner.stop();
|
|
}
|
|
axisDragger.stop();
|
|
domManager.updateCursor(CURSOR_ID);
|
|
tooltipManager.removeTooltip(TOOLTIP_ID);
|
|
}
|
|
onNavZoom(event) {
|
|
const { enabled, enableScrolling, scroller } = this;
|
|
const isDefaultState = this.ctx.interactionManager.isState(_ModuleSupport133.InteractionState.Default);
|
|
if (!isDefaultState || !enabled || !enableScrolling)
|
|
return;
|
|
event.widgetEvent.sourceEvent.preventDefault();
|
|
this.updateZoom(
|
|
userInteraction5(`keyboard(${event.delta})`),
|
|
scroller.updateDelta(event.delta, this.getModuleProperties(), this.getZoom())
|
|
);
|
|
}
|
|
onWheel(event) {
|
|
const { enabled, enablePanning, enableScrolling, paddedRect } = this;
|
|
if (!enabled || !enableScrolling || !paddedRect || !this.isState(InteractionState6.ZoomWheelable))
|
|
return;
|
|
const { deltaX, deltaY } = event.sourceEvent;
|
|
const isHorizontalScrolling = deltaX != null && deltaY != null && Math.abs(deltaX) > Math.abs(deltaY);
|
|
if (enablePanning && isHorizontalScrolling) {
|
|
this.onWheelPanning(event);
|
|
} else {
|
|
this.onWheelScrolling(event);
|
|
}
|
|
}
|
|
onWheelPanning(event) {
|
|
const {
|
|
scrollingStep,
|
|
scrollPanner,
|
|
seriesRect,
|
|
ctx: { zoomManager }
|
|
} = this;
|
|
if (!seriesRect)
|
|
return;
|
|
event.sourceEvent.preventDefault();
|
|
const newZooms = scrollPanner.update(event, scrollingStep, seriesRect, zoomManager.getAxisZooms());
|
|
this.updateChanges(userInteraction5("zoom-seriesarea-wheel"), newZooms);
|
|
}
|
|
onWheelScrolling(event) {
|
|
const zoom = this.getZoom();
|
|
const isZoomCapped = event.deltaY > 0 && isMaxZoom(zoom);
|
|
this.wheelSequencer.onWheel(event, () => this.handleWheelScrolling(event, isZoomCapped));
|
|
}
|
|
onAxisWheel(axisDirection, event) {
|
|
if (!this.enableAxisScrolling)
|
|
return;
|
|
if (axisDirection !== ChartAxisDirection40.X && axisDirection !== ChartAxisDirection40.Y) {
|
|
return;
|
|
}
|
|
const isScalingX = axisDirection === ChartAxisDirection40.X;
|
|
const isScalingY = !isScalingX;
|
|
const props = this.getModuleProperties({ isScalingX, isScalingY });
|
|
const zoom = this.getZoom();
|
|
const isZoomCapped = event.deltaY > 0 && zoom[axisDirection].min === UNIT_MIN4 && zoom[axisDirection].max === UNIT_MAX4;
|
|
this.autoScaler.onManualAdjustment(axisDirection);
|
|
this.wheelSequencer.onWheel(event, () => this.handleWheelScrolling(event, isZoomCapped, props));
|
|
}
|
|
handleWheelScrolling(event, isZoomCapped, props = this.getModuleProperties()) {
|
|
const {
|
|
enableIndependentAxes,
|
|
scroller,
|
|
seriesRect,
|
|
ctx: { zoomManager }
|
|
} = this;
|
|
if (!seriesRect)
|
|
return "abort";
|
|
let updated = true;
|
|
const sourcing = userInteraction5("zoom-axis-wheel");
|
|
if (enableIndependentAxes === true) {
|
|
const newZooms = scroller.updateAxes(event, props, seriesRect, zoomManager.getAxisZooms());
|
|
for (const [axisId, { direction, min, max }] of entries10(newZooms)) {
|
|
const constrainedZoom = direction === ChartAxisDirection40.X ? this.constrainZoom({ x: { min, max }, y: { min: UNIT_MAX4, max: UNIT_MAX4 } }).x : { min, max };
|
|
updated && (updated = this.updateAxisZoom(sourcing, axisId, direction, constrainedZoom));
|
|
}
|
|
} else {
|
|
const newZoom = scroller.update(event, props, seriesRect, this.getZoom());
|
|
if (newZoom == null)
|
|
return "abort";
|
|
updated = this.updateUnifiedZoom(sourcing, newZoom, { directional: true });
|
|
}
|
|
return isZoomCapped || event.deltaY < 0 && !updated ? "capped" : "uncapped";
|
|
}
|
|
onTouchStart(event, current) {
|
|
if (!this.enableTwoFingerZoom || this.dragState !== 0 /* None */)
|
|
return;
|
|
if (this.twoFingers.start(event, current, this.getZoom())) {
|
|
this.dragState = 4 /* TwoFingers */;
|
|
}
|
|
}
|
|
onTouchMove(event, current) {
|
|
if (!this.enableTwoFingerZoom || this.dragState !== 4 /* TwoFingers */)
|
|
return;
|
|
const newZoom = this.twoFingers.update(event, current);
|
|
this.updateZoom(userInteraction5("zoom-seriesarea-twofingers"), constrainZoom(newZoom));
|
|
}
|
|
onTouchEnd(event) {
|
|
if (!this.enableTwoFingerZoom || this.dragState !== 4 /* TwoFingers */)
|
|
return;
|
|
event.sourceEvent.preventDefault();
|
|
if (this.twoFingers.end(event)) {
|
|
this.dragState = 0 /* None */;
|
|
}
|
|
}
|
|
onProcessData(event) {
|
|
this.shouldFlipXY = event.series.shouldFlipXY;
|
|
}
|
|
onLayoutComplete(event) {
|
|
this.domProxy.update(
|
|
this.enabled,
|
|
this.enableAxisDragging,
|
|
this.enableAxisScrolling,
|
|
this.ctx,
|
|
event.series.rect
|
|
);
|
|
if (!this.enabled)
|
|
return;
|
|
this.seriesRect = event.series.rect;
|
|
this.paddedRect = event.series.paddedRect;
|
|
if (this.enableAxisDragging) {
|
|
this.toggleAxisDraggingCursorsDebounced();
|
|
}
|
|
}
|
|
onZoomChangeRequested(event) {
|
|
if (event.sourceDetail !== "zoom-seriesarea-panner") {
|
|
this.panner.stopInteractions();
|
|
}
|
|
const zoom = this.getZoom();
|
|
this.buttons.toggleVisibleZoomed(isMaxZoom(zoom));
|
|
}
|
|
onZoomPanStart(event) {
|
|
if (event.callerId === "zoom") {
|
|
this.panner.stopInteractions();
|
|
}
|
|
}
|
|
onPanUpdate(event) {
|
|
const {
|
|
panner,
|
|
seriesRect,
|
|
ctx: { tooltipManager, zoomManager }
|
|
} = this;
|
|
if (!seriesRect)
|
|
return;
|
|
const newZooms = panner.translateZooms(seriesRect, zoomManager.getAxisZooms(), event.deltaX, event.deltaY);
|
|
this.updateChanges(userInteraction5("zoom-seriesarea-panner"), newZooms);
|
|
tooltipManager.updateTooltip(TOOLTIP_ID);
|
|
}
|
|
isPanningKeyPressed(event) {
|
|
switch (this.panKey) {
|
|
case "alt":
|
|
return event.altKey;
|
|
case "ctrl":
|
|
return event.ctrlKey;
|
|
case "shift":
|
|
return event.shiftKey;
|
|
case "meta":
|
|
return event.metaKey;
|
|
}
|
|
}
|
|
isScalingX() {
|
|
if (this.axes === "xy")
|
|
return true;
|
|
return this.shouldFlipXY ? this.axes === "y" : this.axes === "x";
|
|
}
|
|
isScalingY() {
|
|
if (this.axes === "xy")
|
|
return true;
|
|
return this.shouldFlipXY ? this.axes === "x" : this.axes === "y";
|
|
}
|
|
getAnchorPointX() {
|
|
return this.shouldFlipXY ? this.anchorPointY : this.anchorPointX;
|
|
}
|
|
getAnchorPointY() {
|
|
return this.shouldFlipXY ? this.anchorPointX : this.anchorPointY;
|
|
}
|
|
constrainZoom(newZoom) {
|
|
return this.ctx.zoomManager.constrainZoomToItemCount(newZoom, this.minVisibleItems, this.autoScaler.enabled);
|
|
}
|
|
isZoomValid(newZoom, options) {
|
|
const {
|
|
minVisibleItems,
|
|
ctx: { zoomManager }
|
|
} = this;
|
|
if (minVisibleItems === 0) {
|
|
this.previousZoomValid = true;
|
|
return true;
|
|
}
|
|
const zoom = this.getZoom();
|
|
const zoomedInX = round(dx(newZoom)) < round(dx(zoom));
|
|
const zoomedInY = round(dy(newZoom)) < round(dy(zoom));
|
|
if (!zoomedInX && !zoomedInY) {
|
|
this.previousZoomValid = true;
|
|
return true;
|
|
}
|
|
if (!this.previousZoomValid && options?.directional) {
|
|
return false;
|
|
}
|
|
const includeYVisibleRange = options?.includeYVisibleRange ?? false;
|
|
const autoScaleYAxis = this.autoScaler.enabled;
|
|
const valid = zoomManager.isVisibleItemsCountAtLeast(newZoom, minVisibleItems, {
|
|
includeYVisibleRange,
|
|
autoScaleYAxis
|
|
});
|
|
this.previousZoomValid = options?.directional ? valid : true;
|
|
return valid;
|
|
}
|
|
isAxisZoomValid(direction, axisZoom, options) {
|
|
const {
|
|
minVisibleItems,
|
|
ctx: { zoomManager }
|
|
} = this;
|
|
const zoom = this.getZoom();
|
|
const deltaAxis = axisZoom.max - axisZoom.min;
|
|
const deltaOld = zoom[direction].max - zoom[direction].min;
|
|
const newZoom = { ...zoom, [direction]: axisZoom };
|
|
if (deltaAxis >= deltaOld) {
|
|
this.previousAxisZoomValid[direction] = true;
|
|
return true;
|
|
}
|
|
if (!this.previousAxisZoomValid[direction] && options?.directional) {
|
|
return false;
|
|
}
|
|
const opts = { includeYVisibleRange: false, autoScaleYAxis: this.autoScaler.enabled };
|
|
const valid = zoomManager.isVisibleItemsCountAtLeast(newZoom, minVisibleItems, opts);
|
|
this.previousAxisZoomValid[direction] = options?.directional ? valid : true;
|
|
return valid;
|
|
}
|
|
resetZoom(sourceDetail) {
|
|
this.previousZoomValid = true;
|
|
this.previousAxisZoomValid = { [ChartAxisDirection40.X]: true, [ChartAxisDirection40.Y]: true };
|
|
this.ctx.zoomManager.resetZoom({ source: "user-interaction", sourceDetail });
|
|
}
|
|
updateSyncZoom(zoom) {
|
|
this.updateZoom({ source: "sync", sourceDetail: "internal-updateSyncZoom" }, zoom);
|
|
}
|
|
updateChanges(sourcing, changes) {
|
|
const partialZoom = this.ctx.zoomManager.toZoomState(changes) ?? {};
|
|
const currentZoom = definedZoomState11(this.ctx.zoomManager.getZoom());
|
|
this.updateZoom(sourcing, {
|
|
x: partialZoom.x ?? currentZoom.x,
|
|
y: partialZoom.y ?? currentZoom.y
|
|
});
|
|
}
|
|
updateZoom(sourcing, zoom) {
|
|
if (this.enableIndependentAxes) {
|
|
this.updatePrimaryAxisZooms(sourcing, zoom);
|
|
} else {
|
|
this.updateUnifiedZoom(sourcing, zoom);
|
|
}
|
|
}
|
|
updateUnifiedZoom(sourcing, zoom, validOptions) {
|
|
zoom = this.constrainZoom(zoom);
|
|
if (!this.isZoomValid(zoom, validOptions)) {
|
|
this.ctx.updateService.update(ChartUpdateType8.SCENE_RENDER, { skipAnimations: true });
|
|
return false;
|
|
}
|
|
this.ctx.zoomManager.updateZoom(sourcing, zoom);
|
|
return true;
|
|
}
|
|
updatePrimaryAxisZooms(sourcing, zoom) {
|
|
this.updatePrimaryAxisZoom(sourcing, zoom, ChartAxisDirection40.X);
|
|
this.updatePrimaryAxisZoom(sourcing, zoom, ChartAxisDirection40.Y);
|
|
}
|
|
updatePrimaryAxisZoom(sourcing, zoom, direction) {
|
|
const axisId = this.ctx.zoomManager.getPrimaryAxisId(direction);
|
|
if (axisId == null)
|
|
return;
|
|
this.updateAxisZoom(sourcing, axisId, direction, zoom[direction]);
|
|
}
|
|
updateAxisZoom(sourcing, axisId, direction, axisZoom, validOptions) {
|
|
const {
|
|
enableIndependentAxes,
|
|
ctx: { zoomManager }
|
|
} = this;
|
|
if (!axisZoom)
|
|
return false;
|
|
const zoom = this.getZoom();
|
|
if (enableIndependentAxes !== true) {
|
|
zoom[direction] = axisZoom;
|
|
return this.updateUnifiedZoom(sourcing, zoom, validOptions);
|
|
}
|
|
if (!this.isAxisZoomValid(direction, axisZoom, validOptions))
|
|
return false;
|
|
const { source, sourceDetail } = sourcing;
|
|
zoomManager.updateChanges({ source, sourceDetail, changes: { [axisId]: axisZoom }, isReset: false });
|
|
return true;
|
|
}
|
|
updateAxisCursor(opts) {
|
|
if (!this.domProxy)
|
|
return;
|
|
const {
|
|
enableAxisDragging = this.enableAxisDragging,
|
|
enableAxisScrolling = this.enableAxisScrolling,
|
|
axisDraggingMode = this.axisDraggingMode
|
|
} = opts;
|
|
if (enableAxisDragging) {
|
|
this.domProxy.setAxisCursor(axisDraggingMode === "pan" ? "grab" : void 0);
|
|
} else if (enableAxisScrolling) {
|
|
this.domProxy.setAxisCursor("default");
|
|
} else {
|
|
this.domProxy.setAxisCursor(void 0);
|
|
}
|
|
}
|
|
toggleAxisDraggingCursors() {
|
|
const { anchorPointX, anchorPointY, domProxy } = this;
|
|
const zoom = this.getZoom();
|
|
let showCursorX = dx(zoom) !== UNIT_SIZE;
|
|
let showCursorY = dy(zoom) !== UNIT_SIZE;
|
|
if (!showCursorX) {
|
|
const checkZoomX = scaleZoom(zoom, 0.999, 1);
|
|
checkZoomX.x = scaleZoomAxisWithAnchor(checkZoomX.x, zoom.x, anchorPointX);
|
|
showCursorX = this.isZoomValid(checkZoomX, { includeYVisibleRange: true });
|
|
}
|
|
if (!showCursorY) {
|
|
const checkZoomY = scaleZoom(zoom, 1, 0.999);
|
|
checkZoomY.y = scaleZoomAxisWithAnchor(checkZoomY.y, zoom.y, anchorPointY);
|
|
showCursorY = this.isZoomValid(checkZoomY, { includeYVisibleRange: true });
|
|
}
|
|
domProxy.toggleAxisDraggingCursor(ChartAxisDirection40.X, showCursorX);
|
|
domProxy.toggleAxisDraggingCursor(ChartAxisDirection40.Y, showCursorY);
|
|
}
|
|
getZoom() {
|
|
return definedZoomState11(this.ctx.zoomManager.getZoom());
|
|
}
|
|
getModuleProperties(overrides) {
|
|
return {
|
|
anchorPointX: overrides?.anchorPointX ?? this.getAnchorPointX(),
|
|
anchorPointY: overrides?.anchorPointY ?? this.getAnchorPointY(),
|
|
enabled: overrides?.enabled ?? this.enabled,
|
|
independentAxes: overrides?.independentAxes ?? this.enableIndependentAxes === true,
|
|
isScalingX: overrides?.isScalingX ?? this.isScalingX(),
|
|
isScalingY: overrides?.isScalingY ?? this.isScalingY(),
|
|
keepAspectRatio: overrides?.keepAspectRatio ?? this.keepAspectRatio,
|
|
scrollingStep: overrides?.scrollingStep ?? this.scrollingStep
|
|
};
|
|
}
|
|
};
|
|
__decorateClass([
|
|
ActionOnSet9({
|
|
newValue(enabled) {
|
|
this.onEnabledChange(enabled);
|
|
}
|
|
}),
|
|
Property67
|
|
], Zoom.prototype, "enabled", 2);
|
|
__decorateClass([
|
|
ActionOnSet9({
|
|
changeValue(newValue) {
|
|
this.updateAxisCursor({ enableAxisDragging: newValue });
|
|
}
|
|
}),
|
|
Property67
|
|
], Zoom.prototype, "enableAxisDragging", 2);
|
|
__decorateClass([
|
|
ActionOnSet9({
|
|
changeValue(newValue) {
|
|
this.updateAxisCursor({ enableAxisScrolling: newValue });
|
|
}
|
|
}),
|
|
Property67
|
|
], Zoom.prototype, "enableAxisScrolling", 2);
|
|
__decorateClass([
|
|
Property67
|
|
], Zoom.prototype, "enableDoubleClickToReset", 2);
|
|
__decorateClass([
|
|
ActionOnSet9({
|
|
changeValue(newValue) {
|
|
this.ctx.zoomManager.setIndependentAxes(Boolean(newValue));
|
|
}
|
|
}),
|
|
Property67
|
|
], Zoom.prototype, "enableIndependentAxes", 2);
|
|
__decorateClass([
|
|
Property67
|
|
], Zoom.prototype, "enablePanning", 2);
|
|
__decorateClass([
|
|
Property67
|
|
], Zoom.prototype, "enableScrolling", 2);
|
|
__decorateClass([
|
|
Property67
|
|
], Zoom.prototype, "enableSelecting", 2);
|
|
__decorateClass([
|
|
Property67
|
|
], Zoom.prototype, "enableTwoFingerZoom", 2);
|
|
__decorateClass([
|
|
Property67
|
|
], Zoom.prototype, "panKey", 2);
|
|
__decorateClass([
|
|
Property67
|
|
], Zoom.prototype, "axes", 2);
|
|
__decorateClass([
|
|
Property67
|
|
], Zoom.prototype, "scrollingStep", 2);
|
|
__decorateClass([
|
|
Property67
|
|
], Zoom.prototype, "keepAspectRatio", 2);
|
|
__decorateClass([
|
|
Property67
|
|
], Zoom.prototype, "minVisibleItems", 2);
|
|
__decorateClass([
|
|
Property67
|
|
], Zoom.prototype, "anchorPointX", 2);
|
|
__decorateClass([
|
|
Property67
|
|
], Zoom.prototype, "anchorPointY", 2);
|
|
__decorateClass([
|
|
Property67
|
|
], Zoom.prototype, "autoScaling", 2);
|
|
__decorateClass([
|
|
ActionOnSet9({
|
|
changeValue(newValue) {
|
|
this.updateAxisCursor({ axisDraggingMode: newValue });
|
|
}
|
|
}),
|
|
Property67
|
|
], Zoom.prototype, "axisDraggingMode", 2);
|
|
__decorateClass([
|
|
Property67
|
|
], Zoom.prototype, "buttons", 2);
|
|
__decorateClass([
|
|
Property67
|
|
], Zoom.prototype, "onDataChange", 2);
|
|
__decorateClass([
|
|
ProxyProperty3("panner.deceleration"),
|
|
Property67
|
|
], Zoom.prototype, "deceleration", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/features/zoom/zoomModule.ts
|
|
var zoomAnchorPoint = union4("pointer", "start", "middle", "end");
|
|
var ZoomModule = {
|
|
type: "plugin",
|
|
name: "zoom",
|
|
enterprise: true,
|
|
version: VERSION27,
|
|
options: {
|
|
enabled: boolean15,
|
|
enableAxisDragging: boolean15,
|
|
enableAxisScrolling: boolean15,
|
|
enableDoubleClickToReset: boolean15,
|
|
enablePanning: boolean15,
|
|
enableScrolling: boolean15,
|
|
enableSelecting: boolean15,
|
|
enableTwoFingerZoom: boolean15,
|
|
keepAspectRatio: boolean15,
|
|
anchorPointX: zoomAnchorPoint,
|
|
anchorPointY: zoomAnchorPoint,
|
|
axisDraggingMode: union4("pan", "zoom"),
|
|
axes: union4("x", "y", "xy"),
|
|
deceleration: or2(union4("off", "short", "long"), ratio6),
|
|
minVisibleItems: positiveNumber7,
|
|
panKey: union4("alt", "ctrl", "meta", "shift"),
|
|
scrollingStep: ratio6,
|
|
autoScaling: {
|
|
enabled: boolean15,
|
|
padding: ratio6
|
|
},
|
|
onDataChange: {
|
|
strategy: strictUnion2()("reset", "preserveDomain", "preserveRatios"),
|
|
stickToEnd: boolean15
|
|
},
|
|
buttons: {
|
|
enabled: boolean15,
|
|
buttons: arrayOfDefs4(
|
|
{
|
|
...toolbarButtonOptionsDefs2,
|
|
value: union4("reset", "zoom-in", "zoom-out", "pan-left", "pan-right", "pan-start", "pan-end"),
|
|
section: string9
|
|
},
|
|
"zoom button options array"
|
|
),
|
|
visible: union4("always", "zoomed", "hover")
|
|
}
|
|
},
|
|
themeTemplate: {
|
|
enabled: false,
|
|
enableAxisDragging: true,
|
|
enableAxisScrolling: true,
|
|
enableDoubleClickToReset: true,
|
|
enablePanning: true,
|
|
enableScrolling: true,
|
|
enableSelecting: false,
|
|
enableTwoFingerZoom: true,
|
|
deceleration: "short",
|
|
minVisibleItems: 2,
|
|
panKey: "alt",
|
|
scrollingStep: 0.1,
|
|
autoScaling: {
|
|
enabled: {
|
|
$and: [
|
|
{ $eq: [{ $path: "../axes" }, "x"] },
|
|
{ $not: { $eq: [{ $path: "/series/0/direction" }, "horizontal"] } }
|
|
]
|
|
},
|
|
padding: 0.05
|
|
},
|
|
onDataChange: {
|
|
strategy: "preserveDomain",
|
|
stickToEnd: false
|
|
// TODO(olegat): change default to 'true'
|
|
},
|
|
anchorPointX: "end",
|
|
anchorPointY: "middle",
|
|
axes: "x",
|
|
buttons: {
|
|
enabled: { $path: "../enabled" },
|
|
visible: "hover",
|
|
buttons: {
|
|
$shallowSimple: [
|
|
{ icon: "zoom-out", value: "zoom-out", section: "scale" },
|
|
{ icon: "zoom-in", value: "zoom-in", section: "scale" },
|
|
{ icon: "pan-left", value: "pan-left", section: "pan" },
|
|
{ icon: "pan-right", value: "pan-right", section: "pan" },
|
|
{ icon: "reset", value: "reset", section: "reset" }
|
|
]
|
|
}
|
|
}
|
|
},
|
|
create: (ctx) => new Zoom(ctx)
|
|
};
|
|
ZoomModule.options.enableIndependentAxes = undocumented8(boolean15);
|
|
ZoomModule.options.buttons.anchorPointX = undocumented8(zoomAnchorPoint);
|
|
ZoomModule.options.buttons.anchorPointY = undocumented8(zoomAnchorPoint);
|
|
|
|
// packages/ag-charts-enterprise/src/gradient-legend/gradientLegendModule.ts
|
|
import { VERSION as VERSION28 } from "ag-charts-community";
|
|
import {
|
|
FILL_GRADIENT_BLANK_DEFAULTS,
|
|
FILL_IMAGE_BLANK_DEFAULTS,
|
|
FILL_PATTERN_BLANK_DEFAULTS,
|
|
LEGEND_CONTAINER_THEME,
|
|
and as and2,
|
|
array as array2,
|
|
boolean as boolean16,
|
|
borderOptionsDef,
|
|
callback as callback3,
|
|
colorUnion,
|
|
fontOptionsDef as fontOptionsDef2,
|
|
greaterThan,
|
|
legendPositionValidator,
|
|
lessThan,
|
|
number as number7,
|
|
numberFormatValidator as numberFormatValidator2,
|
|
padding,
|
|
positiveNumber as positiveNumber8,
|
|
ratio as ratio7
|
|
} from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/gradient-legend/gradientLegend.ts
|
|
import {
|
|
_ModuleSupport as _ModuleSupport135
|
|
} from "ag-charts-community";
|
|
import {
|
|
BaseProperties as BaseProperties29,
|
|
Border,
|
|
CleanupRegistry as CleanupRegistry7,
|
|
Property as Property68,
|
|
ProxyProperty as ProxyProperty4,
|
|
ZIndexMap as ZIndexMap13,
|
|
createId as createId6,
|
|
expandLegendPosition
|
|
} from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/gradient-legend/axisTicks.ts
|
|
import { _ModuleSupport as _ModuleSupport134 } from "ag-charts-community";
|
|
import {
|
|
ZIndexMap as ZIndexMap12,
|
|
cachedTextMeasurer as cachedTextMeasurer4,
|
|
countFractionDigits as countFractionDigits2,
|
|
createId as createId5,
|
|
createIdsGenerator,
|
|
estimateTickCount,
|
|
findMinMax as findMinMax5,
|
|
findRangeExtent,
|
|
isArray,
|
|
measureTextSegments,
|
|
toPlainText as toPlainText4,
|
|
toTextString
|
|
} from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/utils/formatter.ts
|
|
import { callWithContext as callWithContext2 } from "ag-charts-core";
|
|
function formatWithContext(ctx, formatter, params) {
|
|
return callWithContext2(ctx.chartService, formatter, params);
|
|
}
|
|
|
|
// packages/ag-charts-enterprise/src/gradient-legend/axisTicks.ts
|
|
var { AxisInterval: AxisInterval2, AxisLabel: AxisLabel2, LinearScale: LinearScale3, BBox: BBox15, TranslatableGroup: TranslatableGroup4, Selection: Selection4, Text: Text2 } = _ModuleSupport134;
|
|
var _AxisTicks = class _AxisTicks {
|
|
constructor(ctx, dataProvider) {
|
|
this.ctx = ctx;
|
|
this.dataProvider = dataProvider;
|
|
this.id = createId5(this);
|
|
this.axisGroup = new TranslatableGroup4({ name: `${this.id}-AxisTicks`, zIndex: ZIndexMap12.AXIS });
|
|
this.labelSelection = Selection4.select(this.axisGroup, Text2);
|
|
this.interval = new AxisInterval2();
|
|
this.label = new AxisLabel2();
|
|
this.scale = new LinearScale3();
|
|
this.placement = "bottom";
|
|
this.translationX = 0;
|
|
this.translationY = 0;
|
|
this.padding = 0;
|
|
}
|
|
get horizontal() {
|
|
return this.placement.startsWith("top") || this.placement.startsWith("bottom");
|
|
}
|
|
attachAxis(axisNode) {
|
|
axisNode.appendChild(this.axisGroup);
|
|
}
|
|
calculateLayout() {
|
|
const { placement, translationX, translationY, horizontal, label } = this;
|
|
function unreachable(_a) {
|
|
return void 0;
|
|
}
|
|
let textBaseline;
|
|
let textAlign;
|
|
switch (placement) {
|
|
case "top":
|
|
case "top-right":
|
|
case "top-left":
|
|
textBaseline = "bottom";
|
|
textAlign = "center";
|
|
label.mirrored = false;
|
|
label.parallel = true;
|
|
break;
|
|
case "bottom":
|
|
case "bottom-right":
|
|
case "bottom-left":
|
|
textBaseline = "top";
|
|
textAlign = "center";
|
|
label.mirrored = false;
|
|
label.parallel = true;
|
|
break;
|
|
case "right":
|
|
case "right-top":
|
|
case "right-bottom":
|
|
case "left":
|
|
case "left-top":
|
|
case "left-bottom":
|
|
textBaseline = "middle";
|
|
textAlign = "left";
|
|
label.mirrored = true;
|
|
label.parallel = false;
|
|
break;
|
|
default:
|
|
unreachable(placement);
|
|
}
|
|
const boxes = [];
|
|
const tickGenerationResult = this.generateTicks();
|
|
const { ticks } = tickGenerationResult;
|
|
this.labelSelection.update(ticks, void 0, (datum) => datum.tickId);
|
|
this.axisGroup.setProperties({ translationX, translationY });
|
|
this.labelSelection.each((node, datum) => {
|
|
node.fontFamily = label.fontFamily;
|
|
node.fontSize = label.fontSize;
|
|
node.fontStyle = label.fontStyle;
|
|
node.fontWeight = label.fontWeight;
|
|
node.fill = label.color;
|
|
node.textBaseline = textBaseline;
|
|
node.textAlign = textAlign;
|
|
node.text = datum.tickLabel;
|
|
node.x = horizontal ? datum.translation : 0;
|
|
node.y = horizontal ? 0 : datum.translation;
|
|
boxes.push(node.getBBox());
|
|
});
|
|
return boxes.length > 0 ? BBox15.merge(boxes).translate(translationX, translationY) : void 0;
|
|
}
|
|
tickFormatter(domain, _ticks, _primary, fractionDigits) {
|
|
const { ctx } = this;
|
|
const { formatManager } = ctx;
|
|
const boundSeries = this.dataProvider.data.flatMap((d) => d.series);
|
|
return (value, index) => {
|
|
const formatParams = {
|
|
type: "number",
|
|
value,
|
|
datum: void 0,
|
|
seriesId: void 0,
|
|
legendItemName: void 0,
|
|
key: void 0,
|
|
source: "gradient-legend",
|
|
property: "color",
|
|
domain,
|
|
boundSeries,
|
|
fractionDigits,
|
|
visibleDomain: void 0
|
|
};
|
|
return this.label.formatValue((fn, params) => formatWithContext(ctx, fn, params), formatParams, index) ?? formatManager.format((fn, params) => formatWithContext(ctx, fn, params), formatParams) ?? formatManager.defaultFormat(formatParams);
|
|
};
|
|
}
|
|
inRange(x, tolerance = 1e-3) {
|
|
const [min, max] = findMinMax5(this.scale.range);
|
|
return x >= min - tolerance && x <= max + tolerance;
|
|
}
|
|
generateTicks() {
|
|
const { minSpacing, maxSpacing } = this.interval;
|
|
const { maxTickCount, minTickCount, tickCount } = estimateTickCount(
|
|
findRangeExtent(this.scale.range),
|
|
1,
|
|
minSpacing,
|
|
maxSpacing,
|
|
_AxisTicks.DefaultTickCount,
|
|
_AxisTicks.DefaultMinSpacing
|
|
);
|
|
const tickData = this.getTicksData({
|
|
nice: [true, true],
|
|
interval: this.interval.step,
|
|
tickCount,
|
|
minTickCount,
|
|
maxTickCount
|
|
});
|
|
if (this.placement === "bottom" || this.placement === "top") {
|
|
const measurer3 = cachedTextMeasurer4(this.label);
|
|
const { domain } = this.scale;
|
|
const reversed = domain[0] > domain[1];
|
|
const direction = reversed ? -1 : 1;
|
|
let lastTickPosition = -Infinity * direction;
|
|
tickData.ticks = tickData.ticks.filter((data) => {
|
|
if (Math.sign(data.translation - lastTickPosition) !== direction)
|
|
return false;
|
|
const { width: labelWidth } = isArray(data.tickLabel) ? measureTextSegments(data.tickLabel, this.label) : measurer3.measureLines(toTextString(data.tickLabel));
|
|
lastTickPosition = data.translation + labelWidth * direction;
|
|
return true;
|
|
});
|
|
}
|
|
return tickData;
|
|
}
|
|
getTicksData(tickParams) {
|
|
const ticks = [];
|
|
const domain = tickParams.nice ? this.scale.niceDomain(tickParams) : this.scale.domain;
|
|
const rawTicks = this.scale.ticks(tickParams, domain)?.ticks ?? [];
|
|
const fractionDigits = rawTicks.reduce((max, tick) => Math.max(max, countFractionDigits2(tick)), 0);
|
|
const idGenerator = createIdsGenerator();
|
|
const tickFormatter = this.tickFormatter(domain, rawTicks, false, fractionDigits);
|
|
for (let index = 0; index < rawTicks.length; index++) {
|
|
const tick = rawTicks[index];
|
|
const translation = this.scale.convert(tick);
|
|
if (!this.inRange(translation))
|
|
continue;
|
|
const tickLabel = tickFormatter(tick, index);
|
|
if (tickLabel == null || tickLabel === "")
|
|
continue;
|
|
const tickId = idGenerator(toPlainText4(tickLabel));
|
|
ticks.push({ tick, tickId, tickLabel, translation });
|
|
}
|
|
return { rawTicks, fractionDigits, ticks };
|
|
}
|
|
};
|
|
_AxisTicks.className = "AxisTicks";
|
|
_AxisTicks.DefaultTickCount = 5;
|
|
_AxisTicks.DefaultMinSpacing = 10;
|
|
var AxisTicks = _AxisTicks;
|
|
|
|
// packages/ag-charts-enterprise/src/gradient-legend/gradientLegend.ts
|
|
var { LayoutElement: LayoutElement6, Group: Group9, Rect: Rect6, Marker: Marker2, TranslatableGroup: TranslatableGroup5, BBox: BBox16 } = _ModuleSupport135;
|
|
var GradientBar = class extends BaseProperties29 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.thickness = 16;
|
|
this.preferredLength = 100;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property68
|
|
], GradientBar.prototype, "thickness", 2);
|
|
__decorateClass([
|
|
Property68
|
|
], GradientBar.prototype, "preferredLength", 2);
|
|
var GradientLegendScale = class extends BaseProperties29 {
|
|
constructor(axisTicks) {
|
|
super();
|
|
this.axisTicks = axisTicks;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
ProxyProperty4("axisTicks.label")
|
|
], GradientLegendScale.prototype, "label", 2);
|
|
__decorateClass([
|
|
ProxyProperty4("axisTicks.interval")
|
|
], GradientLegendScale.prototype, "interval", 2);
|
|
__decorateClass([
|
|
ProxyProperty4("axisTicks.padding")
|
|
], GradientLegendScale.prototype, "padding", 2);
|
|
var GradientLegend = class extends BaseProperties29 {
|
|
constructor(ctx) {
|
|
super();
|
|
this.ctx = ctx;
|
|
this.id = createId6(this);
|
|
this.legendGroup = new TranslatableGroup5({ name: "legend", zIndex: ZIndexMap13.LEGEND });
|
|
this.containerNode = this.legendGroup.appendChild(new Rect6({ name: "legend-container" }));
|
|
this.gradientRect = new Rect6();
|
|
this.arrow = new Marker2({ shape: "triangle" });
|
|
this.ticksGroup = new Group9({ name: "legend-axis-group" });
|
|
this.cleanup = new CleanupRegistry7();
|
|
this.enabled = false;
|
|
this.position = "bottom";
|
|
this.reverseOrder = false;
|
|
this.gradient = new GradientBar();
|
|
this.spacing = 20;
|
|
this.border = new Border(this.containerNode);
|
|
this.cornerRadius = 0;
|
|
this.fillOpacity = 1;
|
|
this.padding = 4;
|
|
this.data = [];
|
|
this.highlightManager = ctx.highlightManager;
|
|
this.axisTicks = new AxisTicks(ctx, this);
|
|
this.axisTicks.attachAxis(this.ticksGroup);
|
|
this.scale = new GradientLegendScale(this.axisTicks);
|
|
this.legendGroup.append([this.gradientRect, this.arrow, this.ticksGroup]);
|
|
this.cleanup.register(
|
|
ctx.eventsHub.on("highlight:change", () => this.onChartHoverChange()),
|
|
ctx.layoutManager.registerElement(LayoutElement6.Legend, (e) => this.onStartLayout(e)),
|
|
() => this.legendGroup.remove()
|
|
);
|
|
}
|
|
isVertical() {
|
|
const { placement } = expandLegendPosition(this.position);
|
|
return placement.startsWith("right") || placement.startsWith("left");
|
|
}
|
|
destroy() {
|
|
this.cleanup.flush();
|
|
}
|
|
attachLegend(scene) {
|
|
scene.appendChild(this.legendGroup);
|
|
}
|
|
onStartLayout({ layoutBox }) {
|
|
const [data] = this.data;
|
|
if (!this.enabled || !data?.enabled || data.legendType !== "gradient") {
|
|
this.legendGroup.visible = false;
|
|
return;
|
|
}
|
|
const { colorRange } = this.normalizeColorArrays(data);
|
|
const { strokeWidth, padding: padding2 } = this.getContainerStyles();
|
|
const gradientRectBBox = this.updateGradientRect(layoutBox, colorRange);
|
|
const axisBBox = this.updateAxis(data, gradientRectBBox) ?? new BBox16(0, 0, 0, 0);
|
|
const legendBBox = BBox16.merge([gradientRectBBox, axisBBox]);
|
|
legendBBox.grow(padding2).grow(strokeWidth);
|
|
const { left, top } = this.getMeasurements(layoutBox, legendBBox);
|
|
this.updateContainer(legendBBox);
|
|
this.updateArrow();
|
|
this.legendGroup.visible = true;
|
|
this.legendGroup.translationX = left;
|
|
this.legendGroup.translationY = top;
|
|
}
|
|
normalizeColorArrays(data) {
|
|
let colorDomain = data.colorDomain.slice();
|
|
const colorRange = data.colorRange.slice();
|
|
if (colorDomain.length === colorRange.length) {
|
|
return { colorDomain, colorRange };
|
|
}
|
|
if (colorDomain.length > colorRange.length) {
|
|
colorRange.splice(colorDomain.length);
|
|
}
|
|
const [d0, d1] = colorDomain;
|
|
const count = colorRange.length;
|
|
colorDomain = colorRange.map((_, i) => {
|
|
if (i === 0) {
|
|
return d0;
|
|
} else if (i === count - 1) {
|
|
return d1;
|
|
}
|
|
return d0 + (d1 - d0) * i / (count - 1);
|
|
});
|
|
return { colorDomain, colorRange };
|
|
}
|
|
updateGradientRect(shrinkRect, colorRange) {
|
|
const { gradientRect, gradient } = this;
|
|
const { preferredLength, thickness } = gradient;
|
|
const gradientRectBBox = new BBox16(0, 0, 0, 0);
|
|
const colorCount = Math.max(colorRange.length - 1, 1);
|
|
let angle;
|
|
if (this.isVertical()) {
|
|
angle = 0;
|
|
gradientRectBBox.width = thickness;
|
|
gradientRectBBox.height = Math.min(shrinkRect.height, preferredLength);
|
|
} else {
|
|
angle = 90;
|
|
gradientRectBBox.width = Math.min(shrinkRect.width, preferredLength);
|
|
gradientRectBBox.height = thickness;
|
|
}
|
|
gradientRect.x = gradientRectBBox.x;
|
|
gradientRect.y = gradientRectBBox.y;
|
|
gradientRect.width = gradientRectBBox.width;
|
|
gradientRect.height = gradientRectBBox.height;
|
|
gradientRect.fill = {
|
|
type: "gradient",
|
|
gradient: "linear",
|
|
colorSpace: "oklch",
|
|
colorStops: colorRange.map((color7, i) => ({
|
|
stop: i / colorCount,
|
|
color: color7
|
|
})),
|
|
rotation: angle
|
|
};
|
|
return gradientRectBBox;
|
|
}
|
|
updateAxis(data, gradientRectBBox) {
|
|
const { axisTicks, gradient, scale } = this;
|
|
const { placement } = expandLegendPosition(this.position);
|
|
const vertical = this.isVertical();
|
|
const positiveAxis = this.reverseOrder !== vertical;
|
|
axisTicks.placement = placement;
|
|
const offset = gradient.thickness + (scale.padding ?? 0);
|
|
axisTicks.translationX = vertical ? offset : gradientRectBBox.x;
|
|
axisTicks.translationY = vertical ? gradientRectBBox.y : offset;
|
|
axisTicks.scale.domain = positiveAxis ? data.colorDomain.slice().reverse() : data.colorDomain;
|
|
axisTicks.scale.range = vertical ? [gradientRectBBox.x, gradientRectBBox.height] : [gradientRectBBox.y, gradientRectBBox.width];
|
|
return axisTicks.calculateLayout();
|
|
}
|
|
updateContainer(bbox) {
|
|
const containerStyles = this.getContainerStyles();
|
|
this.containerNode.setStyleProperties(containerStyles);
|
|
this.containerNode.cornerRadius = containerStyles.cornerRadius;
|
|
this.containerNode.x = bbox.x;
|
|
this.containerNode.y = bbox.y;
|
|
this.containerNode.width = bbox.width;
|
|
this.containerNode.height = bbox.height;
|
|
}
|
|
updateArrow() {
|
|
const highlighted = this.highlightManager.getActiveHighlight();
|
|
const { arrow } = this;
|
|
if (highlighted?.colorValue == null) {
|
|
arrow.visible = false;
|
|
return;
|
|
}
|
|
const { scale, label } = this.axisTicks;
|
|
const size = label.fontSize ?? 0;
|
|
const t = scale.convert(highlighted.colorValue);
|
|
let { x, y } = this.gradientRect;
|
|
let rotation = Math.PI;
|
|
if (this.isVertical()) {
|
|
x -= size / 2;
|
|
y += t;
|
|
rotation /= 2;
|
|
} else {
|
|
x += t;
|
|
y -= size / 2;
|
|
}
|
|
arrow.visible = true;
|
|
arrow.fill = label.color;
|
|
arrow.rotation = rotation;
|
|
arrow.size = size;
|
|
arrow.translationX = x;
|
|
arrow.translationY = y;
|
|
}
|
|
getMeasurements(shrinkRect, legendBBox) {
|
|
const unreachable = (_a) => {
|
|
return void 0;
|
|
};
|
|
let { x: left, y: top } = shrinkRect;
|
|
const { width, height } = legendBBox;
|
|
const { placement, floating, xOffset, yOffset } = expandLegendPosition(this.position);
|
|
const containerStyles = this.getContainerStyles();
|
|
left += containerStyles.strokeWidth + containerStyles.padding.left;
|
|
top += containerStyles.strokeWidth + containerStyles.padding.top;
|
|
switch (placement) {
|
|
case "left":
|
|
top += shrinkRect.height / 2 - height / 2;
|
|
break;
|
|
case "right":
|
|
left += shrinkRect.width - width;
|
|
top += shrinkRect.height / 2 - height / 2;
|
|
break;
|
|
case "top":
|
|
left += shrinkRect.width / 2 - width / 2;
|
|
break;
|
|
case "bottom":
|
|
left += shrinkRect.width / 2 - width / 2;
|
|
top += shrinkRect.height - height;
|
|
break;
|
|
case "right-top":
|
|
case "top-right":
|
|
left += shrinkRect.width - width;
|
|
break;
|
|
case "right-bottom":
|
|
case "bottom-right":
|
|
left += shrinkRect.width - width;
|
|
top += shrinkRect.height - height;
|
|
break;
|
|
case "left-bottom":
|
|
case "bottom-left":
|
|
top += shrinkRect.height - height;
|
|
break;
|
|
case "left-top":
|
|
case "top-left":
|
|
break;
|
|
default:
|
|
unreachable(placement);
|
|
}
|
|
if (!floating) {
|
|
switch (placement) {
|
|
case "left":
|
|
case "left-top":
|
|
case "left-bottom":
|
|
shrinkRect.shrink(width + this.spacing, "left");
|
|
break;
|
|
case "right":
|
|
case "right-top":
|
|
case "right-bottom":
|
|
shrinkRect.shrink(width + this.spacing, "right");
|
|
break;
|
|
case "top":
|
|
case "top-left":
|
|
case "top-right":
|
|
shrinkRect.shrink(height + this.spacing, "top");
|
|
break;
|
|
case "bottom":
|
|
case "bottom-left":
|
|
case "bottom-right":
|
|
shrinkRect.shrink(height + this.spacing, "bottom");
|
|
break;
|
|
default:
|
|
unreachable(placement);
|
|
}
|
|
}
|
|
left += xOffset;
|
|
top += yOffset;
|
|
return { top, left };
|
|
}
|
|
getContainerStyles() {
|
|
const { stroke: stroke3, strokeOpacity, strokeWidth } = this.border;
|
|
const { cornerRadius, fill, fillOpacity, padding: padding2 } = this;
|
|
const isPaddingNumber = typeof padding2 === "number";
|
|
return {
|
|
cornerRadius,
|
|
fill,
|
|
fillOpacity,
|
|
padding: {
|
|
top: isPaddingNumber ? padding2 : padding2.top ?? 0,
|
|
right: isPaddingNumber ? padding2 : padding2.right ?? 0,
|
|
bottom: isPaddingNumber ? padding2 : padding2.bottom ?? 0,
|
|
left: isPaddingNumber ? padding2 : padding2.left ?? 0
|
|
},
|
|
stroke: stroke3,
|
|
strokeOpacity,
|
|
strokeWidth: this.border.enabled ? strokeWidth : 0
|
|
};
|
|
}
|
|
onChartHoverChange() {
|
|
if (!this.enabled)
|
|
return;
|
|
this.updateArrow();
|
|
}
|
|
};
|
|
GradientLegend.className = "GradientLegend";
|
|
__decorateClass([
|
|
Property68
|
|
], GradientLegend.prototype, "enabled", 2);
|
|
__decorateClass([
|
|
Property68
|
|
], GradientLegend.prototype, "position", 2);
|
|
__decorateClass([
|
|
Property68
|
|
], GradientLegend.prototype, "reverseOrder", 2);
|
|
__decorateClass([
|
|
Property68
|
|
], GradientLegend.prototype, "gradient", 2);
|
|
__decorateClass([
|
|
Property68
|
|
], GradientLegend.prototype, "spacing", 2);
|
|
__decorateClass([
|
|
Property68
|
|
], GradientLegend.prototype, "border", 2);
|
|
__decorateClass([
|
|
Property68
|
|
], GradientLegend.prototype, "cornerRadius", 2);
|
|
__decorateClass([
|
|
Property68
|
|
], GradientLegend.prototype, "fill", 2);
|
|
__decorateClass([
|
|
Property68
|
|
], GradientLegend.prototype, "fillOpacity", 2);
|
|
__decorateClass([
|
|
Property68
|
|
], GradientLegend.prototype, "padding", 2);
|
|
__decorateClass([
|
|
Property68
|
|
], GradientLegend.prototype, "scale", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/gradient-legend/gradientLegendModule.ts
|
|
var GradientLegendModule = {
|
|
type: "plugin",
|
|
name: "gradientLegend",
|
|
enterprise: true,
|
|
version: VERSION28,
|
|
// removable: 'standalone-only',
|
|
options: {
|
|
enabled: boolean16,
|
|
position: legendPositionValidator,
|
|
spacing: positiveNumber8,
|
|
reverseOrder: boolean16,
|
|
border: borderOptionsDef,
|
|
cornerRadius: number7,
|
|
padding,
|
|
fill: colorUnion,
|
|
fillOpacity: ratio7,
|
|
gradient: {
|
|
preferredLength: positiveNumber8,
|
|
thickness: positiveNumber8
|
|
},
|
|
scale: {
|
|
label: {
|
|
...fontOptionsDef2,
|
|
minSpacing: positiveNumber8,
|
|
format: numberFormatValidator2,
|
|
formatter: callback3
|
|
},
|
|
padding: positiveNumber8,
|
|
interval: {
|
|
step: number7,
|
|
values: array2,
|
|
minSpacing: and2(positiveNumber8, lessThan("maxSpacing")),
|
|
maxSpacing: and2(positiveNumber8, greaterThan("minSpacing"))
|
|
}
|
|
}
|
|
},
|
|
themeTemplate: {
|
|
...LEGEND_CONTAINER_THEME,
|
|
enabled: false,
|
|
position: "bottom",
|
|
spacing: 20,
|
|
scale: {
|
|
padding: 13,
|
|
label: {
|
|
color: { $ref: "textColor" },
|
|
fontSize: { $ref: "fontSize" },
|
|
fontFamily: { $ref: "fontFamily" },
|
|
fontWeight: { $ref: "fontWeight" },
|
|
minSpacing: 5
|
|
},
|
|
interval: {
|
|
minSpacing: 15
|
|
}
|
|
},
|
|
gradient: {
|
|
preferredLength: 100,
|
|
thickness: 16
|
|
},
|
|
reverseOrder: false,
|
|
fill: {
|
|
$applySwitch: [
|
|
{ $path: "type" },
|
|
{ $ref: "chartBackgroundColour" },
|
|
["gradient", FILL_GRADIENT_BLANK_DEFAULTS],
|
|
["pattern", FILL_PATTERN_BLANK_DEFAULTS],
|
|
["image", FILL_IMAGE_BLANK_DEFAULTS]
|
|
]
|
|
}
|
|
},
|
|
create: (ctx) => {
|
|
const moduleInstance = new GradientLegend(ctx);
|
|
moduleInstance.attachLegend(ctx.scene);
|
|
return moduleInstance;
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/series/chord/chordModule.ts
|
|
import { VERSION as VERSION30 } from "ag-charts-community";
|
|
import {
|
|
FILL_GRADIENT_LINEAR_DEFAULTS as FILL_GRADIENT_LINEAR_DEFAULTS4,
|
|
FILL_IMAGE_DEFAULTS as FILL_IMAGE_DEFAULTS6,
|
|
FILL_PATTERN_DEFAULTS as FILL_PATTERN_DEFAULTS4,
|
|
LABEL_BOXING_DEFAULTS as LABEL_BOXING_DEFAULTS5,
|
|
SINGLE_SERIES_HIGHLIGHT_STYLE as SINGLE_SERIES_HIGHLIGHT_STYLE2
|
|
} from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/charts/standaloneChartModule.ts
|
|
import { VERSION as VERSION29, _ModuleSupport as _ModuleSupport137 } from "ag-charts-community";
|
|
|
|
// packages/ag-charts-enterprise/src/charts/standaloneChart.ts
|
|
import { _ModuleSupport as _ModuleSupport136 } from "ag-charts-community";
|
|
var { Chart } = _ModuleSupport136;
|
|
var StandaloneChart = class extends Chart {
|
|
getChartType() {
|
|
return "standalone";
|
|
}
|
|
performLayout(ctx) {
|
|
const { seriesRoot, annotationRoot } = this;
|
|
const seriesRect = ctx.layoutBox.clone().shrink(this.seriesArea.getPadding());
|
|
this.seriesRect = seriesRect;
|
|
this.animationRect = seriesRect;
|
|
for (const group of [seriesRoot, annotationRoot]) {
|
|
group.translationX = Math.floor(seriesRect.x);
|
|
group.translationY = Math.floor(seriesRect.y);
|
|
}
|
|
seriesRoot.visible = this.series[0].visible;
|
|
this.ctx.layoutManager.emitLayoutComplete(ctx, {
|
|
series: { visible: true, rect: seriesRect, paddedRect: ctx.layoutBox }
|
|
});
|
|
}
|
|
getAriaLabel() {
|
|
const seriesType = this.series[0]?.type;
|
|
if (seriesType == null)
|
|
return "";
|
|
const caption = this.getCaptionText();
|
|
switch (seriesType) {
|
|
case "radial-gauge":
|
|
case "linear-gauge": {
|
|
const captions = [];
|
|
if (caption.length !== 0) {
|
|
captions.push(caption);
|
|
}
|
|
for (const series of this.series) {
|
|
captions.push(series.getCaptionText());
|
|
}
|
|
return this.ctx.localeManager.t("ariaAnnounceGaugeChart", { caption: captions.join(". ") });
|
|
}
|
|
case "treemap":
|
|
case "sunburst":
|
|
return this.ctx.localeManager.t("ariaAnnounceHierarchyChart", { caption });
|
|
default: {
|
|
return this.ctx.localeManager.t("ariaAnnounceStandaloneChart", { caption });
|
|
}
|
|
}
|
|
}
|
|
};
|
|
StandaloneChart.className = "StandaloneChart";
|
|
StandaloneChart.type = "standalone";
|
|
|
|
// packages/ag-charts-enterprise/src/charts/standaloneChartModule.ts
|
|
var { standaloneChartOptionsDefs } = _ModuleSupport137;
|
|
var StandaloneChartModule = {
|
|
type: "chart",
|
|
name: "standalone",
|
|
enterprise: true,
|
|
version: VERSION29,
|
|
options: standaloneChartOptionsDefs,
|
|
create(options, resources) {
|
|
return new StandaloneChart(options, resources);
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/series/chord/chordSeries.ts
|
|
import { _ModuleSupport as _ModuleSupport141 } from "ag-charts-community";
|
|
import {
|
|
Logger as Logger15,
|
|
angleBetween as angleBetween2,
|
|
cachedTextMeasurer as cachedTextMeasurer5,
|
|
calcLineHeight as calcLineHeight6,
|
|
evaluateBezier,
|
|
isBetweenAngles,
|
|
mergeDefaults as mergeDefaults10,
|
|
normalizeAngle360 as normalizeAngle3604,
|
|
toPlainText as toPlainText5,
|
|
wrapText as wrapText3
|
|
} from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/series/flow-proportion/flowProportionSeries.ts
|
|
import {
|
|
_ModuleSupport as _ModuleSupport138
|
|
} from "ag-charts-community";
|
|
|
|
// packages/ag-charts-enterprise/src/series/flow-proportion/flowProportionUtil.ts
|
|
import { Logger as Logger14 } from "ag-charts-core";
|
|
function computeNodeGraph(nodes, links, includeCircularReferences) {
|
|
if (!includeCircularReferences) {
|
|
links = removeCircularLinks(links);
|
|
}
|
|
const nodeGraph = /* @__PURE__ */ new Map();
|
|
for (const datum of nodes) {
|
|
const itemId = datum.datumIndex.type === 0 /* Link */ ? `link-${datum.datumIndex.index}` : `node-${datum.datumIndex.index}`;
|
|
nodeGraph.set(datum.id, {
|
|
itemId,
|
|
datum,
|
|
linksBefore: [],
|
|
linksAfter: [],
|
|
maxPathLengthBefore: -1,
|
|
maxPathLengthAfter: -1
|
|
});
|
|
}
|
|
let maxPathLength = 0;
|
|
for (const [id, node] of nodeGraph.entries()) {
|
|
maxPathLength = Math.max(
|
|
maxPathLength,
|
|
computePathLength(nodeGraph, links, node, id, -1, []) + computePathLength(nodeGraph, links, node, id, 1, []) + 1
|
|
);
|
|
}
|
|
return { links, nodeGraph, maxPathLength };
|
|
}
|
|
function findCircularLinks(links, link, into, stack) {
|
|
const stackIndex = stack.indexOf(link);
|
|
if (stackIndex !== -1) {
|
|
for (let i = stackIndex; i < stack.length; i += 1) {
|
|
into.add(stack[i]);
|
|
}
|
|
return;
|
|
}
|
|
stack.push(link);
|
|
const { toNode } = link;
|
|
for (const next of links) {
|
|
if (next.fromNode === toNode) {
|
|
findCircularLinks(links, next, into, stack);
|
|
}
|
|
}
|
|
stack.pop();
|
|
}
|
|
function removeCircularLinks(links) {
|
|
const circularLinks = /* @__PURE__ */ new Set();
|
|
for (const link of links) {
|
|
findCircularLinks(links, link, circularLinks, []);
|
|
}
|
|
if (circularLinks.size !== 0) {
|
|
Logger14.warnOnce("Some links formed circular references. These will be removed from the output.");
|
|
}
|
|
return circularLinks.size === 0 ? links : links.filter((link) => !circularLinks.has(link));
|
|
}
|
|
function computePathLength(nodeGraph, links, node, id, direction, stack) {
|
|
if (stack.includes(id)) {
|
|
return Infinity;
|
|
}
|
|
let maxPathLength = direction === -1 ? node.maxPathLengthBefore : node.maxPathLengthAfter;
|
|
if (maxPathLength === -1) {
|
|
maxPathLength = 0;
|
|
const connectedLinks = direction === -1 ? node.linksBefore : node.linksAfter;
|
|
for (const link of links) {
|
|
const { fromNode, toNode } = link;
|
|
const linkId = direction === -1 ? toNode.id : fromNode.id;
|
|
const nextNodeId = direction === -1 ? fromNode.id : toNode.id;
|
|
const nextNode = id === linkId ? nodeGraph.get(nextNodeId) : void 0;
|
|
if (nextNode == null)
|
|
continue;
|
|
connectedLinks.push({ node: nextNode, link });
|
|
stack?.push(id);
|
|
maxPathLength = Math.max(
|
|
maxPathLength,
|
|
computePathLength(nodeGraph, links, nextNode, nextNodeId, direction, stack) + 1
|
|
);
|
|
stack?.pop();
|
|
}
|
|
if (direction === -1) {
|
|
node.maxPathLengthBefore = maxPathLength;
|
|
} else {
|
|
node.maxPathLengthAfter = maxPathLength;
|
|
}
|
|
}
|
|
return maxPathLength;
|
|
}
|
|
|
|
// packages/ag-charts-enterprise/src/series/flow-proportion/flowProportionSeries.ts
|
|
var {
|
|
findNodeDatumInArray,
|
|
keyProperty: keyProperty7,
|
|
valueProperty: valueProperty9,
|
|
DataController,
|
|
Group: Group10,
|
|
HighlightState: HighlightState4,
|
|
Selection: Selection5,
|
|
Series,
|
|
TransformableText
|
|
} = _ModuleSupport138;
|
|
var FlowProportionSeriesNodeEvent = class extends _ModuleSupport138.SeriesNodeEvent {
|
|
constructor(type, nativeEvent, datum, series) {
|
|
super(type, nativeEvent, datum, series);
|
|
const { datumIndex } = datum;
|
|
const nodeDatum = series.contextNodeData?.nodeData.find(
|
|
(d) => d.datumIndex.type === datumIndex.type && d.datumIndex.index === datumIndex.index
|
|
);
|
|
this.size = nodeDatum?.size;
|
|
this.label = nodeDatum?.type === 1 /* Node */ ? nodeDatum?.label : void 0;
|
|
}
|
|
};
|
|
var FlowProportionSeries = class extends Series {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.NodeEvent = FlowProportionSeriesNodeEvent;
|
|
this.nodeCount = 0;
|
|
this.linkCount = 0;
|
|
this.linksDataModel = void 0;
|
|
this.linksProcessedData = void 0;
|
|
this.nodesDataModel = void 0;
|
|
this.nodesProcessedData = void 0;
|
|
this.processedNodes = /* @__PURE__ */ new Map();
|
|
this.linkGroup = this.contentGroup.appendChild(new Group10({ name: "linkGroup" }));
|
|
this.nodeGroup = this.contentGroup.appendChild(new Group10({ name: "nodeGroup" }));
|
|
this.focusLinkGroup = this.highlightGroup.appendChild(new Group10({ name: "linkGroup" }));
|
|
this.focusNodeGroup = this.highlightGroup.appendChild(new Group10({ name: "nodeGroup" }));
|
|
this.highlightLinkGroup = this.highlightGroup.appendChild(new Group10({ name: "linkGroup" }));
|
|
this.labelSelection = Selection5.select(
|
|
this.labelGroup,
|
|
TransformableText
|
|
);
|
|
this.linkSelection = Selection5.select(
|
|
this.linkGroup,
|
|
() => this.linkFactory()
|
|
);
|
|
this.nodeSelection = Selection5.select(
|
|
this.nodeGroup,
|
|
() => this.nodeFactory()
|
|
);
|
|
this.focusLinkSelection = Selection5.select(
|
|
this.focusLinkGroup,
|
|
() => this.linkFactory()
|
|
);
|
|
this.focusNodeSelection = Selection5.select(
|
|
this.focusNodeGroup,
|
|
() => this.nodeFactory()
|
|
);
|
|
this.highlightLinkSelection = Selection5.select(
|
|
this.highlightLinkGroup,
|
|
() => this.linkFactory()
|
|
);
|
|
this.highlightNodeSelection = Selection5.select(
|
|
this.highlightNodeGroup,
|
|
() => this.nodeFactory()
|
|
);
|
|
}
|
|
get nodes() {
|
|
return this.properties.nodes;
|
|
}
|
|
async processData(dataController) {
|
|
const { data, nodes } = this;
|
|
if (data == null)
|
|
return;
|
|
const { fromKey, toKey, sizeKey, idKey, labelKey } = this.properties;
|
|
const nodesDataController = new DataController(
|
|
"standalone",
|
|
dataController.suppressFieldDotNotation,
|
|
this.ctx.eventsHub
|
|
);
|
|
const nodesDataModelPromise = nodes == null ? null : nodesDataController.request(
|
|
this.id,
|
|
_ModuleSupport138.DataSet.wrap(nodes) ?? _ModuleSupport138.DataSet.empty(),
|
|
{
|
|
props: [
|
|
keyProperty7(idKey, void 0, { id: "idValue", includeProperty: false }),
|
|
...labelKey == null ? [] : [valueProperty9(labelKey, void 0, { id: "labelValue", includeProperty: false })]
|
|
],
|
|
groupByKeys: true
|
|
}
|
|
);
|
|
const linksDataModelPromise = dataController.request(this.id, data, {
|
|
props: [
|
|
valueProperty9(fromKey, void 0, { id: "fromValue", includeProperty: false }),
|
|
valueProperty9(toKey, void 0, { id: "toValue", includeProperty: false }),
|
|
...sizeKey == null ? [] : [
|
|
valueProperty9(sizeKey, void 0, {
|
|
id: "sizeValue",
|
|
includeProperty: false,
|
|
missingValue: 0
|
|
})
|
|
]
|
|
],
|
|
groupByKeys: false
|
|
});
|
|
if (nodes != null) {
|
|
nodesDataController.execute();
|
|
}
|
|
const [nodesDataModel, linksDataModel] = await Promise.all([
|
|
nodesDataModelPromise ?? Promise.resolve(null),
|
|
linksDataModelPromise
|
|
]);
|
|
this.nodesDataModel = nodesDataModel?.dataModel;
|
|
this.nodesProcessedData = nodesDataModel?.processedData;
|
|
this.linksDataModel = linksDataModel?.dataModel;
|
|
this.linksProcessedData = linksDataModel?.processedData;
|
|
const processedNodes = /* @__PURE__ */ new Map();
|
|
if (nodesDataModel == null) {
|
|
const fromIdValues = linksDataModel.dataModel.resolveColumnById(
|
|
this,
|
|
"fromValue",
|
|
linksDataModel.processedData
|
|
);
|
|
const toIdValues = linksDataModel.dataModel.resolveColumnById(
|
|
this,
|
|
"toValue",
|
|
linksDataModel.processedData
|
|
);
|
|
const createImplicitNode = (id) => {
|
|
const datumIndex = processedNodes.size;
|
|
const label = id;
|
|
return {
|
|
series: this,
|
|
itemId: `node-${datumIndex}`,
|
|
datum: {},
|
|
// Must be a referential object for tooltips
|
|
datumIndex: { type: 1 /* Node */, index: datumIndex },
|
|
type: 1 /* Node */,
|
|
index: datumIndex,
|
|
linksBefore: [],
|
|
linksAfter: [],
|
|
id,
|
|
size: 0,
|
|
label,
|
|
style: this.getNodeStyle(
|
|
{
|
|
datumIndex: { type: 1 /* Node */, index: datumIndex },
|
|
datum: {},
|
|
size: 0,
|
|
label
|
|
},
|
|
datumIndex,
|
|
false
|
|
)
|
|
};
|
|
};
|
|
const linkData = linksDataModel.processedData.dataSources.get(this.id)?.data;
|
|
if (linkData) {
|
|
for (const [datumIndex] of linkData.entries()) {
|
|
const fromId = fromIdValues[datumIndex];
|
|
const toId = toIdValues[datumIndex];
|
|
if (fromId == null || toId == null)
|
|
continue;
|
|
if (!processedNodes.has(fromId)) {
|
|
processedNodes.set(fromId, createImplicitNode(fromId));
|
|
}
|
|
if (!processedNodes.has(toId)) {
|
|
processedNodes.set(toId, createImplicitNode(toId));
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
const nodeIdValues = nodesDataModel.dataModel.resolveColumnById(
|
|
this,
|
|
"idValue",
|
|
nodesDataModel.processedData
|
|
);
|
|
const labelValues = labelKey == null ? void 0 : nodesDataModel.dataModel.resolveColumnById(
|
|
this,
|
|
"labelValue",
|
|
nodesDataModel.processedData
|
|
);
|
|
const nodeData = nodesDataModel.processedData.dataSources.get(this.id)?.data;
|
|
if (nodeData) {
|
|
for (const [datumIndex, datum] of nodeData.entries()) {
|
|
const id = nodeIdValues[datumIndex];
|
|
const label = labelValues?.[datumIndex];
|
|
const nodeDatumIndex = { type: 1 /* Node */, index: datumIndex };
|
|
processedNodes.set(id, {
|
|
series: this,
|
|
itemId: `node-${datumIndex}`,
|
|
datum,
|
|
datumIndex: nodeDatumIndex,
|
|
type: 1 /* Node */,
|
|
index: datumIndex,
|
|
linksBefore: [],
|
|
linksAfter: [],
|
|
id,
|
|
size: 0,
|
|
label,
|
|
style: this.getNodeStyle(
|
|
{ datumIndex: nodeDatumIndex, datum, size: 0, label },
|
|
datumIndex,
|
|
false
|
|
)
|
|
});
|
|
}
|
|
}
|
|
}
|
|
this.processedNodes = processedNodes;
|
|
}
|
|
findNodeDatum(itemId) {
|
|
return findNodeDatumInArray(itemId, this.contextNodeData?.nodeData);
|
|
}
|
|
getNodeGraph(createNode, createLink, { includeCircularReferences }) {
|
|
const { linksDataModel, linksProcessedData } = this;
|
|
if (linksDataModel == null || linksProcessedData == null) {
|
|
const { links: links2, nodeGraph: nodeGraph2, maxPathLength: maxPathLength2 } = computeNodeGraph(
|
|
(/* @__PURE__ */ new Map()).values(),
|
|
[],
|
|
includeCircularReferences
|
|
);
|
|
this.nodeCount = 0;
|
|
this.linkCount = 0;
|
|
return { nodeGraph: nodeGraph2, links: links2, maxPathLength: maxPathLength2 };
|
|
}
|
|
const { sizeKey } = this.properties;
|
|
const fromIdValues = linksDataModel.resolveColumnById(this, "fromValue", linksProcessedData);
|
|
const toIdValues = linksDataModel.resolveColumnById(this, "toValue", linksProcessedData);
|
|
const sizeValues = sizeKey == null ? void 0 : linksDataModel.resolveColumnById(this, "sizeValue", linksProcessedData);
|
|
const nodesById = /* @__PURE__ */ new Map();
|
|
for (const datum of this.processedNodes.values()) {
|
|
const node = createNode(datum);
|
|
nodesById.set(datum.id, node);
|
|
}
|
|
const baseLinks = [];
|
|
const linkData = linksProcessedData.dataSources.get(this.id)?.data;
|
|
if (linkData) {
|
|
for (const [datumIndex, datum] of linkData.entries()) {
|
|
const fromId = fromIdValues[datumIndex];
|
|
const toId = toIdValues[datumIndex];
|
|
const size = sizeValues == null ? 1 : sizeValues[datumIndex];
|
|
const fromNode = nodesById.get(fromId);
|
|
const toNode = nodesById.get(toId);
|
|
if (size <= 0 || fromNode == null || toNode == null)
|
|
continue;
|
|
const linkNodeDatumIndex = { type: 0 /* Link */, index: datumIndex };
|
|
const link = createLink({
|
|
series: this,
|
|
itemId: `link-${datumIndex}`,
|
|
datum,
|
|
datumIndex: linkNodeDatumIndex,
|
|
type: 0 /* Link */,
|
|
index: datumIndex,
|
|
fromNode,
|
|
toNode,
|
|
size,
|
|
style: this.getLinkStyle(
|
|
{ datum, datumIndex: linkNodeDatumIndex },
|
|
fromNode.datumIndex,
|
|
false
|
|
)
|
|
});
|
|
baseLinks.push(link);
|
|
}
|
|
}
|
|
const { links, nodeGraph, maxPathLength } = computeNodeGraph(
|
|
nodesById.values(),
|
|
baseLinks,
|
|
includeCircularReferences
|
|
);
|
|
for (const node of nodeGraph.values()) {
|
|
node.datum.linksBefore = node.linksBefore.map((linkedNode) => linkedNode.link);
|
|
node.datum.linksAfter = node.linksAfter.map((linkedNode) => linkedNode.link);
|
|
}
|
|
this.nodeCount = nodeGraph.size;
|
|
this.linkCount = links.length;
|
|
return { nodeGraph, links, maxPathLength };
|
|
}
|
|
updateSelections() {
|
|
if (this.nodeDataRefresh) {
|
|
this.contextNodeData = this.createNodeData();
|
|
this.nodeDataRefresh = false;
|
|
}
|
|
}
|
|
update(opts) {
|
|
const { seriesRect } = opts;
|
|
const newNodeDataDependencies = {
|
|
seriesRectWidth: seriesRect?.width ?? 0,
|
|
seriesRectHeight: seriesRect?.height ?? 0
|
|
};
|
|
if (this._nodeDataDependencies == null || this._nodeDataDependencies.seriesRectWidth !== newNodeDataDependencies.seriesRectWidth || this._nodeDataDependencies.seriesRectHeight !== newNodeDataDependencies.seriesRectHeight) {
|
|
this._nodeDataDependencies = newNodeDataDependencies;
|
|
}
|
|
this.updateSelections();
|
|
const nodeData = this.contextNodeData?.nodeData ?? [];
|
|
const labelData = this.contextNodeData?.labelData ?? [];
|
|
const highlightedDatum = this.getHighlightedDatum();
|
|
this.contentGroup.visible = this.visible;
|
|
const highlightState = highlightedDatum == null ? HighlightState4.None : HighlightState4.OtherItem;
|
|
this.contentGroup.opacity = this.properties.highlight.getStyle(highlightState).opacity ?? 1;
|
|
this.labelSelection = this.updateLabelSelection({ labelData, labelSelection: this.labelSelection });
|
|
this.updateLabelNodes({ labelSelection: this.labelSelection });
|
|
this.linkSelection = this.updateLinkSelection({
|
|
nodeData: nodeData.filter((d) => d.type === 0 /* Link */),
|
|
datumSelection: this.linkSelection
|
|
});
|
|
this.updateLinkNodes({ datumSelection: this.linkSelection, isHighlight: false });
|
|
this.nodeSelection = this.updateNodeSelection({
|
|
nodeData: nodeData.filter((d) => d.type === 1 /* Node */),
|
|
datumSelection: this.nodeSelection
|
|
});
|
|
this.updateNodeNodes({ datumSelection: this.nodeSelection, isHighlight: false });
|
|
let focusLinkSelection;
|
|
let focusNodeSelection;
|
|
let highlightLinkSelection;
|
|
let highlightNodeSelection;
|
|
if (highlightedDatum?.type === 1 /* Node */) {
|
|
focusLinkSelection = nodeData.filter((node) => {
|
|
return node.type === 0 /* Link */ && (node.toNode === highlightedDatum || node.fromNode === highlightedDatum);
|
|
});
|
|
focusNodeSelection = focusLinkSelection.map((link) => {
|
|
return link.fromNode === highlightedDatum ? link.toNode : link.fromNode;
|
|
});
|
|
focusNodeSelection.push(highlightedDatum);
|
|
highlightLinkSelection = [];
|
|
highlightNodeSelection = [highlightedDatum];
|
|
} else if (highlightedDatum?.type === 0 /* Link */) {
|
|
focusLinkSelection = [highlightedDatum];
|
|
focusNodeSelection = [highlightedDatum.fromNode, highlightedDatum.toNode];
|
|
highlightLinkSelection = [highlightedDatum];
|
|
highlightNodeSelection = [];
|
|
} else {
|
|
focusLinkSelection = [];
|
|
focusNodeSelection = [];
|
|
highlightLinkSelection = [];
|
|
highlightNodeSelection = [];
|
|
}
|
|
this.focusLinkSelection = this.updateLinkSelection({
|
|
nodeData: focusLinkSelection,
|
|
datumSelection: this.focusLinkSelection
|
|
});
|
|
this.updateLinkNodes({ datumSelection: this.focusLinkSelection, isHighlight: false });
|
|
this.focusNodeSelection = this.updateNodeSelection({
|
|
nodeData: focusNodeSelection,
|
|
datumSelection: this.focusNodeSelection
|
|
});
|
|
this.updateNodeNodes({ datumSelection: this.focusNodeSelection, isHighlight: false });
|
|
this.highlightLinkSelection = this.updateLinkSelection({
|
|
nodeData: highlightLinkSelection,
|
|
datumSelection: this.highlightLinkSelection
|
|
});
|
|
this.updateLinkNodes({ datumSelection: this.highlightLinkSelection, isHighlight: true });
|
|
this.highlightNodeSelection = this.updateNodeSelection({
|
|
nodeData: highlightNodeSelection,
|
|
datumSelection: this.highlightNodeSelection
|
|
});
|
|
this.updateNodeNodes({ datumSelection: this.highlightNodeSelection, isHighlight: true });
|
|
}
|
|
getHighlightedDatum() {
|
|
let highlightedDatum = this.ctx.highlightManager?.getActiveHighlight();
|
|
if (highlightedDatum?.series === this && highlightedDatum.type == null) {
|
|
const { itemId } = highlightedDatum;
|
|
const nodeData = this.contextNodeData?.nodeData ?? [];
|
|
highlightedDatum = itemId == null ? void 0 : nodeData.find((node) => node.type === 1 /* Node */ && node.id === itemId);
|
|
} else if (highlightedDatum?.series !== this) {
|
|
highlightedDatum = void 0;
|
|
}
|
|
return highlightedDatum;
|
|
}
|
|
isLabelHighlighted(datum, activeHighlight) {
|
|
if (activeHighlight == null)
|
|
return false;
|
|
if (activeHighlight.type === 1 /* Node */) {
|
|
return activeHighlight === datum;
|
|
}
|
|
if (activeHighlight.type === 0 /* Link */) {
|
|
return activeHighlight.fromNode === datum || activeHighlight.toNode === datum;
|
|
}
|
|
return false;
|
|
}
|
|
resetAnimation(_chartAnimationPhase) {
|
|
}
|
|
dataCount() {
|
|
return Number.NaN;
|
|
}
|
|
getSeriesDomain(_direction) {
|
|
return { domain: [] };
|
|
}
|
|
getSeriesRange(_direction, _visibleRange) {
|
|
return [Number.NaN, Number.NaN];
|
|
}
|
|
legendItemSymbol(_type, nodeIndex, format = {}) {
|
|
const { fills, strokes } = this.properties;
|
|
const {
|
|
fill = fills[nodeIndex % fills.length],
|
|
fillOpacity = 1,
|
|
stroke: stroke3 = strokes[nodeIndex % strokes.length],
|
|
strokeWidth = 0,
|
|
strokeOpacity = 1,
|
|
lineDash = [0],
|
|
lineDashOffset = 0
|
|
} = format;
|
|
return {
|
|
marker: {
|
|
fill,
|
|
fillOpacity,
|
|
stroke: stroke3,
|
|
strokeWidth,
|
|
strokeOpacity,
|
|
lineDash,
|
|
lineDashOffset
|
|
}
|
|
};
|
|
}
|
|
getLegendData(legendType) {
|
|
if (legendType !== "category")
|
|
return [];
|
|
const { showInLegend } = this.properties;
|
|
return Array.from(
|
|
this.processedNodes.values(),
|
|
({ id, label }, nodeIndex) => ({
|
|
legendType: "category",
|
|
id: this.id,
|
|
itemId: id,
|
|
seriesId: this.id,
|
|
enabled: true,
|
|
label: { text: label ?? id },
|
|
symbol: this.legendItemSymbol(1 /* Node */, nodeIndex),
|
|
hideInLegend: !showInLegend,
|
|
isFixed: true
|
|
})
|
|
);
|
|
}
|
|
pickNodeClosestDatum({ x, y }) {
|
|
let minDistanceSquared = Infinity;
|
|
let minDatum;
|
|
this.linkSelection.each((node, datum) => {
|
|
const distanceSquared = node.distanceSquared(x, y);
|
|
if (distanceSquared < minDistanceSquared) {
|
|
minDistanceSquared = distanceSquared;
|
|
minDatum = datum;
|
|
}
|
|
});
|
|
this.nodeSelection.each((node, datum) => {
|
|
const distanceSquared = node.distanceSquared(x, y);
|
|
if (distanceSquared < minDistanceSquared) {
|
|
minDistanceSquared = distanceSquared;
|
|
minDatum = datum;
|
|
}
|
|
});
|
|
return minDatum == null ? void 0 : { datum: minDatum, distance: Math.sqrt(minDistanceSquared) };
|
|
}
|
|
getDatumAriaText(datum, description) {
|
|
if (datum.type === 0 /* Link */) {
|
|
return this.ctx.localeManager.t("ariaAnnounceFlowProportionLink", {
|
|
index: datum.index + 1,
|
|
count: this.linkCount,
|
|
from: datum.fromNode.id,
|
|
to: datum.toNode.id,
|
|
size: datum.size,
|
|
sizeName: this.properties.sizeName ?? this.properties.sizeKey
|
|
});
|
|
} else if (datum.type === 1 /* Node */) {
|
|
return this.ctx.localeManager.t("ariaAnnounceFlowProportionNode", {
|
|
index: datum.index + 1,
|
|
count: this.nodeCount,
|
|
description
|
|
});
|
|
}
|
|
}
|
|
pickFocus(opts) {
|
|
const { datumIndexDelta: childDelta, otherIndexDelta: depthDelta } = opts;
|
|
const currentNodeDatum = this.contextNodeData?.nodeData[opts.datumIndex - opts.datumIndexDelta];
|
|
let nextNodeDatum = currentNodeDatum;
|
|
if (depthDelta !== 0 || childDelta === 0)
|
|
return;
|
|
if (currentNodeDatum?.type === 0 /* Link */) {
|
|
const allLinks = Array.from(this.linkSelection, (link) => link.datum);
|
|
const selfIndex = allLinks.indexOf(currentNodeDatum);
|
|
const nextIndex = selfIndex + childDelta;
|
|
if (nextIndex >= 0 && nextIndex < allLinks.length) {
|
|
nextNodeDatum = allLinks[nextIndex];
|
|
} else if (nextIndex > 0) {
|
|
nextNodeDatum = allLinks.at(-1);
|
|
} else {
|
|
const allNodes = Array.from(this.nodeSelection, (node) => node.datum);
|
|
nextNodeDatum = allNodes.at(-1);
|
|
}
|
|
} else if (currentNodeDatum?.type === 1 /* Node */) {
|
|
const allNodes = Array.from(this.nodeSelection, (node) => node.datum);
|
|
const selfIndex = allNodes.indexOf(currentNodeDatum);
|
|
const nextIndex = selfIndex + childDelta;
|
|
if (nextIndex >= 0 && nextIndex < allNodes.length) {
|
|
nextNodeDatum = allNodes[nextIndex];
|
|
} else if (nextIndex < 0) {
|
|
nextNodeDatum = allNodes[0];
|
|
} else {
|
|
const allLinks = Array.from(this.linkSelection, (link) => link.datum);
|
|
nextNodeDatum = allLinks[0];
|
|
}
|
|
}
|
|
if (nextNodeDatum == null)
|
|
return;
|
|
const nodeDatum = nextNodeDatum.type === 1 /* Node */ ? Array.from(this.nodeSelection).find((n) => n.datum === nextNodeDatum) : Array.from(this.linkSelection).find((n) => n.datum === nextNodeDatum);
|
|
if (nodeDatum == null)
|
|
return;
|
|
const bounds = this.computeFocusBounds(nodeDatum.node);
|
|
if (bounds == null)
|
|
return;
|
|
return {
|
|
datum: nodeDatum.datum,
|
|
datumIndex: this.contextNodeData?.nodeData.indexOf(nodeDatum.datum) ?? 0,
|
|
otherIndex: 0,
|
|
bounds,
|
|
clipFocusBox: true
|
|
};
|
|
}
|
|
getCategoryValue(_datumIndex) {
|
|
return;
|
|
}
|
|
datumIndexForCategoryValue(_categoryValue) {
|
|
return;
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/series/chord/chordLink.ts
|
|
import { _ModuleSupport as _ModuleSupport139 } from "ag-charts-community";
|
|
import { SceneChangeDetection as SceneChangeDetection6 } from "ag-charts-core";
|
|
var { Path: Path9 } = _ModuleSupport139;
|
|
function bezierControlPoints({
|
|
radius,
|
|
startAngle,
|
|
endAngle,
|
|
tension
|
|
}) {
|
|
const cp0x = radius * Math.cos(startAngle);
|
|
const cp0y = radius * Math.sin(startAngle);
|
|
const cp3x = radius * Math.cos(endAngle);
|
|
const cp3y = radius * Math.sin(endAngle);
|
|
const cp1x = cp0x * tension;
|
|
const cp1y = cp0y * tension;
|
|
const cp2x = cp3x * tension;
|
|
const cp2y = cp3y * tension;
|
|
return {
|
|
x: [cp0x, cp1x, cp2x, cp3x],
|
|
y: [cp0y, cp1y, cp2y, cp3y]
|
|
};
|
|
}
|
|
var ChordLink = class extends Path9 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.centerX = 0;
|
|
this.centerY = 0;
|
|
this.radius = 0;
|
|
this.startAngle1 = 0;
|
|
this.endAngle1 = 0;
|
|
this.startAngle2 = 0;
|
|
this.endAngle2 = 0;
|
|
this.tension = 1;
|
|
}
|
|
tensionedCurveTo(cp0x, cp0y, cp1x, cp1y, cp2x, cp2y, cp3x, cp3y) {
|
|
const { path, tension } = this;
|
|
const scale = 1 - tension;
|
|
path.cubicCurveTo(
|
|
(cp1x - cp0x) * scale + cp0x,
|
|
(cp1y - cp0y) * scale + cp0y,
|
|
(cp2x - cp3x) * scale + cp3x,
|
|
(cp2y - cp3y) * scale + cp3y,
|
|
cp3x,
|
|
cp3y
|
|
);
|
|
}
|
|
updatePath() {
|
|
const { path, centerX, centerY, radius } = this;
|
|
let { startAngle1, endAngle1, startAngle2, endAngle2 } = this;
|
|
if (startAngle1 > startAngle2) {
|
|
[startAngle1, startAngle2] = [startAngle2, startAngle1];
|
|
[endAngle1, endAngle2] = [endAngle2, endAngle1];
|
|
}
|
|
path.clear();
|
|
const startX = centerX + radius * Math.cos(startAngle1);
|
|
const startY = centerY + radius * Math.sin(startAngle1);
|
|
path.moveTo(startX, startY);
|
|
this.tensionedCurveTo(
|
|
startX,
|
|
startY,
|
|
centerX,
|
|
centerY,
|
|
centerX,
|
|
centerY,
|
|
centerX + radius * Math.cos(endAngle2),
|
|
centerY + radius * Math.sin(endAngle2)
|
|
);
|
|
path.arc(centerX, centerY, radius, endAngle2, startAngle2, true);
|
|
this.tensionedCurveTo(
|
|
centerX + radius * Math.cos(startAngle2),
|
|
centerY + radius * Math.sin(startAngle2),
|
|
centerX,
|
|
centerY,
|
|
centerX,
|
|
centerY,
|
|
centerX + radius * Math.cos(endAngle1),
|
|
centerY + radius * Math.sin(endAngle1)
|
|
);
|
|
path.arc(centerX, centerY, radius, endAngle1, startAngle1, true);
|
|
path.closePath();
|
|
}
|
|
};
|
|
__decorateClass([
|
|
SceneChangeDetection6()
|
|
], ChordLink.prototype, "centerX", 2);
|
|
__decorateClass([
|
|
SceneChangeDetection6()
|
|
], ChordLink.prototype, "centerY", 2);
|
|
__decorateClass([
|
|
SceneChangeDetection6()
|
|
], ChordLink.prototype, "radius", 2);
|
|
__decorateClass([
|
|
SceneChangeDetection6()
|
|
], ChordLink.prototype, "startAngle1", 2);
|
|
__decorateClass([
|
|
SceneChangeDetection6()
|
|
], ChordLink.prototype, "endAngle1", 2);
|
|
__decorateClass([
|
|
SceneChangeDetection6()
|
|
], ChordLink.prototype, "startAngle2", 2);
|
|
__decorateClass([
|
|
SceneChangeDetection6()
|
|
], ChordLink.prototype, "endAngle2", 2);
|
|
__decorateClass([
|
|
SceneChangeDetection6()
|
|
], ChordLink.prototype, "tension", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/series/chord/chordSeriesProperties.ts
|
|
import {
|
|
_ModuleSupport as _ModuleSupport140
|
|
} from "ag-charts-community";
|
|
import { BaseProperties as BaseProperties30, Property as Property69 } from "ag-charts-core";
|
|
var { FillGradientDefaults: FillGradientDefaults2, FillPatternDefaults: FillPatternDefaults2, FillImageDefaults: FillImageDefaults2, makeSeriesTooltip: makeSeriesTooltip8, SeriesProperties, Label: Label6 } = _ModuleSupport140;
|
|
var ChordSeriesLabelProperties = class extends Label6 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.spacing = 1;
|
|
this.maxWidth = 1;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property69
|
|
], ChordSeriesLabelProperties.prototype, "spacing", 2);
|
|
__decorateClass([
|
|
Property69
|
|
], ChordSeriesLabelProperties.prototype, "maxWidth", 2);
|
|
var ChordSeriesLinkProperties = class extends BaseProperties30 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.fill = void 0;
|
|
this.fillOpacity = 1;
|
|
this.stroke = void 0;
|
|
this.strokeOpacity = 1;
|
|
this.strokeWidth = 1;
|
|
this.lineDash = [0];
|
|
this.lineDashOffset = 0;
|
|
this.tension = 0;
|
|
}
|
|
getStyle(fills, strokes, index) {
|
|
const { fillOpacity, strokeWidth, strokeOpacity, lineDash, lineDashOffset, tension } = this;
|
|
const fill = this.fill ?? fills[index % fills.length];
|
|
const stroke3 = this.stroke ?? strokes[index % fills.length];
|
|
return {
|
|
fill,
|
|
fillOpacity,
|
|
stroke: stroke3,
|
|
strokeWidth,
|
|
strokeOpacity,
|
|
lineDash,
|
|
lineDashOffset,
|
|
tension
|
|
};
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property69
|
|
], ChordSeriesLinkProperties.prototype, "fill", 2);
|
|
__decorateClass([
|
|
Property69
|
|
], ChordSeriesLinkProperties.prototype, "fillOpacity", 2);
|
|
__decorateClass([
|
|
Property69
|
|
], ChordSeriesLinkProperties.prototype, "stroke", 2);
|
|
__decorateClass([
|
|
Property69
|
|
], ChordSeriesLinkProperties.prototype, "strokeOpacity", 2);
|
|
__decorateClass([
|
|
Property69
|
|
], ChordSeriesLinkProperties.prototype, "strokeWidth", 2);
|
|
__decorateClass([
|
|
Property69
|
|
], ChordSeriesLinkProperties.prototype, "lineDash", 2);
|
|
__decorateClass([
|
|
Property69
|
|
], ChordSeriesLinkProperties.prototype, "lineDashOffset", 2);
|
|
__decorateClass([
|
|
Property69
|
|
], ChordSeriesLinkProperties.prototype, "tension", 2);
|
|
__decorateClass([
|
|
Property69
|
|
], ChordSeriesLinkProperties.prototype, "itemStyler", 2);
|
|
var ChordSeriesNodeProperties = class extends BaseProperties30 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.spacing = 1;
|
|
this.width = 1;
|
|
this.fill = void 0;
|
|
this.fillOpacity = 1;
|
|
this.stroke = void 0;
|
|
this.strokeOpacity = 1;
|
|
this.strokeWidth = 1;
|
|
this.lineDash = [0];
|
|
this.lineDashOffset = 0;
|
|
}
|
|
getStyle(fills, strokes, index) {
|
|
const { fillOpacity, strokeWidth, strokeOpacity, lineDash, lineDashOffset } = this;
|
|
const fill = this.fill ?? fills[index % fills.length];
|
|
const stroke3 = this.stroke ?? strokes[index % fills.length];
|
|
return {
|
|
fill,
|
|
fillOpacity,
|
|
stroke: stroke3,
|
|
strokeWidth,
|
|
strokeOpacity,
|
|
lineDash,
|
|
lineDashOffset
|
|
};
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property69
|
|
], ChordSeriesNodeProperties.prototype, "spacing", 2);
|
|
__decorateClass([
|
|
Property69
|
|
], ChordSeriesNodeProperties.prototype, "width", 2);
|
|
__decorateClass([
|
|
Property69
|
|
], ChordSeriesNodeProperties.prototype, "fill", 2);
|
|
__decorateClass([
|
|
Property69
|
|
], ChordSeriesNodeProperties.prototype, "fillOpacity", 2);
|
|
__decorateClass([
|
|
Property69
|
|
], ChordSeriesNodeProperties.prototype, "stroke", 2);
|
|
__decorateClass([
|
|
Property69
|
|
], ChordSeriesNodeProperties.prototype, "strokeOpacity", 2);
|
|
__decorateClass([
|
|
Property69
|
|
], ChordSeriesNodeProperties.prototype, "strokeWidth", 2);
|
|
__decorateClass([
|
|
Property69
|
|
], ChordSeriesNodeProperties.prototype, "lineDash", 2);
|
|
__decorateClass([
|
|
Property69
|
|
], ChordSeriesNodeProperties.prototype, "lineDashOffset", 2);
|
|
__decorateClass([
|
|
Property69
|
|
], ChordSeriesNodeProperties.prototype, "itemStyler", 2);
|
|
var ChordSeriesProperties = class extends SeriesProperties {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.idKey = "";
|
|
this.idName = void 0;
|
|
this.labelKey = void 0;
|
|
this.labelName = void 0;
|
|
this.sizeKey = void 0;
|
|
this.sizeName = void 0;
|
|
this.nodes = void 0;
|
|
this.fillGradientDefaults = new FillGradientDefaults2();
|
|
this.fillPatternDefaults = new FillPatternDefaults2();
|
|
this.fillImageDefaults = new FillImageDefaults2();
|
|
this.fills = [];
|
|
this.strokes = [];
|
|
this.label = new ChordSeriesLabelProperties();
|
|
this.link = new ChordSeriesLinkProperties();
|
|
this.node = new ChordSeriesNodeProperties();
|
|
this.tooltip = makeSeriesTooltip8();
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property69
|
|
], ChordSeriesProperties.prototype, "fromKey", 2);
|
|
__decorateClass([
|
|
Property69
|
|
], ChordSeriesProperties.prototype, "toKey", 2);
|
|
__decorateClass([
|
|
Property69
|
|
], ChordSeriesProperties.prototype, "idKey", 2);
|
|
__decorateClass([
|
|
Property69
|
|
], ChordSeriesProperties.prototype, "idName", 2);
|
|
__decorateClass([
|
|
Property69
|
|
], ChordSeriesProperties.prototype, "labelKey", 2);
|
|
__decorateClass([
|
|
Property69
|
|
], ChordSeriesProperties.prototype, "labelName", 2);
|
|
__decorateClass([
|
|
Property69
|
|
], ChordSeriesProperties.prototype, "sizeKey", 2);
|
|
__decorateClass([
|
|
Property69
|
|
], ChordSeriesProperties.prototype, "sizeName", 2);
|
|
__decorateClass([
|
|
Property69
|
|
], ChordSeriesProperties.prototype, "nodes", 2);
|
|
__decorateClass([
|
|
Property69
|
|
], ChordSeriesProperties.prototype, "fillGradientDefaults", 2);
|
|
__decorateClass([
|
|
Property69
|
|
], ChordSeriesProperties.prototype, "fillPatternDefaults", 2);
|
|
__decorateClass([
|
|
Property69
|
|
], ChordSeriesProperties.prototype, "fillImageDefaults", 2);
|
|
__decorateClass([
|
|
Property69
|
|
], ChordSeriesProperties.prototype, "fills", 2);
|
|
__decorateClass([
|
|
Property69
|
|
], ChordSeriesProperties.prototype, "strokes", 2);
|
|
__decorateClass([
|
|
Property69
|
|
], ChordSeriesProperties.prototype, "label", 2);
|
|
__decorateClass([
|
|
Property69
|
|
], ChordSeriesProperties.prototype, "link", 2);
|
|
__decorateClass([
|
|
Property69
|
|
], ChordSeriesProperties.prototype, "node", 2);
|
|
__decorateClass([
|
|
Property69
|
|
], ChordSeriesProperties.prototype, "tooltip", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/series/chord/chordSeries.ts
|
|
var { SeriesNodePickMode: SeriesNodePickMode6, createDatumId: createDatumId7, Sector: Sector3, getShapeStyle, getLabelStyles, BBox: BBox17 } = _ModuleSupport141;
|
|
var nodeMidAngle = (node) => node.startAngle + angleBetween2(node.startAngle, node.endAngle) / 2;
|
|
var ChordSeries = class extends FlowProportionSeries {
|
|
constructor(moduleCtx) {
|
|
super({
|
|
moduleCtx,
|
|
pickModes: [SeriesNodePickMode6.NEAREST_NODE, SeriesNodePickMode6.EXACT_SHAPE_MATCH]
|
|
});
|
|
this.properties = new ChordSeriesProperties();
|
|
}
|
|
isLabelEnabled() {
|
|
return (this.properties.labelKey != null || this.nodes == null) && this.properties.label.enabled;
|
|
}
|
|
linkFactory() {
|
|
return new ChordLink();
|
|
}
|
|
nodeFactory() {
|
|
return new Sector3();
|
|
}
|
|
createNodeData() {
|
|
const {
|
|
id: seriesId,
|
|
_nodeDataDependencies: { seriesRectWidth, seriesRectHeight } = { seriesRectWidth: 0, seriesRectHeight: 0 },
|
|
properties
|
|
} = this;
|
|
const {
|
|
fromKey,
|
|
toKey,
|
|
sizeKey,
|
|
labelKey,
|
|
label: { spacing: labelSpacing, maxWidth: labelMaxWidth, fontSize },
|
|
node: { width: nodeWidth, spacing: nodeSpacing }
|
|
} = properties;
|
|
const centerX = seriesRectWidth / 2;
|
|
const centerY = seriesRectHeight / 2;
|
|
let labelData = [];
|
|
const { nodeGraph, links } = this.getNodeGraph(
|
|
(node) => ({
|
|
...node,
|
|
centerX,
|
|
centerY,
|
|
innerRadius: Number.NaN,
|
|
outerRadius: Number.NaN,
|
|
startAngle: Number.NaN,
|
|
endAngle: Number.NaN
|
|
}),
|
|
(link) => ({
|
|
...link,
|
|
centerX,
|
|
centerY,
|
|
radius: Number.NaN,
|
|
startAngle1: Number.NaN,
|
|
endAngle1: Number.NaN,
|
|
startAngle2: Number.NaN,
|
|
endAngle2: Number.NaN
|
|
}),
|
|
{ includeCircularReferences: true }
|
|
);
|
|
let totalSize = 0;
|
|
for (const [id, { datum: node, linksBefore, linksAfter }] of nodeGraph.entries()) {
|
|
const size = linksBefore.reduce((acc, { link }) => acc + link.size, 0) + linksAfter.reduce((acc, { link }) => acc + link.size, 0);
|
|
if (size === 0) {
|
|
nodeGraph.delete(id);
|
|
} else {
|
|
const { label } = properties;
|
|
node.size = size;
|
|
totalSize += node.size;
|
|
const labelText = label.enabled ? this.getLabelText(
|
|
node.label,
|
|
node.datum,
|
|
labelKey,
|
|
"label",
|
|
[],
|
|
label,
|
|
{ datum: node.datum, value: node.label, fromKey, toKey, sizeKey, size: node.size }
|
|
) : void 0;
|
|
node.label = toPlainText5(labelText);
|
|
}
|
|
}
|
|
let labelInset = 0;
|
|
if (this.isLabelEnabled()) {
|
|
const measurer3 = cachedTextMeasurer5(this.properties.label);
|
|
let maxMeasuredLabelWidth = 0;
|
|
for (const { datum: node } of nodeGraph.values()) {
|
|
const { id, label } = node;
|
|
if (label == null)
|
|
continue;
|
|
const text2 = wrapText3(label, {
|
|
maxWidth: labelMaxWidth,
|
|
font: this.properties.label,
|
|
textWrap: "never"
|
|
});
|
|
const { width } = measurer3.measureLines(text2);
|
|
maxMeasuredLabelWidth = Math.max(width, maxMeasuredLabelWidth);
|
|
labelData.push({
|
|
id,
|
|
text: text2,
|
|
centerX,
|
|
centerY,
|
|
angle: Number.NaN,
|
|
radius: Number.NaN,
|
|
size: node.size,
|
|
datumIndex: node.datumIndex,
|
|
nodeDatum: node
|
|
});
|
|
}
|
|
labelInset = maxMeasuredLabelWidth + labelSpacing;
|
|
}
|
|
const nodeCount = nodeGraph.size;
|
|
let radius = Math.min(seriesRectWidth, seriesRectHeight) / 2 - nodeWidth - labelInset;
|
|
let spacingSweep = nodeSpacing / radius;
|
|
if (labelInset !== 0 && (nodeCount * spacingSweep >= 1.5 * Math.PI || radius <= 0)) {
|
|
labelData = [];
|
|
radius = Math.min(seriesRectWidth, seriesRectHeight) / 2 - nodeWidth;
|
|
spacingSweep = nodeSpacing / radius;
|
|
}
|
|
if (nodeCount * spacingSweep >= 2 * Math.PI || radius <= 0) {
|
|
Logger15.warnOnce("There was insufficient space to display the Chord Series.");
|
|
return;
|
|
}
|
|
const innerRadius = radius;
|
|
const outerRadius = radius + nodeWidth;
|
|
const sizeScale = Math.max((2 * Math.PI - nodeCount * spacingSweep) / totalSize, 0);
|
|
let nodeAngle = 0;
|
|
for (const { datum: node } of nodeGraph.values()) {
|
|
node.innerRadius = innerRadius;
|
|
node.outerRadius = outerRadius;
|
|
node.startAngle = nodeAngle;
|
|
node.endAngle = nodeAngle + node.size * sizeScale;
|
|
nodeAngle = node.endAngle + spacingSweep;
|
|
const midR = (node.innerRadius + node.outerRadius) / 2;
|
|
const midAngle = nodeMidAngle(node);
|
|
node.midPoint = {
|
|
x: node.centerX + midR * Math.cos(midAngle),
|
|
y: node.centerY + midR * Math.sin(midAngle)
|
|
};
|
|
}
|
|
const nodeData = [];
|
|
for (const { datum: node, linksBefore, linksAfter } of nodeGraph.values()) {
|
|
const midAngle = nodeMidAngle(node);
|
|
const combinedLinks = [
|
|
...linksBefore.map((l) => ({
|
|
link: l.link,
|
|
distance: angleBetween2(nodeMidAngle(l.node.datum), midAngle),
|
|
after: false
|
|
})),
|
|
...linksAfter.map((l) => ({
|
|
link: l.link,
|
|
distance: angleBetween2(nodeMidAngle(l.node.datum), midAngle),
|
|
after: true
|
|
}))
|
|
];
|
|
let linkAngle = node.startAngle;
|
|
for (const { link, after } of combinedLinks.toSorted((a, b) => a.distance - b.distance)) {
|
|
const linkSweep = link.size * sizeScale;
|
|
if (after) {
|
|
link.startAngle1 = linkAngle;
|
|
link.endAngle1 = linkAngle + linkSweep;
|
|
} else {
|
|
link.startAngle2 = linkAngle;
|
|
link.endAngle2 = linkAngle + linkSweep;
|
|
}
|
|
linkAngle += link.size * sizeScale;
|
|
}
|
|
nodeData.push(node);
|
|
}
|
|
const { tension } = this.properties.link;
|
|
for (const link of links) {
|
|
link.radius = radius;
|
|
const outer = bezierControlPoints({
|
|
radius,
|
|
startAngle: link.startAngle1,
|
|
endAngle: link.endAngle2,
|
|
tension
|
|
});
|
|
const inner = bezierControlPoints({
|
|
radius,
|
|
startAngle: link.startAngle2,
|
|
endAngle: link.endAngle1,
|
|
tension
|
|
});
|
|
const outerX = evaluateBezier(...outer.x, 0.5);
|
|
const outerY = evaluateBezier(...outer.y, 0.5);
|
|
const innerX = evaluateBezier(...inner.x, 0.5);
|
|
const innerY = evaluateBezier(...inner.y, 0.5);
|
|
link.midPoint = {
|
|
x: link.centerX + (outerX + innerX) / 2,
|
|
y: link.centerY + (outerY + innerY) / 2
|
|
};
|
|
nodeData.push(link);
|
|
}
|
|
for (const label of labelData) {
|
|
const node = nodeGraph.get(label.id)?.datum;
|
|
if (node == null)
|
|
continue;
|
|
label.radius = outerRadius + labelSpacing;
|
|
label.angle = normalizeAngle3604(node.startAngle + angleBetween2(node.startAngle, node.endAngle) / 2);
|
|
label.datumIndex = node.datumIndex;
|
|
label.nodeDatum = node;
|
|
}
|
|
labelData.sort((a, b) => a.angle - b.angle);
|
|
let minAngle = Infinity;
|
|
let maxAngle = -Infinity;
|
|
labelData = labelData.filter((label) => {
|
|
const labelHeight = calcLineHeight6(fontSize);
|
|
const da = Math.atan2(labelHeight / 2, label.radius);
|
|
const a0 = label.angle - da;
|
|
const a1 = label.angle + da;
|
|
if (isBetweenAngles(minAngle, a0, a1))
|
|
return false;
|
|
if (isBetweenAngles(maxAngle, a0, a1))
|
|
return false;
|
|
minAngle = Math.min(a0, minAngle);
|
|
maxAngle = Math.max(a1, maxAngle);
|
|
return true;
|
|
});
|
|
return {
|
|
itemId: seriesId,
|
|
nodeData,
|
|
labelData
|
|
};
|
|
}
|
|
updateLabelSelection(opts) {
|
|
const labels = this.isLabelEnabled() ? opts.labelData : [];
|
|
return opts.labelSelection.update(labels);
|
|
}
|
|
updateLabelNodes(opts) {
|
|
const params = {
|
|
toKey: this.properties.toKey,
|
|
fromKey: this.properties.fromKey,
|
|
sizeKey: this.properties.sizeKey,
|
|
size: Number.NaN
|
|
};
|
|
const activeHighlightDatum = this.getHighlightedDatum();
|
|
opts.labelSelection.each((label, labelNodeDatum) => {
|
|
const { size, text: text2, centerX, centerY, radius, angle, datumIndex, nodeDatum } = labelNodeDatum;
|
|
params.size = size;
|
|
const isHighlight = this.isLabelHighlighted(nodeDatum, activeHighlightDatum);
|
|
const highlightStyle = this.getHighlightStyle(isHighlight, datumIndex);
|
|
const style = getLabelStyles(
|
|
this,
|
|
void 0,
|
|
params,
|
|
this.properties.label,
|
|
isHighlight,
|
|
activeHighlightDatum
|
|
);
|
|
const { fontStyle, fontWeight, fontSize, fontFamily, color: fill } = style;
|
|
label.visible = true;
|
|
label.translationX = centerX + radius * Math.cos(angle);
|
|
label.translationY = centerY + radius * Math.sin(angle);
|
|
label.text = text2;
|
|
label.fill = fill;
|
|
label.fontStyle = fontStyle;
|
|
label.fontWeight = fontWeight;
|
|
label.fontSize = fontSize;
|
|
label.fontFamily = fontFamily;
|
|
label.textBaseline = "middle";
|
|
if (Math.cos(angle) >= 0) {
|
|
label.textAlign = "left";
|
|
label.rotation = angle;
|
|
} else {
|
|
label.textAlign = "right";
|
|
label.rotation = angle - Math.PI;
|
|
}
|
|
const opacity = highlightStyle.opacity ?? 1;
|
|
label.opacity = opacity;
|
|
label.fillOpacity = opacity;
|
|
label.setBoxing(style);
|
|
});
|
|
}
|
|
updateNodeSelection(opts) {
|
|
return opts.datumSelection.update(opts.nodeData, void 0, (datum) => createDatumId7(datum.type, datum.id));
|
|
}
|
|
getNodeStyle(nodeDatum, fromNodeDatumIndex, isHighlight) {
|
|
const { properties } = this;
|
|
const { fills, strokes, fillGradientDefaults: fillGradientDefaults3, fillPatternDefaults: fillPatternDefaults3, fillImageDefaults: fillImageDefaults3 } = properties;
|
|
const { itemStyler } = properties.node;
|
|
const highlightStyle = this.getHighlightStyle(isHighlight, nodeDatum.datumIndex);
|
|
const baseStyle = mergeDefaults10(highlightStyle, properties.node.getStyle(fills, strokes, fromNodeDatumIndex));
|
|
let style = getShapeStyle(baseStyle, fillGradientDefaults3, fillPatternDefaults3, fillImageDefaults3);
|
|
if (itemStyler != null && nodeDatum.datumIndex != null) {
|
|
const overrides = this.cachedDatumCallback(
|
|
createDatumId7(nodeDatum.datumIndex.index, "node", isHighlight ? "highlight" : "node"),
|
|
() => {
|
|
const params = this.makeItemStylerParams(nodeDatum, isHighlight, style);
|
|
return this.callWithContext(itemStyler, params);
|
|
}
|
|
);
|
|
if (overrides) {
|
|
style = getShapeStyle(
|
|
mergeDefaults10(overrides, style),
|
|
fillGradientDefaults3,
|
|
fillPatternDefaults3,
|
|
fillImageDefaults3
|
|
);
|
|
}
|
|
}
|
|
style.opacity = 1;
|
|
return style;
|
|
}
|
|
makeItemStylerParams({ datum, datumIndex, size = 0, label }, isHighlight, style) {
|
|
const { id: seriesId } = this;
|
|
const activeHighlight = this.ctx.highlightManager?.getActiveHighlight();
|
|
const highlightState = this.getHighlightStateString(activeHighlight, isHighlight, datumIndex);
|
|
const fill = this.filterItemStylerFillParams(style.fill) ?? style.fill;
|
|
return {
|
|
seriesId,
|
|
datum,
|
|
highlightState,
|
|
...style,
|
|
size,
|
|
label,
|
|
fill
|
|
};
|
|
}
|
|
updateNodeNodes(opts) {
|
|
const { datumSelection, isHighlight } = opts;
|
|
const fillBBox = this.getShapeFillBBox();
|
|
datumSelection.each((sector, datum) => {
|
|
const { datumIndex } = datum;
|
|
const style = this.getNodeStyle(datum, datumIndex.index, isHighlight);
|
|
sector.setStyleProperties(style, fillBBox);
|
|
sector.centerX = datum.centerX;
|
|
sector.centerY = datum.centerY;
|
|
sector.innerRadius = datum.innerRadius;
|
|
sector.outerRadius = datum.outerRadius;
|
|
sector.startAngle = datum.startAngle;
|
|
sector.endAngle = datum.endAngle;
|
|
sector.inset = sector.strokeWidth / 2;
|
|
});
|
|
}
|
|
updateLinkSelection(opts) {
|
|
return opts.datumSelection.update(
|
|
opts.nodeData,
|
|
void 0,
|
|
(datum) => createDatumId7(datum.type, datum.index, datum.fromNode.id, datum.toNode.id)
|
|
);
|
|
}
|
|
getLinkStyle({ datumIndex, datum }, fromNodeDatumIndex, isHighlight) {
|
|
const { id: seriesId, properties } = this;
|
|
const { fills, strokes, fillGradientDefaults: fillGradientDefaults3, fillPatternDefaults: fillPatternDefaults3, fillImageDefaults: fillImageDefaults3 } = properties;
|
|
const { itemStyler } = properties.link;
|
|
const highlightStyle = this.getHighlightStyle(isHighlight, datumIndex);
|
|
const baseStyle = mergeDefaults10(
|
|
highlightStyle,
|
|
properties.link.getStyle(fills, strokes, fromNodeDatumIndex.index)
|
|
);
|
|
let style = getShapeStyle(baseStyle, fillGradientDefaults3, fillPatternDefaults3, fillImageDefaults3);
|
|
if (itemStyler != null && datumIndex != null) {
|
|
const activeHighlight = this.ctx.highlightManager?.getActiveHighlight();
|
|
const overrides = this.cachedDatumCallback(
|
|
createDatumId7(datumIndex.index, "link", isHighlight ? "highlight" : "node"),
|
|
() => {
|
|
const highlightState = this.getHighlightStateString(
|
|
activeHighlight,
|
|
isHighlight,
|
|
fromNodeDatumIndex
|
|
);
|
|
return this.callWithContext(itemStyler, {
|
|
seriesId,
|
|
datum,
|
|
highlightState,
|
|
...style
|
|
});
|
|
}
|
|
);
|
|
if (overrides) {
|
|
style = getShapeStyle(
|
|
mergeDefaults10(overrides, style),
|
|
fillGradientDefaults3,
|
|
fillPatternDefaults3,
|
|
fillImageDefaults3
|
|
);
|
|
}
|
|
}
|
|
style.opacity = 1;
|
|
return style;
|
|
}
|
|
updateLinkNodes(opts) {
|
|
const { datumSelection, isHighlight } = opts;
|
|
const fillBBox = this.getShapeFillBBox();
|
|
datumSelection.each((link, datum) => {
|
|
const fromNodeDatumIndex = datum.fromNode.datumIndex;
|
|
const style = this.getLinkStyle(datum, fromNodeDatumIndex, isHighlight);
|
|
link.centerX = datum.centerX;
|
|
link.centerY = datum.centerY;
|
|
link.radius = datum.radius;
|
|
link.startAngle1 = datum.startAngle1;
|
|
link.endAngle1 = datum.endAngle1;
|
|
link.startAngle2 = datum.startAngle2;
|
|
link.endAngle2 = datum.endAngle2;
|
|
link.tension = style.tension;
|
|
link.setStyleProperties(style, fillBBox);
|
|
});
|
|
}
|
|
getShapeFillBBox() {
|
|
const width = this._nodeDataDependencies?.seriesRectWidth ?? 0;
|
|
const height = this._nodeDataDependencies?.seriesRectHeight ?? 0;
|
|
const size = Math.min(width, height);
|
|
const x = (width - size) / 2;
|
|
const y = (height - size) / 2;
|
|
const bbox = new BBox17(x, y, width, height);
|
|
return { series: bbox, axis: bbox };
|
|
}
|
|
getTooltipContent(datumIndex) {
|
|
const {
|
|
id: seriesId,
|
|
linksProcessedData,
|
|
nodesProcessedData,
|
|
properties,
|
|
ctx: { formatManager }
|
|
} = this;
|
|
const { fromKey, toKey, sizeKey, sizeName, tooltip } = properties;
|
|
const seriesDatum = this.contextNodeData?.nodeData.find(
|
|
(d) => d.datumIndex.type === datumIndex.type && d.datumIndex.index === datumIndex.index
|
|
);
|
|
if (seriesDatum == null)
|
|
return;
|
|
const nodeIndex = seriesDatum.type === 0 /* Link */ ? seriesDatum.fromNode.index : seriesDatum.index;
|
|
const title = seriesDatum.type === 0 /* Link */ ? `${seriesDatum.fromNode.label} - ${seriesDatum.toNode.label}` : seriesDatum.label;
|
|
const datum = datumIndex.type === 0 /* Link */ ? linksProcessedData?.dataSources.get(this.id)?.data[datumIndex.index] : nodesProcessedData?.dataSources.get(this.id)?.data[datumIndex.index];
|
|
const size = seriesDatum.size;
|
|
let format;
|
|
if (seriesDatum.type === 0 /* Link */) {
|
|
const fromNodeDatumIndex = seriesDatum.fromNode.datumIndex;
|
|
format = this.getLinkStyle({ datumIndex, datum }, fromNodeDatumIndex, false);
|
|
} else {
|
|
const label = seriesDatum.label;
|
|
format = this.getNodeStyle({ datumIndex, datum, size, label }, datumIndex.index, false);
|
|
}
|
|
const data = [];
|
|
if (sizeKey != null) {
|
|
const content = formatManager.format(this.callWithContext.bind(this), {
|
|
type: "number",
|
|
value: size,
|
|
datum,
|
|
seriesId,
|
|
legendItemName: void 0,
|
|
key: sizeKey,
|
|
source: "tooltip",
|
|
property: "size",
|
|
domain: [],
|
|
boundSeries: this.getFormatterContext("size"),
|
|
fractionDigits: void 0,
|
|
visibleDomain: void 0
|
|
});
|
|
data.push({ label: sizeName, fallbackLabel: sizeKey, value: content ?? String(size) });
|
|
}
|
|
return this.formatTooltipWithContext(
|
|
tooltip,
|
|
{
|
|
title,
|
|
symbol: this.legendItemSymbol(seriesDatum.type, nodeIndex, format),
|
|
data
|
|
},
|
|
{
|
|
seriesId,
|
|
datum,
|
|
title,
|
|
fromKey,
|
|
toKey,
|
|
sizeKey,
|
|
sizeName,
|
|
size,
|
|
...format
|
|
}
|
|
);
|
|
}
|
|
computeFocusBounds(node) {
|
|
return node;
|
|
}
|
|
hasItemStylers() {
|
|
return this.properties.node.itemStyler != null || this.properties.link.itemStyler != null || this.properties.label.itemStyler != null;
|
|
}
|
|
};
|
|
ChordSeries.className = "ChordSeries";
|
|
ChordSeries.type = "chord";
|
|
|
|
// packages/ag-charts-enterprise/src/series/chord/chordSeriesOptionsDef.ts
|
|
import { _ModuleSupport as _ModuleSupport142 } from "ag-charts-community";
|
|
import {
|
|
commonSeriesOptionsDefs as commonSeriesOptionsDefs8,
|
|
constant as constant8,
|
|
fillGradientDefaults,
|
|
fillImageDefaults,
|
|
fillPatternDefaults,
|
|
required as required8,
|
|
string as string10,
|
|
undocumented as undocumented9
|
|
} from "ag-charts-core";
|
|
var { chordSeriesThemeableOptionsDef } = _ModuleSupport142;
|
|
var chordSeriesOptionsDef = {
|
|
...chordSeriesThemeableOptionsDef,
|
|
...commonSeriesOptionsDefs8,
|
|
type: required8(constant8("chord")),
|
|
fromKey: required8(string10),
|
|
toKey: required8(string10),
|
|
sizeKey: string10,
|
|
sizeName: string10
|
|
};
|
|
chordSeriesOptionsDef.fillGradientDefaults = undocumented9(fillGradientDefaults);
|
|
chordSeriesOptionsDef.fillPatternDefaults = undocumented9(fillPatternDefaults);
|
|
chordSeriesOptionsDef.fillImageDefaults = undocumented9(fillImageDefaults);
|
|
|
|
// packages/ag-charts-enterprise/src/series/chord/chordModule.ts
|
|
var ChordSeriesModule = {
|
|
type: "series",
|
|
name: "chord",
|
|
chartType: "standalone",
|
|
enterprise: true,
|
|
solo: true,
|
|
version: VERSION30,
|
|
dependencies: [StandaloneChartModule],
|
|
options: chordSeriesOptionsDef,
|
|
themeTemplate: {
|
|
series: {
|
|
fills: { $palette: "fills" },
|
|
strokes: { $palette: "strokes" },
|
|
fillGradientDefaults: FILL_GRADIENT_LINEAR_DEFAULTS4,
|
|
fillPatternDefaults: FILL_PATTERN_DEFAULTS4,
|
|
fillImageDefaults: FILL_IMAGE_DEFAULTS6,
|
|
highlight: SINGLE_SERIES_HIGHLIGHT_STYLE2,
|
|
label: {
|
|
...LABEL_BOXING_DEFAULTS5,
|
|
enabled: true,
|
|
fontFamily: { $ref: "fontFamily" },
|
|
fontSize: { $ref: "fontSize" },
|
|
fontWeight: { $ref: "fontWeight" },
|
|
color: { $ref: "textColor" },
|
|
spacing: 5,
|
|
maxWidth: 100
|
|
},
|
|
node: {
|
|
spacing: 8,
|
|
width: 10,
|
|
strokeWidth: { $isUserOption: ["./stroke", 2, 0] }
|
|
},
|
|
link: {
|
|
fillOpacity: 0.5,
|
|
strokeWidth: { $isUserOption: ["./stroke", 2, 0] },
|
|
tension: 0.4
|
|
}
|
|
},
|
|
legend: {
|
|
enabled: false,
|
|
toggleSeries: false
|
|
}
|
|
},
|
|
create: (ctx) => new ChordSeries(ctx)
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/series/cone-funnel/coneFunnelModule.ts
|
|
import { CartesianChartModule as CartesianChartModule8, VERSION as VERSION31 } from "ag-charts-community";
|
|
|
|
// packages/ag-charts-enterprise/src/series/funnel/funnelThemes.ts
|
|
import {
|
|
CARTESIAN_AXIS_TYPE as CARTESIAN_AXIS_TYPE9,
|
|
CARTESIAN_POSITION as CARTESIAN_POSITION5,
|
|
DEFAULT_SHADOW_COLOUR,
|
|
FILL_GRADIENT_LINEAR_SINGLE_DEFAULTS,
|
|
FILL_IMAGE_DEFAULTS as FILL_IMAGE_DEFAULTS7,
|
|
FILL_PATTERN_SINGLE_DEFAULTS,
|
|
LABEL_BOXING_DEFAULTS as LABEL_BOXING_DEFAULTS6
|
|
} from "ag-charts-core";
|
|
var isHorizontal = { $eq: [{ $path: ["/series/0/direction", void 0] }, "horizontal"] };
|
|
var labelOptions = { $clone: { $omit: [["placement", "spacing"], { $path: "/series/0/stageLabel" }] } };
|
|
var FUNNEL_SERIES_AXES = {
|
|
y: {
|
|
type: {
|
|
$if: [isHorizontal, CARTESIAN_AXIS_TYPE9.NUMBER, CARTESIAN_AXIS_TYPE9.CATEGORY]
|
|
},
|
|
position: {
|
|
$if: [
|
|
isHorizontal,
|
|
CARTESIAN_POSITION5.LEFT,
|
|
{
|
|
$if: [
|
|
{ $eq: [{ $path: ["/series/0/stageLabel/placement", void 0] }, "after"] },
|
|
CARTESIAN_POSITION5.RIGHT,
|
|
CARTESIAN_POSITION5.LEFT
|
|
]
|
|
}
|
|
]
|
|
},
|
|
label: {
|
|
$if: [isHorizontal, void 0, labelOptions]
|
|
}
|
|
},
|
|
x: {
|
|
type: {
|
|
$if: [isHorizontal, CARTESIAN_AXIS_TYPE9.CATEGORY, CARTESIAN_AXIS_TYPE9.NUMBER]
|
|
},
|
|
position: {
|
|
$if: [
|
|
isHorizontal,
|
|
{
|
|
$if: [
|
|
{ $eq: [{ $path: ["/series/0/stageLabel/placement", void 0] }, "before"] },
|
|
CARTESIAN_POSITION5.TOP,
|
|
CARTESIAN_POSITION5.BOTTOM
|
|
]
|
|
},
|
|
CARTESIAN_POSITION5.BOTTOM
|
|
]
|
|
},
|
|
label: {
|
|
$if: [isHorizontal, labelOptions, void 0]
|
|
}
|
|
}
|
|
};
|
|
var FUNNEL_SERIES_THEME = {
|
|
series: {
|
|
direction: "vertical",
|
|
strokeWidth: { $isUserOption: ["./strokes/0", 2, 0] },
|
|
spacingRatio: 0.25,
|
|
fills: {
|
|
$applyCycle: [
|
|
{ $size: { $path: ["./data", { $path: "/data" }] } },
|
|
[{ $path: ["/0", void 0, { $palette: "fills" }] }],
|
|
{
|
|
$applySwitch: [
|
|
{ $path: ["/type", void 0, { $value: "$1" }] },
|
|
{ $value: "$1" },
|
|
["gradient", FILL_GRADIENT_LINEAR_SINGLE_DEFAULTS],
|
|
["pattern", FILL_PATTERN_SINGLE_DEFAULTS],
|
|
["image", FILL_IMAGE_DEFAULTS7]
|
|
]
|
|
}
|
|
]
|
|
},
|
|
strokes: {
|
|
$applyCycle: [
|
|
{ $size: { $path: ["./data", { $path: "/data" }] } },
|
|
[{ $path: ["/0", void 0, { $palette: "strokes" }] }]
|
|
]
|
|
},
|
|
label: {
|
|
...LABEL_BOXING_DEFAULTS6,
|
|
enabled: true,
|
|
fontSize: { $ref: "fontSize" },
|
|
fontFamily: { $ref: "fontFamily" },
|
|
fontWeight: { $ref: "fontWeight" },
|
|
color: { $ref: "chartBackgroundColor" }
|
|
},
|
|
dropOff: {
|
|
enabled: true,
|
|
fillOpacity: 0.2,
|
|
strokeWidth: { $isUserOption: ["./stroke", 2, 0] }
|
|
},
|
|
shadow: {
|
|
enabled: false,
|
|
color: DEFAULT_SHADOW_COLOUR,
|
|
xOffset: 3,
|
|
yOffset: 3,
|
|
blur: 5
|
|
},
|
|
highlight: {
|
|
unhighlightedItem: {
|
|
opacity: 0.6
|
|
}
|
|
}
|
|
},
|
|
axes: {
|
|
[CARTESIAN_AXIS_TYPE9.NUMBER]: {
|
|
nice: false,
|
|
gridLine: {
|
|
enabled: false
|
|
},
|
|
crosshair: {
|
|
enabled: false
|
|
},
|
|
label: {
|
|
enabled: false
|
|
}
|
|
},
|
|
[CARTESIAN_AXIS_TYPE9.CATEGORY]: {
|
|
line: {
|
|
enabled: false
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/series/cone-funnel/coneFunnelSeries.ts
|
|
import {
|
|
_ModuleSupport as _ModuleSupport147
|
|
} from "ag-charts-community";
|
|
import { ChartAxisDirection as ChartAxisDirection42 } from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/series/funnel/baseFunnelSeries.ts
|
|
import {
|
|
_ModuleSupport as _ModuleSupport145
|
|
} from "ag-charts-community";
|
|
import { ChartAxisDirection as ChartAxisDirection41, SeriesZIndexMap } from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/series/funnel/funnelConnector.ts
|
|
import { _ModuleSupport as _ModuleSupport143 } from "ag-charts-community";
|
|
import { SceneChangeDetection as SceneChangeDetection7, lineDistanceSquared } from "ag-charts-core";
|
|
var { BBox: BBox18, Path: Path10 } = _ModuleSupport143;
|
|
var delta = 1e-6;
|
|
function pointsEq([ax, ay], [bx, by]) {
|
|
return Math.abs(ax - bx) <= delta && Math.abs(ay - by) <= delta;
|
|
}
|
|
var FunnelConnector = class extends Path10 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.x0 = 0;
|
|
this.y0 = 0;
|
|
this.x1 = 0;
|
|
this.y1 = 0;
|
|
this.x2 = 0;
|
|
this.y2 = 0;
|
|
this.x3 = 0;
|
|
this.y3 = 0;
|
|
}
|
|
get midPoint() {
|
|
const { x0, y0, x1, y1, x2, y2, x3, y3 } = this;
|
|
return {
|
|
x: (x0 + x1 + x2 + x3) / 4,
|
|
y: (y0 + y1 + y2 + y3) / 4
|
|
};
|
|
}
|
|
distanceSquared(x, y) {
|
|
if (this.containsPoint(x, y))
|
|
return 0;
|
|
const { x0, y0, x1, y1, x2, y2, x3, y3 } = this;
|
|
return Math.min(
|
|
lineDistanceSquared(x, y, x0, y0, x1, y1, Infinity),
|
|
lineDistanceSquared(x, y, x1, y1, x2, y2, Infinity),
|
|
lineDistanceSquared(x, y, x2, y2, x3, y3, Infinity),
|
|
lineDistanceSquared(x, y, x3, y3, x0, y0, Infinity)
|
|
);
|
|
}
|
|
computeBBox() {
|
|
const { x0, y0, x1, y1, x2, y2, x3, y3 } = this;
|
|
const x = Math.min(x0, x1, x2, x3);
|
|
const width = Math.max(x0, x1, x2, x3) - x;
|
|
const y = Math.min(y0, y1, y2, y3);
|
|
const height = Math.max(y0, y1, y2, y3) - y;
|
|
return new BBox18(x, y, width, height);
|
|
}
|
|
updatePath() {
|
|
const { path, x0, y0, x1, y1, x2, y2, x3, y3 } = this;
|
|
const points = [
|
|
[x0, y0],
|
|
[x1, y1],
|
|
[x2, y2],
|
|
[x3, y3]
|
|
];
|
|
path.clear();
|
|
let start;
|
|
let current;
|
|
for (const p of points) {
|
|
if (start != null && pointsEq(start, p) || current != null && pointsEq(current, p)) {
|
|
continue;
|
|
}
|
|
const [x, y] = p;
|
|
if (start == null) {
|
|
path.moveTo(x, y);
|
|
} else {
|
|
path.lineTo(x, y);
|
|
}
|
|
start ?? (start = p);
|
|
current = p;
|
|
}
|
|
path.closePath();
|
|
}
|
|
};
|
|
__decorateClass([
|
|
SceneChangeDetection7()
|
|
], FunnelConnector.prototype, "x0", 2);
|
|
__decorateClass([
|
|
SceneChangeDetection7()
|
|
], FunnelConnector.prototype, "y0", 2);
|
|
__decorateClass([
|
|
SceneChangeDetection7()
|
|
], FunnelConnector.prototype, "x1", 2);
|
|
__decorateClass([
|
|
SceneChangeDetection7()
|
|
], FunnelConnector.prototype, "y1", 2);
|
|
__decorateClass([
|
|
SceneChangeDetection7()
|
|
], FunnelConnector.prototype, "x2", 2);
|
|
__decorateClass([
|
|
SceneChangeDetection7()
|
|
], FunnelConnector.prototype, "y2", 2);
|
|
__decorateClass([
|
|
SceneChangeDetection7()
|
|
], FunnelConnector.prototype, "x3", 2);
|
|
__decorateClass([
|
|
SceneChangeDetection7()
|
|
], FunnelConnector.prototype, "y3", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/series/funnel/funnelUtil.ts
|
|
import { _ModuleSupport as _ModuleSupport144 } from "ag-charts-community";
|
|
var { NODE_UPDATE_STATE_TO_PHASE_MAPPING } = _ModuleSupport144;
|
|
function connectorStartingPosition(datum, _prevDatum, isVertical, _mode) {
|
|
const { x0, y0, x1, y1, x2, y2, x3, y3, opacity } = datum;
|
|
if (isVertical) {
|
|
return {
|
|
x0: (x0 + x3) / 2,
|
|
y0: (y0 + y3) / 2,
|
|
x1: (x1 + x2) / 2,
|
|
y1: (y1 + y2) / 2,
|
|
x2: (x1 + x2) / 2,
|
|
y2: (y1 + y2) / 2,
|
|
x3: (x0 + x3) / 2,
|
|
y3: (y0 + y3) / 2,
|
|
opacity
|
|
};
|
|
} else {
|
|
return {
|
|
x0: (x0 + x1) / 2,
|
|
y0: (y0 + y1) / 2,
|
|
x1: (x0 + x1) / 2,
|
|
y1: (y0 + y1) / 2,
|
|
x2: (x2 + x3) / 2,
|
|
y2: (y2 + y3) / 2,
|
|
x3: (x2 + x3) / 2,
|
|
y3: (y2 + y3) / 2,
|
|
opacity
|
|
};
|
|
}
|
|
}
|
|
function prepareConnectorAnimationFunctions(isVertical, mode) {
|
|
const isRemoved = (datum) => datum == null;
|
|
const fromFn = (connector, datum, status) => {
|
|
if (status === "updated" && isRemoved(datum)) {
|
|
status = "removed";
|
|
} else if (status === "updated" && isRemoved(connector.previousDatum)) {
|
|
status = "added";
|
|
}
|
|
let source;
|
|
if (status === "added" && connector.previousDatum == null && mode === "fade") {
|
|
source = { ...resetConnectorSelectionsFn(connector, datum), opacity: 0 };
|
|
} else if (status === "unknown" || status === "added") {
|
|
source = connectorStartingPosition(datum, connector.previousDatum, isVertical, mode);
|
|
} else {
|
|
source = {
|
|
x0: connector.x0,
|
|
y0: connector.y0,
|
|
x1: connector.x1,
|
|
y1: connector.y1,
|
|
x2: connector.x2,
|
|
y2: connector.y2,
|
|
x3: connector.x3,
|
|
y3: connector.y3,
|
|
opacity: connector.opacity
|
|
};
|
|
}
|
|
const phase = NODE_UPDATE_STATE_TO_PHASE_MAPPING[status];
|
|
return { ...source, phase };
|
|
};
|
|
const toFn = (connector, datum, status) => {
|
|
let source;
|
|
if (status === "removed" && connector.datum == null && mode === "fade") {
|
|
source = { ...resetConnectorSelectionsFn(connector, datum), opacity: 0 };
|
|
} else if (status === "removed" || isRemoved(datum)) {
|
|
source = connectorStartingPosition(datum, connector.previousDatum, isVertical, mode);
|
|
} else {
|
|
source = resetConnectorSelectionsFn(connector, datum);
|
|
}
|
|
return source;
|
|
};
|
|
return { fromFn, toFn };
|
|
}
|
|
function resetConnectorSelectionsFn(_node, datum) {
|
|
const { x0, y0, x1, y1, x2, y2, x3, y3, opacity } = datum;
|
|
return { x0, y0, x1, y1, x2, y2, x3, y3, opacity };
|
|
}
|
|
|
|
// packages/ag-charts-enterprise/src/series/funnel/baseFunnelSeries.ts
|
|
var {
|
|
SeriesNodePickMode: SeriesNodePickMode7,
|
|
valueProperty: valueProperty10,
|
|
keyProperty: keyProperty8,
|
|
updateLabelNode: updateLabelNode5,
|
|
SMALLEST_KEY_INTERVAL: SMALLEST_KEY_INTERVAL4,
|
|
LARGEST_KEY_INTERVAL: LARGEST_KEY_INTERVAL2,
|
|
diff: diff5,
|
|
fixNumericExtent: fixNumericExtent7,
|
|
seriesLabelFadeInAnimation: seriesLabelFadeInAnimation4,
|
|
resetMotion: resetMotion2,
|
|
resetLabelFn: resetLabelFn4,
|
|
animationValidation: animationValidation6,
|
|
computeBarFocusBounds: computeBarFocusBounds6,
|
|
Group: Group11,
|
|
Selection: Selection6,
|
|
PointerEvents: PointerEvents4,
|
|
motion: motion4,
|
|
checkCrisp: checkCrisp3,
|
|
createDatumId: createDatumId8
|
|
} = _ModuleSupport145;
|
|
var FunnelSeriesNodeEvent = class extends _ModuleSupport145.SeriesNodeEvent {
|
|
constructor(type, nativeEvent, datum, series) {
|
|
super(type, nativeEvent, datum, series);
|
|
this.xKey = series.properties.stageKey;
|
|
this.yKey = series.properties.valueKey;
|
|
}
|
|
};
|
|
var BaseFunnelSeries = class extends _ModuleSupport145.AbstractBarSeries {
|
|
constructor({
|
|
moduleCtx,
|
|
animationResetFns
|
|
}) {
|
|
super({
|
|
moduleCtx,
|
|
pickModes: [SeriesNodePickMode7.AXIS_ALIGNED, SeriesNodePickMode7.EXACT_SHAPE_MATCH],
|
|
propertyKeys: {
|
|
x: ["stageKey"],
|
|
y: ["valueKey"]
|
|
},
|
|
propertyNames: {
|
|
x: [],
|
|
y: []
|
|
},
|
|
categoryKey: "xValue",
|
|
datumSelectionGarbageCollection: false,
|
|
animationResetFns: {
|
|
datum: animationResetFns.datum,
|
|
label: resetLabelFn4
|
|
}
|
|
});
|
|
// @ts-expect-error xKey/yKey renamed
|
|
this.NodeEvent = FunnelSeriesNodeEvent;
|
|
this.connectorNodeGroup = this.contentGroup.appendChild(
|
|
new Group11({
|
|
name: `${this.id}-series-connectorNodes`,
|
|
zIndex: SeriesZIndexMap.BACKGROUND
|
|
})
|
|
);
|
|
this.connectorSelection = Selection6.select(
|
|
this.connectorNodeGroup,
|
|
() => this.connectionFactory()
|
|
);
|
|
this.connectorNodeGroup.pointerEvents = PointerEvents4.None;
|
|
}
|
|
get pickModeAxis() {
|
|
return "main-category";
|
|
}
|
|
setZIndex(zIndex) {
|
|
super.setZIndex(zIndex);
|
|
this.connectorNodeGroup.zIndex = [SeriesZIndexMap.BACKGROUND, zIndex];
|
|
return true;
|
|
}
|
|
isVertical() {
|
|
return !super.isVertical();
|
|
}
|
|
connectionFactory() {
|
|
return new FunnelConnector();
|
|
}
|
|
getKeyAxis(direction) {
|
|
if (direction === ChartAxisDirection41.X)
|
|
return this.properties.xKeyAxis;
|
|
if (direction === ChartAxisDirection41.Y)
|
|
return this.properties.yKeyAxis;
|
|
}
|
|
async processData(dataController) {
|
|
const { stageKey, valueKey } = this.properties;
|
|
const { visible, id: seriesId } = this;
|
|
const validation = (_value, _datum, index) => visible && this.ctx.legendManager.getItemEnabled({ seriesId, itemId: index });
|
|
const xScale = this.getCategoryAxis()?.scale;
|
|
const yScale = this.getValueAxis()?.scale;
|
|
const { isContinuousX, xScaleType, yScaleType } = this.getScaleInformation({ xScale, yScale });
|
|
const extraProps = [];
|
|
if (this.needsDataModelDiff() && this.processedData) {
|
|
extraProps.push(diff5(this.id, this.processedData));
|
|
}
|
|
if (!this.ctx.animationManager.isSkipped()) {
|
|
extraProps.push(animationValidation6());
|
|
}
|
|
const visibleProps = this.visible ? {} : { forceValue: 0 };
|
|
const allowNullKey = this.properties.allowNullKeys ?? false;
|
|
const { processedData } = await this.requestDataModel(dataController, this.data, {
|
|
props: [
|
|
keyProperty8(stageKey, xScaleType, { id: "xValue", allowNullKey }),
|
|
valueProperty10(valueKey, yScaleType, { id: `yValue`, ...visibleProps, validation, invalidValue: 0 }),
|
|
...isContinuousX ? [SMALLEST_KEY_INTERVAL4, LARGEST_KEY_INTERVAL2] : [],
|
|
...extraProps
|
|
],
|
|
groupByKeys: false
|
|
});
|
|
this.smallestDataInterval = processedData.reduced?.smallestKeyInterval;
|
|
this.largestDataInterval = processedData.reduced?.largestKeyInterval;
|
|
this.animationState.transition("updateData");
|
|
}
|
|
getSeriesDomain(direction) {
|
|
const {
|
|
processedData,
|
|
dataModel,
|
|
id: seriesId,
|
|
ctx: { legendManager }
|
|
} = this;
|
|
if (!processedData || !dataModel)
|
|
return { domain: [] };
|
|
const {
|
|
keys: [keys]
|
|
} = processedData.domain;
|
|
if (direction === this.getCategoryDirection()) {
|
|
const keyDef = dataModel.resolveProcessedDataDefById(this, `xValue`);
|
|
if (keyDef?.def.type === "key" && keyDef?.def.valueType === "category") {
|
|
if (!this.hasData)
|
|
return { domain: [] };
|
|
const domain = keys.filter((_key, index) => legendManager.getItemEnabled({ seriesId, itemId: index }));
|
|
const sortMetadata = dataModel.getKeySortMetadata(this, "xValue", processedData);
|
|
return { domain, sortMetadata };
|
|
}
|
|
return { domain: this.padBandExtent(keys) };
|
|
} else {
|
|
const yExtent = this.domainForClippedRange(direction, ["yValue"], "xValue");
|
|
const maxExtent = Math.max(...yExtent);
|
|
const fixedYExtent = [-maxExtent, maxExtent];
|
|
return { domain: fixNumericExtent7(fixedYExtent) };
|
|
}
|
|
}
|
|
getSeriesRange(_direction, _visibleRange) {
|
|
return [Number.NaN, Number.NaN];
|
|
}
|
|
createNodeData() {
|
|
const {
|
|
hasData,
|
|
data,
|
|
dataModel,
|
|
processedData,
|
|
id: seriesId,
|
|
ctx: { legendManager }
|
|
} = this;
|
|
const xAxis = this.getCategoryAxis();
|
|
const yAxis = this.getValueAxis();
|
|
if (!(hasData && data && xAxis && yAxis && dataModel && processedData?.type === "ungrouped")) {
|
|
return;
|
|
}
|
|
const xScale = xAxis.scale;
|
|
const yScale = yAxis.scale;
|
|
const barAlongX = this.getBarDirection() === ChartAxisDirection41.X;
|
|
const { stageKey, valueKey } = this.properties;
|
|
const itemId = `${valueKey}`;
|
|
const context = {
|
|
itemId,
|
|
nodeData: [],
|
|
labelData: [],
|
|
connectorData: [],
|
|
scales: this.calculateScaling(),
|
|
groupScale: this.getScaling(this.ctx.seriesStateManager.getGroupScale(this)),
|
|
visible: this.visible
|
|
};
|
|
const isVisible = this.visible;
|
|
if (!isVisible)
|
|
return context;
|
|
const xValues = dataModel.resolveKeysById(this, "xValue", processedData);
|
|
const yValues = dataModel.resolveColumnById(this, `yValue`, processedData);
|
|
const { groupOffset, barOffset, barWidth } = this.getBarDimensions();
|
|
const crisp = checkCrisp3(
|
|
xAxis?.scale,
|
|
xAxis?.visibleRange,
|
|
this.smallestDataInterval,
|
|
this.largestDataInterval
|
|
);
|
|
let previousConnection;
|
|
const rawData = processedData.dataSources.get(this.id)?.data ?? [];
|
|
for (const [datumIndex, datum] of rawData.entries()) {
|
|
const visible = isVisible && legendManager.getItemEnabled({ seriesId, itemId: datumIndex });
|
|
const xDatum = xValues[datumIndex];
|
|
if (xDatum === void 0 && !this.properties.allowNullKeys)
|
|
continue;
|
|
const xConverted = xScale.convert(xDatum);
|
|
if (!Number.isFinite(xConverted))
|
|
continue;
|
|
const x = Math.round(xConverted) + groupOffset + barOffset;
|
|
const yDatum = yValues[datumIndex];
|
|
const yNegative = Math.round(yScale.convert(-yDatum));
|
|
const yPositive = Math.round(yScale.convert(yDatum));
|
|
const style = this.getItemStyle({ datum, datumIndex }, false);
|
|
const barHeight = Math.max(style.strokeWidth ?? 0, Math.abs(yPositive - yNegative));
|
|
const rect = {
|
|
x: barAlongX ? Math.min(yPositive, yNegative) : x,
|
|
y: barAlongX ? x : Math.min(yPositive, yNegative),
|
|
width: barAlongX ? barHeight : barWidth,
|
|
height: barAlongX ? barWidth : barHeight
|
|
};
|
|
const nodeMidPoint = {
|
|
x: rect.x + rect.width / 2,
|
|
y: rect.y + rect.height / 2
|
|
};
|
|
const labelData = this.createLabelData({
|
|
datumIndex,
|
|
rect,
|
|
barAlongX,
|
|
yDatum,
|
|
datum,
|
|
visible
|
|
});
|
|
const nodeDatum = {
|
|
index: datumIndex,
|
|
series: this,
|
|
datum,
|
|
datumIndex,
|
|
xValue: xDatum,
|
|
yValue: yDatum,
|
|
xKey: stageKey,
|
|
yKey: valueKey,
|
|
x: rect.x,
|
|
y: rect.y,
|
|
width: rect.width,
|
|
height: rect.height,
|
|
midPoint: nodeMidPoint,
|
|
crisp,
|
|
label: labelData,
|
|
visible
|
|
};
|
|
context.nodeData.push(nodeDatum);
|
|
if (labelData != null) {
|
|
context.labelData.push(labelData);
|
|
}
|
|
if (previousConnection != null) {
|
|
const prevRect = previousConnection.rect;
|
|
const startNodeDatum = previousConnection.nodeDatum;
|
|
const startDatumIndex = previousConnection.datumIndex;
|
|
if (barAlongX) {
|
|
context.connectorData.push({
|
|
datum: startNodeDatum,
|
|
datumIndex: startDatumIndex,
|
|
x0: prevRect.x,
|
|
y0: prevRect.y + prevRect.height,
|
|
x1: prevRect.x + prevRect.width,
|
|
y1: prevRect.y + prevRect.height,
|
|
x2: rect.x + rect.width,
|
|
y2: rect.y,
|
|
x3: rect.x,
|
|
y3: rect.y,
|
|
opacity: 1
|
|
});
|
|
} else {
|
|
context.connectorData.push({
|
|
datum: startNodeDatum,
|
|
datumIndex: startDatumIndex,
|
|
x0: prevRect.x + prevRect.width,
|
|
y0: prevRect.y,
|
|
x1: rect.x,
|
|
y1: rect.y,
|
|
x2: rect.x,
|
|
y2: rect.y + rect.height,
|
|
x3: prevRect.x + prevRect.width,
|
|
y3: prevRect.y + prevRect.height,
|
|
opacity: 1
|
|
});
|
|
}
|
|
}
|
|
if (visible) {
|
|
previousConnection = {
|
|
itemId,
|
|
rect,
|
|
nodeDatum,
|
|
datumIndex
|
|
};
|
|
}
|
|
}
|
|
return context;
|
|
}
|
|
updateNodes(seriesHighlighted, nodeRefresh) {
|
|
super.updateNodes(seriesHighlighted, nodeRefresh);
|
|
const { connectorSelection } = this;
|
|
const connectorData = this.contextNodeData?.connectorData ?? [];
|
|
this.connectorSelection = this.updateConnectorSelection({ connectorSelection, connectorData });
|
|
this.updateConnectorNodes({ connectorSelection });
|
|
}
|
|
updateDatumSelection(opts) {
|
|
const { nodeData, datumSelection } = opts;
|
|
const data = nodeData ?? [];
|
|
return datumSelection.update(data, void 0, (datum) => this.getDatumId(datum));
|
|
}
|
|
updateConnectorSelection(opts) {
|
|
const { connectorData, connectorSelection } = opts;
|
|
return connectorSelection.update(
|
|
this.connectorEnabled() ? connectorData : [],
|
|
void 0,
|
|
(connector) => this.getDatumId(connector.datum)
|
|
);
|
|
}
|
|
updateConnectorNodes(opts) {
|
|
const fillBBox = this.getShapeFillBBox();
|
|
opts.connectorSelection.each((connector, datum) => {
|
|
const { fill, fillOpacity, stroke: stroke3, strokeOpacity, strokeWidth, lineDash, lineDashOffset } = this.connectorStyle(datum.datumIndex);
|
|
connector.setProperties(resetConnectorSelectionsFn(connector, datum));
|
|
connector.setStyleProperties(
|
|
{
|
|
fill,
|
|
stroke: stroke3,
|
|
fillOpacity,
|
|
strokeOpacity,
|
|
strokeWidth,
|
|
lineDash,
|
|
lineDashOffset
|
|
},
|
|
fillBBox
|
|
);
|
|
});
|
|
}
|
|
updateLabelSelection(opts) {
|
|
const labelData = this.properties.label.enabled ? opts.labelData : [];
|
|
return opts.labelSelection.update(labelData, (text2) => {
|
|
text2.pointerEvents = PointerEvents4.None;
|
|
});
|
|
}
|
|
updateLabelNodes(opts) {
|
|
const params = {
|
|
stageKey: this.properties.stageKey,
|
|
valueKey: this.properties.valueKey
|
|
};
|
|
const activeHighlight = this.ctx.highlightManager?.getActiveHighlight();
|
|
const { isHighlight = false, labelSelection } = opts;
|
|
labelSelection.each((textNode, datum) => {
|
|
const highlightStyle = this.getHighlightStyle(isHighlight, datum.datumIndex);
|
|
textNode.visible = datum.visible || isHighlight;
|
|
textNode.fillOpacity = highlightStyle.opacity ?? 1;
|
|
textNode.opacity = highlightStyle.opacity ?? 1;
|
|
updateLabelNode5(this, textNode, params, this.properties.label, datum, isHighlight, activeHighlight);
|
|
});
|
|
}
|
|
getHighlightLabelData(_labelData, highlightedItem) {
|
|
if (highlightedItem.label) {
|
|
return [{ ...highlightedItem.label }];
|
|
}
|
|
return void 0;
|
|
}
|
|
getTooltipContent(datumIndex) {
|
|
const { id: seriesId, dataModel, processedData, properties } = this;
|
|
const { stageKey, valueKey, tooltip, legendItemName } = properties;
|
|
const xAxis = this.getCategoryAxis();
|
|
const yAxis = this.getValueAxis();
|
|
if (!dataModel || !processedData || !xAxis || !yAxis)
|
|
return;
|
|
const datum = processedData.dataSources.get(this.id)?.data[datumIndex];
|
|
const xValue = dataModel.resolveKeysById(this, "xValue", processedData)[datumIndex];
|
|
const yValue = dataModel.resolveColumnById(this, `yValue`, processedData)[datumIndex];
|
|
const allowNullKeys = this.properties.allowNullKeys ?? false;
|
|
if (xValue === void 0 && !allowNullKeys)
|
|
return;
|
|
return this.formatTooltipWithContext(
|
|
tooltip,
|
|
{
|
|
symbol: this.legendItemSymbol(datumIndex),
|
|
data: [
|
|
{
|
|
label: this.getAxisValueText(xAxis, "tooltip", xValue, datum, stageKey, legendItemName),
|
|
value: this.getAxisValueText(yAxis, "tooltip", yValue, datum, valueKey, legendItemName)
|
|
}
|
|
]
|
|
},
|
|
{ seriesId, datum, title: stageKey, stageKey, valueKey, ...this.tooltipStyle(datum, datumIndex) }
|
|
);
|
|
}
|
|
resetAllAnimation(data) {
|
|
super.resetAllAnimation(data);
|
|
resetMotion2([this.connectorSelection], resetConnectorSelectionsFn);
|
|
}
|
|
animateEmptyUpdateReady({ labelSelection }) {
|
|
const { connectorSelection } = this;
|
|
const isVertical = this.isVertical();
|
|
const mode = "normal";
|
|
const connectorFns = prepareConnectorAnimationFunctions(isVertical, mode);
|
|
motion4.fromToMotion(this.id, "connectors", this.ctx.animationManager, [connectorSelection], connectorFns);
|
|
seriesLabelFadeInAnimation4(this, "labels", this.ctx.animationManager, labelSelection);
|
|
}
|
|
animateWaitingUpdateReady(data) {
|
|
const { labelSelection: labelSelections } = data;
|
|
this.ctx.animationManager.stopByAnimationGroupId(this.id);
|
|
seriesLabelFadeInAnimation4(this, "labels", this.ctx.animationManager, labelSelections);
|
|
}
|
|
getDatumId(datum) {
|
|
return createDatumId8(datum.xValue);
|
|
}
|
|
isLabelEnabled() {
|
|
return this.properties.label.enabled;
|
|
}
|
|
computeFocusBounds({ datumIndex }) {
|
|
return computeBarFocusBounds6(this, this.contextNodeData?.nodeData[datumIndex]);
|
|
}
|
|
legendItemSymbol(datumIndex) {
|
|
const { strokeWidth, fillOpacity, strokeOpacity, lineDash, lineDashOffset, fill, stroke: stroke3 } = this.properties.getStyle(datumIndex);
|
|
return {
|
|
marker: {
|
|
fill,
|
|
fillOpacity,
|
|
stroke: stroke3,
|
|
strokeWidth,
|
|
strokeOpacity,
|
|
lineDash,
|
|
lineDashOffset
|
|
}
|
|
};
|
|
}
|
|
getLegendData(legendType) {
|
|
const {
|
|
id: seriesId,
|
|
processedData,
|
|
dataModel,
|
|
ctx: { legendManager },
|
|
visible
|
|
} = this;
|
|
if (!dataModel || !processedData || legendType !== "category") {
|
|
return [];
|
|
}
|
|
const { showInLegend } = this.properties;
|
|
const xValues = dataModel.resolveKeysById(this, "xValue", processedData);
|
|
return (processedData.dataSources.get(this.id)?.data ?? []).map((datum, datumIndex) => {
|
|
const stageValue = xValues[datumIndex];
|
|
const allowNullKeys = this.properties.allowNullKeys ?? false;
|
|
if (stageValue == null && !allowNullKeys)
|
|
return;
|
|
return {
|
|
legendType: "category",
|
|
id: seriesId,
|
|
datum,
|
|
itemId: datumIndex,
|
|
seriesId,
|
|
enabled: visible && legendManager.getItemEnabled({ seriesId, itemId: datumIndex }),
|
|
label: { text: String(stageValue) },
|
|
symbol: this.legendItemSymbol(datumIndex),
|
|
skipAnimations: true,
|
|
hideInLegend: !showInLegend
|
|
};
|
|
}).filter((datum) => datum != null);
|
|
}
|
|
hasItemStylers() {
|
|
return this.properties.itemStyler != null || this.properties.label.itemStyler != null;
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/series/cone-funnel/coneFunnelProperties.ts
|
|
import { _ModuleSupport as _ModuleSupport146 } from "ag-charts-community";
|
|
import { Property as Property70 } from "ag-charts-core";
|
|
var { Label: Label7, AbstractBarSeriesProperties: AbstractBarSeriesProperties5, makeSeriesTooltip: makeSeriesTooltip9, AxisLabel: AxisLabel3 } = _ModuleSupport146;
|
|
var ConeFunnelSeriesLabel = class extends Label7 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.spacing = 0;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property70
|
|
], ConeFunnelSeriesLabel.prototype, "placement", 2);
|
|
__decorateClass([
|
|
Property70
|
|
], ConeFunnelSeriesLabel.prototype, "spacing", 2);
|
|
var ConeFunnelSeriesStageLabel = class extends AxisLabel3 {
|
|
};
|
|
__decorateClass([
|
|
Property70
|
|
], ConeFunnelSeriesStageLabel.prototype, "placement", 2);
|
|
var ConeFunnelProperties = class extends AbstractBarSeriesProperties5 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.fills = [];
|
|
this.fillOpacity = 1;
|
|
this.strokes = [];
|
|
this.strokeWidth = 1;
|
|
this.strokeOpacity = 1;
|
|
this.lineDash = [0];
|
|
this.lineDashOffset = 0;
|
|
this.label = new ConeFunnelSeriesLabel();
|
|
this.stageLabel = new ConeFunnelSeriesStageLabel();
|
|
this.tooltip = makeSeriesTooltip9();
|
|
}
|
|
getStyle(index) {
|
|
const { fills, strokes, fillOpacity, strokeWidth, strokeOpacity, lineDash, lineDashOffset } = this;
|
|
return {
|
|
fill: fills[index],
|
|
fillOpacity,
|
|
stroke: strokes[index],
|
|
strokeWidth,
|
|
strokeOpacity,
|
|
lineDash,
|
|
lineDashOffset,
|
|
opacity: 1
|
|
};
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property70
|
|
], ConeFunnelProperties.prototype, "stageKey", 2);
|
|
__decorateClass([
|
|
Property70
|
|
], ConeFunnelProperties.prototype, "valueKey", 2);
|
|
__decorateClass([
|
|
Property70
|
|
], ConeFunnelProperties.prototype, "fills", 2);
|
|
__decorateClass([
|
|
Property70
|
|
], ConeFunnelProperties.prototype, "fillOpacity", 2);
|
|
__decorateClass([
|
|
Property70
|
|
], ConeFunnelProperties.prototype, "strokes", 2);
|
|
__decorateClass([
|
|
Property70
|
|
], ConeFunnelProperties.prototype, "strokeWidth", 2);
|
|
__decorateClass([
|
|
Property70
|
|
], ConeFunnelProperties.prototype, "strokeOpacity", 2);
|
|
__decorateClass([
|
|
Property70
|
|
], ConeFunnelProperties.prototype, "lineDash", 2);
|
|
__decorateClass([
|
|
Property70
|
|
], ConeFunnelProperties.prototype, "lineDashOffset", 2);
|
|
__decorateClass([
|
|
Property70
|
|
], ConeFunnelProperties.prototype, "label", 2);
|
|
__decorateClass([
|
|
Property70
|
|
], ConeFunnelProperties.prototype, "stageLabel", 2);
|
|
__decorateClass([
|
|
Property70
|
|
], ConeFunnelProperties.prototype, "tooltip", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/series/cone-funnel/coneFunnelUtil.ts
|
|
function resetLineSelectionsFn(_node, { x, y, width, height, opacity }) {
|
|
return { x1: x, y1: y, x2: x + width, y2: y + height, opacity: opacity ?? 1 };
|
|
}
|
|
|
|
// packages/ag-charts-enterprise/src/series/cone-funnel/coneFunnelSeries.ts
|
|
var { Line: Line5 } = _ModuleSupport147;
|
|
var ConeFunnelSeries = class extends BaseFunnelSeries {
|
|
constructor(moduleCtx) {
|
|
super({
|
|
moduleCtx,
|
|
animationResetFns: {
|
|
datum: resetLineSelectionsFn
|
|
}
|
|
});
|
|
this.properties = new ConeFunnelProperties();
|
|
}
|
|
get hasData() {
|
|
const {
|
|
id: seriesId,
|
|
ctx: { legendManager }
|
|
} = this;
|
|
const visibleItems = this.data?.data.reduce(
|
|
(accum, _, datumIndex) => accum + (legendManager.getItemEnabled({ seriesId, itemId: datumIndex }) ? 1 : 0),
|
|
0
|
|
);
|
|
return visibleItems != null && visibleItems > 1;
|
|
}
|
|
getBandScalePadding() {
|
|
return { inner: 1, outer: 0 };
|
|
}
|
|
connectorEnabled() {
|
|
return true;
|
|
}
|
|
getItemStyle({ datumIndex }, _isHighlight) {
|
|
return this.properties.getStyle(datumIndex);
|
|
}
|
|
connectorStyle(index) {
|
|
return this.properties.getStyle(index);
|
|
}
|
|
nodeFactory() {
|
|
return new Line5();
|
|
}
|
|
createLabelData({
|
|
datumIndex,
|
|
rect,
|
|
barAlongX,
|
|
yDatum,
|
|
datum,
|
|
visible
|
|
}) {
|
|
const { stageKey, valueKey, label } = this.properties;
|
|
const { spacing, placement } = label;
|
|
if (!label.enabled)
|
|
return;
|
|
let x;
|
|
let y;
|
|
let textAlign;
|
|
let textBaseline;
|
|
if (barAlongX) {
|
|
x = rect.x + rect.width / 2;
|
|
textAlign = "center";
|
|
switch (placement) {
|
|
case "before":
|
|
y = rect.y - spacing;
|
|
textBaseline = "bottom";
|
|
break;
|
|
case "after":
|
|
y = rect.y + rect.height + spacing;
|
|
textBaseline = "top";
|
|
break;
|
|
default:
|
|
y = rect.y + rect.height / 2;
|
|
textBaseline = "middle";
|
|
}
|
|
} else {
|
|
y = rect.y + rect.height / 2;
|
|
textBaseline = "middle";
|
|
switch (placement) {
|
|
case "before":
|
|
x = rect.x - spacing;
|
|
textAlign = "right";
|
|
break;
|
|
case "after":
|
|
x = rect.x + rect.width + spacing;
|
|
textAlign = "left";
|
|
break;
|
|
default:
|
|
x = rect.x + rect.width / 2;
|
|
textAlign = "center";
|
|
}
|
|
}
|
|
const yDomain = this.getSeriesDomain(ChartAxisDirection42.Y).domain;
|
|
const text2 = this.getLabelText(
|
|
yDatum,
|
|
datum,
|
|
valueKey,
|
|
"y",
|
|
yDomain,
|
|
label,
|
|
{ itemId: valueKey, value: yDatum, datum, stageKey, valueKey }
|
|
);
|
|
return {
|
|
x,
|
|
y,
|
|
textAlign,
|
|
textBaseline,
|
|
text: text2,
|
|
itemId: valueKey,
|
|
datum,
|
|
datumIndex,
|
|
series: this,
|
|
visible
|
|
};
|
|
}
|
|
updateDatumNodes(opts) {
|
|
const highlightStyle = this.getHighlightStyle(opts.isHighlight);
|
|
opts.datumSelection.each((line, datum) => {
|
|
line.setProperties(resetLineSelectionsFn(line, datum));
|
|
line.stroke = highlightStyle?.stroke;
|
|
line.strokeWidth = highlightStyle?.strokeWidth ?? 0;
|
|
line.strokeOpacity = highlightStyle?.strokeOpacity ?? 1;
|
|
line.lineDash = highlightStyle?.lineDash;
|
|
line.lineDashOffset = highlightStyle?.lineDashOffset ?? 0;
|
|
line.opacity = highlightStyle?.opacity ?? 1;
|
|
});
|
|
}
|
|
tooltipStyle(_datum, datumIndex) {
|
|
const { fill, stroke: stroke3, fillOpacity, strokeOpacity, strokeWidth, lineDash, lineDashOffset } = this.properties.getStyle(datumIndex);
|
|
return {
|
|
fill,
|
|
fillOpacity,
|
|
stroke: stroke3,
|
|
strokeOpacity,
|
|
strokeWidth,
|
|
lineDash,
|
|
lineDashOffset
|
|
};
|
|
}
|
|
hasItemStylers() {
|
|
return this.properties.label.itemStyler != null;
|
|
}
|
|
};
|
|
ConeFunnelSeries.className = "ConeFunnelSeries";
|
|
ConeFunnelSeries.type = "cone-funnel";
|
|
|
|
// packages/ag-charts-enterprise/src/series/cone-funnel/coneFunnelSeriesOptionsDef.ts
|
|
import { _ModuleSupport as _ModuleSupport148 } from "ag-charts-community";
|
|
import { commonSeriesOptionsDefs as commonSeriesOptionsDefs9, constant as constant9, required as required9, string as string11, without as without3 } from "ag-charts-core";
|
|
var { coneFunnelSeriesThemeableOptionsDef } = _ModuleSupport148;
|
|
var coneFunnelSeriesOptionsDef = {
|
|
...without3(commonSeriesOptionsDefs9, ["showInLegend"]),
|
|
...coneFunnelSeriesThemeableOptionsDef,
|
|
type: required9(constant9("cone-funnel")),
|
|
stageKey: required9(string11),
|
|
valueKey: required9(string11)
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/series/cone-funnel/coneFunnelThemes.ts
|
|
import {
|
|
CARTESIAN_AXIS_TYPE as CARTESIAN_AXIS_TYPE10,
|
|
FILL_GRADIENT_LINEAR_SINGLE_DEFAULTS as FILL_GRADIENT_LINEAR_SINGLE_DEFAULTS2,
|
|
FILL_IMAGE_DEFAULTS as FILL_IMAGE_DEFAULTS8,
|
|
FILL_PATTERN_SINGLE_DEFAULTS as FILL_PATTERN_SINGLE_DEFAULTS2,
|
|
LABEL_BOXING_DEFAULTS as LABEL_BOXING_DEFAULTS7,
|
|
SAFE_RANGE2_OPERATION as SAFE_RANGE2_OPERATION2
|
|
} from "ag-charts-core";
|
|
var CONE_FUNNEL_SERIES_THEME = {
|
|
series: {
|
|
direction: "vertical",
|
|
fills: {
|
|
$applyCycle: [
|
|
{ $size: { $path: ["./data", { $path: "/data" }] } },
|
|
{
|
|
$if: [
|
|
{ $eq: [{ $palette: "type" }, "inbuilt"] },
|
|
{ $palette: "secondSequentialColors" },
|
|
SAFE_RANGE2_OPERATION2
|
|
]
|
|
},
|
|
{
|
|
$applySwitch: [
|
|
{ $path: ["/type", void 0, { $value: "$1" }] },
|
|
{ $value: "$1" },
|
|
["gradient", FILL_GRADIENT_LINEAR_SINGLE_DEFAULTS2],
|
|
["pattern", FILL_PATTERN_SINGLE_DEFAULTS2],
|
|
["image", FILL_IMAGE_DEFAULTS8]
|
|
]
|
|
}
|
|
]
|
|
},
|
|
strokes: {
|
|
$applyCycle: [
|
|
{ $size: { $path: ["./data", { $path: "/data" }] } },
|
|
{
|
|
$if: [
|
|
{ $eq: [{ $palette: "type" }, "inbuilt"] },
|
|
{ $palette: "secondSequentialColors" },
|
|
SAFE_RANGE2_OPERATION2
|
|
]
|
|
}
|
|
]
|
|
},
|
|
strokeWidth: { $isUserOption: ["./strokes/0", 2, 0] },
|
|
label: {
|
|
...LABEL_BOXING_DEFAULTS7,
|
|
enabled: true,
|
|
fontSize: { $ref: "fontSize" },
|
|
fontFamily: { $ref: "fontFamily" },
|
|
fontWeight: { $ref: "fontWeight" },
|
|
color: { $ref: "textColor" },
|
|
placement: "before",
|
|
spacing: 4
|
|
},
|
|
tooltip: {
|
|
range: { $path: ["/tooltip/range", "nearest"] }
|
|
},
|
|
highlight: {
|
|
highlightedItem: {
|
|
stroke: `rgba(0, 0, 0, 0.4)`,
|
|
strokeWidth: 2
|
|
}
|
|
}
|
|
},
|
|
seriesArea: {
|
|
padding: {
|
|
top: 20,
|
|
bottom: 20
|
|
}
|
|
},
|
|
axes: {
|
|
[CARTESIAN_AXIS_TYPE10.NUMBER]: {
|
|
nice: false,
|
|
gridLine: {
|
|
enabled: false
|
|
},
|
|
crosshair: {
|
|
enabled: false
|
|
},
|
|
label: {
|
|
enabled: false
|
|
}
|
|
},
|
|
[CARTESIAN_AXIS_TYPE10.CATEGORY]: {
|
|
line: {
|
|
enabled: false
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/series/cone-funnel/coneFunnelModule.ts
|
|
var ConeFunnelSeriesModule = {
|
|
type: "series",
|
|
name: "cone-funnel",
|
|
chartType: "cartesian",
|
|
enterprise: true,
|
|
solo: true,
|
|
version: VERSION31,
|
|
dependencies: [CartesianChartModule8],
|
|
options: coneFunnelSeriesOptionsDef,
|
|
defaultAxes: FUNNEL_SERIES_AXES,
|
|
themeTemplate: CONE_FUNNEL_SERIES_THEME,
|
|
create: (ctx) => new ConeFunnelSeries(ctx)
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/series/funnel/funnelModule.ts
|
|
import { CartesianChartModule as CartesianChartModule9, VERSION as VERSION32 } from "ag-charts-community";
|
|
|
|
// packages/ag-charts-enterprise/src/series/funnel/funnelSeries.ts
|
|
import {
|
|
_ModuleSupport as _ModuleSupport150
|
|
} from "ag-charts-community";
|
|
import { ChartAxisDirection as ChartAxisDirection43, mergeDefaults as mergeDefaults11 } from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/series/funnel/funnelProperties.ts
|
|
import { _ModuleSupport as _ModuleSupport149 } from "ag-charts-community";
|
|
import { BaseProperties as BaseProperties31, Property as Property71 } from "ag-charts-core";
|
|
var { Label: Label8, DropShadow: DropShadow4, AbstractBarSeriesProperties: AbstractBarSeriesProperties6, makeSeriesTooltip: makeSeriesTooltip10, AxisLabel: AxisLabel4 } = _ModuleSupport149;
|
|
var FunnelSeriesLabel = class extends Label8 {
|
|
};
|
|
var FunnelSeriesStageLabel = class extends AxisLabel4 {
|
|
};
|
|
__decorateClass([
|
|
Property71
|
|
], FunnelSeriesStageLabel.prototype, "placement", 2);
|
|
var FunnelDropOff = class extends BaseProperties31 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.enabled = true;
|
|
this.fill = void 0;
|
|
this.fillOpacity = 1;
|
|
this.strokeWidth = 1;
|
|
this.strokeOpacity = 1;
|
|
this.lineDash = [0];
|
|
this.lineDashOffset = 0;
|
|
}
|
|
getStyle() {
|
|
const { fill, stroke: stroke3, fillOpacity, strokeWidth, strokeOpacity, lineDash, lineDashOffset } = this;
|
|
return {
|
|
fill,
|
|
fillOpacity,
|
|
stroke: stroke3,
|
|
strokeWidth,
|
|
strokeOpacity,
|
|
lineDash,
|
|
lineDashOffset,
|
|
opacity: 1
|
|
};
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property71
|
|
], FunnelDropOff.prototype, "enabled", 2);
|
|
__decorateClass([
|
|
Property71
|
|
], FunnelDropOff.prototype, "fill", 2);
|
|
__decorateClass([
|
|
Property71
|
|
], FunnelDropOff.prototype, "fillOpacity", 2);
|
|
__decorateClass([
|
|
Property71
|
|
], FunnelDropOff.prototype, "stroke", 2);
|
|
__decorateClass([
|
|
Property71
|
|
], FunnelDropOff.prototype, "strokeWidth", 2);
|
|
__decorateClass([
|
|
Property71
|
|
], FunnelDropOff.prototype, "strokeOpacity", 2);
|
|
__decorateClass([
|
|
Property71
|
|
], FunnelDropOff.prototype, "lineDash", 2);
|
|
__decorateClass([
|
|
Property71
|
|
], FunnelDropOff.prototype, "lineDashOffset", 2);
|
|
var FunnelProperties = class extends AbstractBarSeriesProperties6 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.fills = [];
|
|
this.fillOpacity = 1;
|
|
this.strokes = [];
|
|
this.strokeWidth = 1;
|
|
this.strokeOpacity = 1;
|
|
this.lineDash = [0];
|
|
this.lineDashOffset = 0;
|
|
this.spacingRatio = 0;
|
|
this.dropOff = new FunnelDropOff();
|
|
this.shadow = new DropShadow4().set({ enabled: false });
|
|
this.label = new FunnelSeriesLabel();
|
|
this.stageLabel = new FunnelSeriesStageLabel();
|
|
this.tooltip = makeSeriesTooltip10();
|
|
}
|
|
getStyle(index) {
|
|
const { fills, strokes, fillOpacity, strokeWidth, strokeOpacity, lineDash, lineDashOffset } = this;
|
|
return {
|
|
fill: fills[index],
|
|
fillOpacity,
|
|
stroke: strokes[index],
|
|
strokeWidth,
|
|
strokeOpacity,
|
|
lineDash,
|
|
lineDashOffset,
|
|
opacity: 1
|
|
};
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property71
|
|
], FunnelProperties.prototype, "stageKey", 2);
|
|
__decorateClass([
|
|
Property71
|
|
], FunnelProperties.prototype, "valueKey", 2);
|
|
__decorateClass([
|
|
Property71
|
|
], FunnelProperties.prototype, "fills", 2);
|
|
__decorateClass([
|
|
Property71
|
|
], FunnelProperties.prototype, "fillOpacity", 2);
|
|
__decorateClass([
|
|
Property71
|
|
], FunnelProperties.prototype, "strokes", 2);
|
|
__decorateClass([
|
|
Property71
|
|
], FunnelProperties.prototype, "strokeWidth", 2);
|
|
__decorateClass([
|
|
Property71
|
|
], FunnelProperties.prototype, "strokeOpacity", 2);
|
|
__decorateClass([
|
|
Property71
|
|
], FunnelProperties.prototype, "lineDash", 2);
|
|
__decorateClass([
|
|
Property71
|
|
], FunnelProperties.prototype, "lineDashOffset", 2);
|
|
__decorateClass([
|
|
Property71
|
|
], FunnelProperties.prototype, "spacingRatio", 2);
|
|
__decorateClass([
|
|
Property71
|
|
], FunnelProperties.prototype, "itemStyler", 2);
|
|
__decorateClass([
|
|
Property71
|
|
], FunnelProperties.prototype, "dropOff", 2);
|
|
__decorateClass([
|
|
Property71
|
|
], FunnelProperties.prototype, "shadow", 2);
|
|
__decorateClass([
|
|
Property71
|
|
], FunnelProperties.prototype, "label", 2);
|
|
__decorateClass([
|
|
Property71
|
|
], FunnelProperties.prototype, "stageLabel", 2);
|
|
__decorateClass([
|
|
Property71
|
|
], FunnelProperties.prototype, "tooltip", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/series/funnel/funnelSeries.ts
|
|
var { resetBarSelectionsFn: resetBarSelectionsFn3, prepareBarAnimationFunctions: prepareBarAnimationFunctions3, midpointStartingBarPosition: midpointStartingBarPosition2, createDatumId: createDatumId9, Rect: Rect7, motion: motion5 } = _ModuleSupport150;
|
|
var FunnelSeries = class extends BaseFunnelSeries {
|
|
constructor(moduleCtx) {
|
|
super({
|
|
moduleCtx,
|
|
animationResetFns: {
|
|
datum: resetBarSelectionsFn3
|
|
}
|
|
});
|
|
this.properties = new FunnelProperties();
|
|
}
|
|
getBandScalePadding() {
|
|
return { inner: this.properties.spacingRatio, outer: 0 };
|
|
}
|
|
connectorEnabled() {
|
|
return this.properties.dropOff.enabled;
|
|
}
|
|
connectorStyle(index) {
|
|
return mergeDefaults11(this.properties.dropOff.getStyle(), this.properties.getStyle(index));
|
|
}
|
|
nodeFactory() {
|
|
return new Rect7();
|
|
}
|
|
createLabelData({
|
|
datumIndex,
|
|
rect,
|
|
yDatum,
|
|
datum,
|
|
visible
|
|
}) {
|
|
const { valueKey, stageKey, label } = this.properties;
|
|
if (!label.enabled)
|
|
return;
|
|
const yDomain = this.getSeriesDomain(ChartAxisDirection43.Y).domain;
|
|
const text2 = this.getLabelText(
|
|
yDatum,
|
|
datum,
|
|
valueKey,
|
|
"y",
|
|
yDomain,
|
|
label,
|
|
{ itemId: valueKey, value: yDatum, datum, stageKey, valueKey }
|
|
);
|
|
return {
|
|
x: rect.x + rect.width / 2,
|
|
y: rect.y + rect.height / 2,
|
|
textAlign: "center",
|
|
textBaseline: "middle",
|
|
text: text2,
|
|
itemId: stageKey,
|
|
datum,
|
|
datumIndex,
|
|
series: this,
|
|
visible
|
|
};
|
|
}
|
|
getItemStyle({ datum, datumIndex }, isHighlight) {
|
|
const { id: seriesId, properties } = this;
|
|
const { stageKey, valueKey, itemStyler } = properties;
|
|
const highlightStyle = this.getHighlightStyle(isHighlight, datumIndex);
|
|
const baseStyle = mergeDefaults11(highlightStyle, properties.getStyle(datumIndex));
|
|
let style = baseStyle;
|
|
if (itemStyler != null) {
|
|
const activeHighlight = this.ctx.highlightManager?.getActiveHighlight();
|
|
const overrides = this.cachedDatumCallback(
|
|
createDatumId9(datumIndex, isHighlight ? "highlight" : "node"),
|
|
() => {
|
|
const highlightStateString = this.getHighlightStateString(activeHighlight, isHighlight, datumIndex);
|
|
return this.callWithContext(itemStyler, {
|
|
seriesId,
|
|
datum,
|
|
highlightState: highlightStateString,
|
|
stageKey,
|
|
valueKey,
|
|
...style
|
|
});
|
|
}
|
|
);
|
|
if (overrides) {
|
|
style = mergeDefaults11(overrides, style);
|
|
}
|
|
}
|
|
return style;
|
|
}
|
|
updateDatumNodes({
|
|
datumSelection,
|
|
isHighlight
|
|
}) {
|
|
const { contextNodeData } = this;
|
|
if (!contextNodeData) {
|
|
return;
|
|
}
|
|
const { shadow } = this.properties;
|
|
const categoryAlongX = this.getCategoryDirection() === ChartAxisDirection43.X;
|
|
const fillBBox = this.getShapeFillBBox();
|
|
datumSelection.each((rect, datum) => {
|
|
const style = this.getItemStyle(datum, isHighlight);
|
|
rect.setStyleProperties(style, fillBBox);
|
|
rect.visible = categoryAlongX ? datum.width > 0 : datum.height > 0;
|
|
rect.crisp = datum.crisp;
|
|
rect.fillShadow = shadow;
|
|
});
|
|
}
|
|
tooltipStyle(datum, datumIndex) {
|
|
return this.getItemStyle({ datum, datumIndex }, false);
|
|
}
|
|
animateEmptyUpdateReady(params) {
|
|
super.animateEmptyUpdateReady(params);
|
|
const { datumSelection } = params;
|
|
const isVertical = this.isVertical();
|
|
const mode = "normal";
|
|
const barFns = prepareBarAnimationFunctions3(midpointStartingBarPosition2(isVertical, mode), "unknown");
|
|
motion5.fromToMotion(this.id, "datums", this.ctx.animationManager, [datumSelection], barFns);
|
|
}
|
|
animateWaitingUpdateReady(data) {
|
|
super.animateWaitingUpdateReady(data);
|
|
const { datumSelection: datumSelections } = data;
|
|
const { processedData } = this;
|
|
const dataDiff = processedData?.reduced?.diff?.[this.id];
|
|
const fns = prepareBarAnimationFunctions3(midpointStartingBarPosition2(this.isVertical(), "fade"), "added");
|
|
motion5.fromToMotion(
|
|
this.id,
|
|
"datums",
|
|
this.ctx.animationManager,
|
|
[datumSelections],
|
|
fns,
|
|
(_, datum) => datum.xValue,
|
|
dataDiff
|
|
);
|
|
}
|
|
hasItemStylers() {
|
|
return this.properties.itemStyler != null || this.properties.label.itemStyler != null;
|
|
}
|
|
};
|
|
FunnelSeries.className = "FunnelSeries";
|
|
FunnelSeries.type = "funnel";
|
|
|
|
// packages/ag-charts-enterprise/src/series/funnel/funnelSeriesOptionsDef.ts
|
|
import { _ModuleSupport as _ModuleSupport151 } from "ag-charts-community";
|
|
import { commonSeriesOptionsDefs as commonSeriesOptionsDefs10, constant as constant10, required as required10, string as string12, without as without4 } from "ag-charts-core";
|
|
var { funnelSeriesThemeableOptionsDef } = _ModuleSupport151;
|
|
var funnelSeriesOptionsDef = {
|
|
...funnelSeriesThemeableOptionsDef,
|
|
...without4(commonSeriesOptionsDefs10, ["showInLegend"]),
|
|
type: required10(constant10("funnel")),
|
|
stageKey: required10(string12),
|
|
valueKey: required10(string12)
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/series/funnel/funnelModule.ts
|
|
var FunnelSeriesModule = {
|
|
type: "series",
|
|
name: "funnel",
|
|
chartType: "cartesian",
|
|
enterprise: true,
|
|
solo: true,
|
|
version: VERSION32,
|
|
dependencies: [CartesianChartModule9],
|
|
options: funnelSeriesOptionsDef,
|
|
defaultAxes: FUNNEL_SERIES_AXES,
|
|
themeTemplate: FUNNEL_SERIES_THEME,
|
|
create: (ctx) => new FunnelSeries(ctx)
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/series/linear-gauge/linearGaugeModule.ts
|
|
import { VERSION as VERSION34 } from "ag-charts-community";
|
|
import {
|
|
FONT_SIZE as FONT_SIZE2,
|
|
LABEL_BOXING_DEFAULTS as LABEL_BOXING_DEFAULTS8,
|
|
SAFE_RANGE2_OPERATION as SAFE_RANGE2_OPERATION3,
|
|
SAFE_STROKE_FILL_OPERATION,
|
|
linearGaugeSeriesOptionsDef as linearGaugeSeriesOptionsDef2
|
|
} from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/preset/gaugePresetModule.ts
|
|
import { VERSION as VERSION33 } from "ag-charts-community";
|
|
import {
|
|
commonChartOptionsDefs,
|
|
defined,
|
|
linearGaugeSeriesOptionsDef,
|
|
positiveNumber as positiveNumber9,
|
|
radialGaugeSeriesOptionsDef,
|
|
tooltipOptionsDefs,
|
|
typeUnion as typeUnion2,
|
|
undocumented as undocumented10,
|
|
without as without5
|
|
} from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/preset/gaugePreset.ts
|
|
import { mergeArrayDefaults, mergeDefaults as mergeDefaults12 } from "ag-charts-core";
|
|
function tooltipOptions(opts) {
|
|
const { enabled, mode, showArrow, range: range2, position, pagination, delay, wrapping, interaction, renderer, ...rest } = opts;
|
|
const seriesTooltipOptions = {
|
|
enabled,
|
|
showArrow,
|
|
range: range2,
|
|
position,
|
|
interaction,
|
|
renderer,
|
|
...rest
|
|
};
|
|
const chartTooltipOptions = {
|
|
mode,
|
|
pagination,
|
|
delay,
|
|
wrapping,
|
|
...rest
|
|
};
|
|
return { chartTooltipOptions, seriesTooltipOptions };
|
|
}
|
|
function radialGaugeOptions(opts) {
|
|
const {
|
|
animation,
|
|
background,
|
|
container,
|
|
contextMenu,
|
|
context,
|
|
footnote,
|
|
foreground,
|
|
height,
|
|
listeners,
|
|
locale,
|
|
minHeight,
|
|
minWidth,
|
|
overrideDevicePixelRatio,
|
|
padding: padding2,
|
|
subtitle,
|
|
theme,
|
|
title,
|
|
width,
|
|
type,
|
|
cursor,
|
|
nodeClickRange,
|
|
tooltip: tooltipInput,
|
|
value,
|
|
scale = {},
|
|
startAngle,
|
|
endAngle,
|
|
highlight,
|
|
segmentation,
|
|
bar,
|
|
needle,
|
|
targets,
|
|
outerRadius,
|
|
innerRadius,
|
|
outerRadiusRatio,
|
|
innerRadiusRatio,
|
|
cornerRadius,
|
|
cornerMode,
|
|
label,
|
|
secondaryLabel,
|
|
spacing,
|
|
...seriesRest
|
|
} = opts;
|
|
const hasTooltip = tooltipInput != null;
|
|
const tooltip = tooltipInput ?? {};
|
|
const { chartTooltipOptions, seriesTooltipOptions } = tooltipOptions(tooltip);
|
|
const seriesOpts = {
|
|
...seriesRest,
|
|
type,
|
|
cursor,
|
|
context,
|
|
nodeClickRange,
|
|
value,
|
|
scale,
|
|
startAngle,
|
|
endAngle,
|
|
highlight,
|
|
segmentation,
|
|
bar,
|
|
targets,
|
|
outerRadius,
|
|
innerRadius,
|
|
outerRadiusRatio,
|
|
innerRadiusRatio,
|
|
cornerRadius,
|
|
cornerMode,
|
|
label,
|
|
secondaryLabel,
|
|
spacing
|
|
};
|
|
if (hasTooltip) {
|
|
seriesOpts.tooltip = seriesTooltipOptions;
|
|
}
|
|
if (needle != null) {
|
|
seriesOpts.needle = { enabled: true, ...needle };
|
|
}
|
|
return {
|
|
animation,
|
|
background,
|
|
container,
|
|
contextMenu,
|
|
context,
|
|
footnote,
|
|
foreground,
|
|
height,
|
|
listeners,
|
|
locale,
|
|
minHeight,
|
|
minWidth,
|
|
overrideDevicePixelRatio,
|
|
padding: padding2,
|
|
subtitle,
|
|
theme,
|
|
title,
|
|
width,
|
|
...hasTooltip ? { tooltip: chartTooltipOptions } : {},
|
|
series: [seriesOpts]
|
|
};
|
|
}
|
|
function linearGaugeOptions(opts) {
|
|
const {
|
|
animation,
|
|
background,
|
|
container,
|
|
contextMenu,
|
|
context,
|
|
footnote,
|
|
foreground,
|
|
height,
|
|
listeners,
|
|
locale,
|
|
minHeight,
|
|
minWidth,
|
|
overrideDevicePixelRatio,
|
|
padding: padding2,
|
|
subtitle,
|
|
theme,
|
|
title,
|
|
width,
|
|
type,
|
|
cursor,
|
|
nodeClickRange,
|
|
tooltip: tooltipInput,
|
|
value,
|
|
scale = {},
|
|
direction = "vertical",
|
|
thickness,
|
|
highlight,
|
|
segmentation,
|
|
bar,
|
|
targets,
|
|
cornerRadius,
|
|
cornerMode,
|
|
label,
|
|
...seriesRest
|
|
} = opts;
|
|
const hasTooltip = tooltipInput != null;
|
|
const tooltip = tooltipInput ?? {};
|
|
const { chartTooltipOptions, seriesTooltipOptions } = tooltipOptions(tooltip);
|
|
const seriesOpts = {
|
|
...seriesRest,
|
|
type,
|
|
cursor,
|
|
nodeClickRange,
|
|
value,
|
|
scale,
|
|
direction,
|
|
thickness,
|
|
highlight,
|
|
segmentation,
|
|
bar,
|
|
targets,
|
|
cornerRadius,
|
|
cornerMode,
|
|
label
|
|
};
|
|
if (hasTooltip) {
|
|
seriesOpts.tooltip = seriesTooltipOptions;
|
|
}
|
|
return {
|
|
animation,
|
|
background,
|
|
container,
|
|
contextMenu,
|
|
context,
|
|
footnote,
|
|
foreground,
|
|
height,
|
|
listeners,
|
|
locale,
|
|
minHeight,
|
|
minWidth,
|
|
overrideDevicePixelRatio,
|
|
padding: padding2,
|
|
subtitle,
|
|
theme,
|
|
title,
|
|
width,
|
|
...hasTooltip ? { tooltip: chartTooltipOptions } : {},
|
|
series: [seriesOpts]
|
|
};
|
|
}
|
|
function applyThemeDefaults(opts, presetTheme) {
|
|
if (presetTheme == null)
|
|
return opts;
|
|
const { targets: targetsTheme, ...gaugeTheme } = presetTheme;
|
|
opts = mergeDefaults12(opts, gaugeTheme);
|
|
if (opts.targets != null && targetsTheme != null) {
|
|
if (opts.type === "radial-gauge") {
|
|
opts.targets = mergeArrayDefaults(opts.targets, targetsTheme);
|
|
} else {
|
|
opts.targets = mergeArrayDefaults(opts.targets, targetsTheme);
|
|
}
|
|
}
|
|
return opts;
|
|
}
|
|
function createGauge(opts, presetTheme) {
|
|
switch (opts.type) {
|
|
case "radial-gauge":
|
|
return radialGaugeOptions(applyThemeDefaults(opts, presetTheme));
|
|
case "linear-gauge":
|
|
return linearGaugeOptions(applyThemeDefaults(opts, presetTheme));
|
|
default:
|
|
return { series: [] };
|
|
}
|
|
}
|
|
|
|
// packages/ag-charts-enterprise/src/preset/gaugePresetModule.ts
|
|
var commonGaugeOptions = {
|
|
// Valid pass-through options
|
|
theme: defined,
|
|
container: defined,
|
|
animation: defined,
|
|
background: defined,
|
|
contextMenu: defined,
|
|
context: () => true,
|
|
listeners: defined,
|
|
locale: defined,
|
|
width: defined,
|
|
height: defined,
|
|
minWidth: defined,
|
|
minHeight: defined,
|
|
title: defined,
|
|
subtitle: defined,
|
|
footnote: defined,
|
|
padding: defined,
|
|
tooltip: {
|
|
...tooltipOptionsDefs,
|
|
...commonChartOptionsDefs.tooltip
|
|
}
|
|
};
|
|
commonGaugeOptions.overrideDevicePixelRatio = undocumented10(positiveNumber9);
|
|
commonGaugeOptions.foreground = undocumented10(defined);
|
|
var GaugePresetModule = {
|
|
type: "preset",
|
|
name: "gauge-preset",
|
|
enterprise: true,
|
|
version: VERSION33,
|
|
dependencies: [StandaloneChartModule],
|
|
options: typeUnion2(
|
|
{
|
|
"linear-gauge": {
|
|
...without5(linearGaugeSeriesOptionsDef, ["type"]),
|
|
...commonGaugeOptions
|
|
},
|
|
"radial-gauge": {
|
|
...without5(radialGaugeSeriesOptionsDef, ["type"]),
|
|
...commonGaugeOptions
|
|
}
|
|
},
|
|
"gauge options"
|
|
),
|
|
create: createGauge
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/series/linear-gauge/linearGaugeSeries.ts
|
|
import {
|
|
_ModuleSupport as _ModuleSupport155
|
|
} from "ag-charts-community";
|
|
import {
|
|
StateMachine as StateMachine12,
|
|
cachedTextMeasurer as cachedTextMeasurer7,
|
|
easeOut as easeOut2,
|
|
findRangeExtent as findRangeExtent2,
|
|
isArray as isArray4,
|
|
measureTextSegments as measureTextSegments3,
|
|
mergeDefaults as mergeDefaults13,
|
|
tickFormat,
|
|
toRadians as toRadians4,
|
|
toTextString as toTextString3
|
|
} from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/series/gauge-util/datumUnion.ts
|
|
var DatumUnion = class {
|
|
*[Symbol.iterator]() {
|
|
const { node, datum } = this;
|
|
if (node && datum)
|
|
yield { node, datum };
|
|
}
|
|
nodes() {
|
|
return this.node ? [this.node] : [];
|
|
}
|
|
update(datumSelection, group, ctor, nodeUpdater) {
|
|
const nodes = datumSelection.nodes();
|
|
if (nodes.length === 0) {
|
|
this.node?.remove();
|
|
this.node = void 0;
|
|
} else {
|
|
if (this.node === void 0) {
|
|
this.node = new ctor();
|
|
this.node.fillOpacity = 0;
|
|
this.node.strokeOpacity = 0;
|
|
group.appendChild(this.node);
|
|
}
|
|
const first = nodes[0];
|
|
const last = nodes.toReversed().find((n) => n.datum.datum.value > n.datum.datum.segmentStart) ?? nodes.at(-1);
|
|
this.node.datum = this.datum = first.datum;
|
|
nodeUpdater(this.node, first, last);
|
|
}
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/series/gauge-util/label.ts
|
|
import { isArray as isArray2 } from "ag-charts-core";
|
|
var fadeInFns = {
|
|
fromFn: () => ({ opacity: 0, phase: "initial" }),
|
|
toFn: () => ({ opacity: 1 })
|
|
};
|
|
function formatLabel(value, scale) {
|
|
if (value == null)
|
|
return "";
|
|
const { min, max } = scale;
|
|
const minLog10 = min === 0 ? 0 : Math.ceil(Math.log10(Math.abs(min)));
|
|
const maxLog10 = max === 0 ? 0 : Math.ceil(Math.log10(Math.abs(max)));
|
|
const dp = Math.max(2 - Math.max(minLog10, maxLog10), 0);
|
|
return value.toFixed(dp);
|
|
}
|
|
function getLabelText(seriesId, ctx, datum, valueOverride) {
|
|
if (datum.text != null)
|
|
return datum.text;
|
|
const value = valueOverride ?? datum.value;
|
|
let labelFormat;
|
|
if (datum?.formatter != null) {
|
|
labelFormat = formatWithContext(ctx, datum.formatter, { seriesId, datum: void 0, value });
|
|
}
|
|
return labelFormat == null || isArray2(labelFormat) ? labelFormat : String(labelFormat);
|
|
}
|
|
|
|
// packages/ag-charts-enterprise/src/series/gauge-util/lineMarker.ts
|
|
function lineMarker({ path, x, y, size }) {
|
|
path.moveTo(x, y - size / 2);
|
|
path.lineTo(x, y + size / 2);
|
|
}
|
|
|
|
// packages/ag-charts-enterprise/src/series/gauge-util/pick.ts
|
|
import { _ModuleSupport as _ModuleSupport152 } from "ag-charts-community";
|
|
import { clamp as clamp12, iterate } from "ag-charts-core";
|
|
function pickGaugeNearestDatum(self, point) {
|
|
const it = iterate(self.datumUnion.nodes(), self.targetSelection.nodes());
|
|
return self.pickNodeNearestDistantObject(point, it);
|
|
}
|
|
function pickGaugeFocus(self, opts) {
|
|
const others = [
|
|
{ data: self.contextNodeData?.nodeData, selection: self.datumUnion },
|
|
{ data: self.contextNodeData?.targetData, selection: self.targetSelection }
|
|
].filter((v) => v.data && v.data.length > 0);
|
|
const otherIndex = clamp12(0, opts.otherIndex + opts.otherIndexDelta, others.length - 1);
|
|
if (others.length === 0)
|
|
return;
|
|
const { data, selection } = others[otherIndex];
|
|
if (data == null || data.length === 0)
|
|
return;
|
|
const datumIndex = clamp12(0, opts.datumIndex, data.length - 1);
|
|
const datum = data[datumIndex];
|
|
for (const node of selection) {
|
|
if (node.datum === datum) {
|
|
const bounds = node.node;
|
|
return { bounds, clipFocusBox: true, datum, datumIndex, otherIndex };
|
|
}
|
|
}
|
|
}
|
|
function findGaugeNodeDatum(self, itemId) {
|
|
return _ModuleSupport152.findNodeDatumInArray(itemId, self.contextNodeData?.nodeData) ?? _ModuleSupport152.findNodeDatumInArray(itemId, self.contextNodeData?.targetData);
|
|
}
|
|
|
|
// packages/ag-charts-enterprise/src/series/linear-gauge/linearGaugeSeriesProperties.ts
|
|
import { _ModuleSupport as _ModuleSupport153 } from "ag-charts-community";
|
|
import { BaseProperties as BaseProperties33, PropertiesArray as PropertiesArray7, Property as Property73 } from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/series/gauge-util/segmentation.ts
|
|
import { BaseProperties as BaseProperties32, Logger as Logger16, Property as Property72 } from "ag-charts-core";
|
|
var GaugeSegmentationIntervalProperties = class extends BaseProperties32 {
|
|
getSegments(scale, maxTicks) {
|
|
const { values, step, count } = this;
|
|
const d0 = Math.min(...scale.domain);
|
|
const d1 = Math.max(...scale.domain);
|
|
let ticks;
|
|
if (values != null) {
|
|
const segments = values.filter((v) => v > d0 && v < d1).sort((a, b) => a - b);
|
|
ticks = [d0, ...segments, d1];
|
|
} else if (step != null) {
|
|
const segments = [];
|
|
for (let i = d0; i < d1; i += step) {
|
|
segments.push(i);
|
|
}
|
|
segments.push(d1);
|
|
ticks = segments;
|
|
} else if (count == null) {
|
|
const segments = scale.ticks({
|
|
nice: [true, true],
|
|
interval: void 0,
|
|
tickCount: void 0,
|
|
minTickCount: 0,
|
|
maxTickCount: Infinity
|
|
})?.ticks?.filter((v) => v > d0 && v < d1);
|
|
ticks = segments == null ? void 0 : [d0, ...segments, d1];
|
|
} else {
|
|
const segments = count + 1;
|
|
ticks = Array.from({ length: segments + 1 }, (_, i) => i / segments * (d1 - d0) + d0);
|
|
}
|
|
if (ticks != null && ticks.length > maxTicks) {
|
|
Logger16.warnOnce(
|
|
`the configured segmentation results in more than 1 item per pixel, ignoring. Supply a segmentation configuration that results in larger segments or omit this configuration`
|
|
);
|
|
ticks = void 0;
|
|
}
|
|
ticks ?? (ticks = [d0, d1]);
|
|
return ticks;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property72
|
|
], GaugeSegmentationIntervalProperties.prototype, "values", 2);
|
|
__decorateClass([
|
|
Property72
|
|
], GaugeSegmentationIntervalProperties.prototype, "step", 2);
|
|
__decorateClass([
|
|
Property72
|
|
], GaugeSegmentationIntervalProperties.prototype, "count", 2);
|
|
var GaugeSegmentationProperties = class extends BaseProperties32 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.enabled = false;
|
|
this.interval = new GaugeSegmentationIntervalProperties();
|
|
this.spacing = 0;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property72
|
|
], GaugeSegmentationProperties.prototype, "enabled", 2);
|
|
__decorateClass([
|
|
Property72
|
|
], GaugeSegmentationProperties.prototype, "interval", 2);
|
|
__decorateClass([
|
|
Property72
|
|
], GaugeSegmentationProperties.prototype, "spacing", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/series/linear-gauge/linearGaugeSeriesProperties.ts
|
|
var { makeSeriesTooltip: makeSeriesTooltip11, SeriesProperties: SeriesProperties2, Label: Label9, AxisLabel: AxisLabel5, getColorStops } = _ModuleSupport153;
|
|
var LinearGaugeDefaultTargetLabelProperties = class extends Label9 {
|
|
};
|
|
__decorateClass([
|
|
Property73
|
|
], LinearGaugeDefaultTargetLabelProperties.prototype, "spacing", 2);
|
|
var LinearGaugeTargetProperties = class extends BaseProperties33 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.value = 0;
|
|
this.label = new LinearGaugeDefaultTargetLabelProperties();
|
|
}
|
|
getStyle(defaultTarget) {
|
|
const {
|
|
fill = defaultTarget.fill ?? "black",
|
|
fillOpacity = defaultTarget.fillOpacity ?? 1,
|
|
stroke: stroke3 = defaultTarget.stroke ?? "black",
|
|
strokeWidth = defaultTarget.strokeWidth ?? 0,
|
|
strokeOpacity = defaultTarget.strokeOpacity ?? 1,
|
|
lineDash = defaultTarget.lineDash ?? [0],
|
|
lineDashOffset = defaultTarget.lineDashOffset ?? 0
|
|
} = this;
|
|
return {
|
|
fill,
|
|
fillOpacity,
|
|
stroke: stroke3,
|
|
strokeWidth,
|
|
strokeOpacity,
|
|
lineDash,
|
|
lineDashOffset
|
|
};
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property73
|
|
], LinearGaugeTargetProperties.prototype, "text", 2);
|
|
__decorateClass([
|
|
Property73
|
|
], LinearGaugeTargetProperties.prototype, "value", 2);
|
|
__decorateClass([
|
|
Property73
|
|
], LinearGaugeTargetProperties.prototype, "shape", 2);
|
|
__decorateClass([
|
|
Property73
|
|
], LinearGaugeTargetProperties.prototype, "placement", 2);
|
|
__decorateClass([
|
|
Property73
|
|
], LinearGaugeTargetProperties.prototype, "spacing", 2);
|
|
__decorateClass([
|
|
Property73
|
|
], LinearGaugeTargetProperties.prototype, "size", 2);
|
|
__decorateClass([
|
|
Property73
|
|
], LinearGaugeTargetProperties.prototype, "rotation", 2);
|
|
__decorateClass([
|
|
Property73
|
|
], LinearGaugeTargetProperties.prototype, "fill", 2);
|
|
__decorateClass([
|
|
Property73
|
|
], LinearGaugeTargetProperties.prototype, "fillOpacity", 2);
|
|
__decorateClass([
|
|
Property73
|
|
], LinearGaugeTargetProperties.prototype, "stroke", 2);
|
|
__decorateClass([
|
|
Property73
|
|
], LinearGaugeTargetProperties.prototype, "strokeWidth", 2);
|
|
__decorateClass([
|
|
Property73
|
|
], LinearGaugeTargetProperties.prototype, "strokeOpacity", 2);
|
|
__decorateClass([
|
|
Property73
|
|
], LinearGaugeTargetProperties.prototype, "lineDash", 2);
|
|
__decorateClass([
|
|
Property73
|
|
], LinearGaugeTargetProperties.prototype, "lineDashOffset", 2);
|
|
__decorateClass([
|
|
Property73
|
|
], LinearGaugeTargetProperties.prototype, "label", 2);
|
|
var LinearGaugeBarProperties = class extends BaseProperties33 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.enabled = true;
|
|
this.thicknessRatio = 1;
|
|
this.fills = new PropertiesArray7(_ModuleSupport153.StopProperties);
|
|
this.fillMode = "continuous";
|
|
this.fillOpacity = 1;
|
|
this.stroke = "black";
|
|
this.strokeWidth = 0;
|
|
this.strokeOpacity = 1;
|
|
this.lineDash = [0];
|
|
this.lineDashOffset = 0;
|
|
}
|
|
getStyle(defaultColorRange, horizontal, scale) {
|
|
const { fill, fills, fillMode, fillOpacity, stroke: stroke3, strokeWidth, strokeOpacity, lineDash, lineDashOffset } = this;
|
|
const barFill = fill ?? createLinearGradient(fills, fillMode, defaultColorRange, scale, horizontal);
|
|
return {
|
|
fill: barFill,
|
|
fillOpacity,
|
|
stroke: stroke3,
|
|
strokeWidth,
|
|
strokeOpacity,
|
|
lineDash,
|
|
lineDashOffset
|
|
};
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property73
|
|
], LinearGaugeBarProperties.prototype, "enabled", 2);
|
|
__decorateClass([
|
|
Property73
|
|
], LinearGaugeBarProperties.prototype, "thickness", 2);
|
|
__decorateClass([
|
|
Property73
|
|
], LinearGaugeBarProperties.prototype, "thicknessRatio", 2);
|
|
__decorateClass([
|
|
Property73
|
|
], LinearGaugeBarProperties.prototype, "fills", 2);
|
|
__decorateClass([
|
|
Property73
|
|
], LinearGaugeBarProperties.prototype, "fillMode", 2);
|
|
__decorateClass([
|
|
Property73
|
|
], LinearGaugeBarProperties.prototype, "fill", 2);
|
|
__decorateClass([
|
|
Property73
|
|
], LinearGaugeBarProperties.prototype, "fillOpacity", 2);
|
|
__decorateClass([
|
|
Property73
|
|
], LinearGaugeBarProperties.prototype, "stroke", 2);
|
|
__decorateClass([
|
|
Property73
|
|
], LinearGaugeBarProperties.prototype, "strokeWidth", 2);
|
|
__decorateClass([
|
|
Property73
|
|
], LinearGaugeBarProperties.prototype, "strokeOpacity", 2);
|
|
__decorateClass([
|
|
Property73
|
|
], LinearGaugeBarProperties.prototype, "lineDash", 2);
|
|
__decorateClass([
|
|
Property73
|
|
], LinearGaugeBarProperties.prototype, "lineDashOffset", 2);
|
|
var LinearGaugeScaleIntervalProperties = class extends BaseProperties33 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.values = void 0;
|
|
this.step = void 0;
|
|
this.minSpacing = 0;
|
|
this.maxSpacing = 1e3;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property73
|
|
], LinearGaugeScaleIntervalProperties.prototype, "values", 2);
|
|
__decorateClass([
|
|
Property73
|
|
], LinearGaugeScaleIntervalProperties.prototype, "step", 2);
|
|
__decorateClass([
|
|
Property73
|
|
], LinearGaugeScaleIntervalProperties.prototype, "minSpacing", 2);
|
|
__decorateClass([
|
|
Property73
|
|
], LinearGaugeScaleIntervalProperties.prototype, "maxSpacing", 2);
|
|
var LinearGaugeScaleLabelProperties = class extends AxisLabel5 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.placement = void 0;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property73
|
|
], LinearGaugeScaleLabelProperties.prototype, "placement", 2);
|
|
var LinearGaugeScaleProperties = class extends BaseProperties33 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.min = 0;
|
|
this.max = 1;
|
|
this.fills = new PropertiesArray7(_ModuleSupport153.StopProperties);
|
|
this.fillMode = "continuous";
|
|
this.fillOpacity = 1;
|
|
this.stroke = "black";
|
|
this.strokeWidth = 0;
|
|
this.strokeOpacity = 1;
|
|
this.lineDash = [0];
|
|
this.lineDashOffset = 0;
|
|
this.defaultFill = "black";
|
|
this.interval = new LinearGaugeScaleIntervalProperties();
|
|
this.label = new LinearGaugeScaleLabelProperties();
|
|
}
|
|
getStyle(barEnabled, defaultColorRange, horizontal, scale) {
|
|
const {
|
|
fill,
|
|
fills,
|
|
defaultFill,
|
|
fillMode,
|
|
fillOpacity,
|
|
stroke: stroke3,
|
|
strokeWidth,
|
|
strokeOpacity,
|
|
lineDash,
|
|
lineDashOffset
|
|
} = this;
|
|
const scaleFill = fill ?? (barEnabled && fills.length === 0 ? defaultFill : void 0) ?? createLinearGradient(fills, fillMode, defaultColorRange, scale, horizontal);
|
|
return {
|
|
fill: scaleFill,
|
|
fillOpacity,
|
|
stroke: stroke3,
|
|
strokeWidth,
|
|
strokeOpacity,
|
|
lineDash,
|
|
lineDashOffset
|
|
};
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property73
|
|
], LinearGaugeScaleProperties.prototype, "min", 2);
|
|
__decorateClass([
|
|
Property73
|
|
], LinearGaugeScaleProperties.prototype, "max", 2);
|
|
__decorateClass([
|
|
Property73
|
|
], LinearGaugeScaleProperties.prototype, "fills", 2);
|
|
__decorateClass([
|
|
Property73
|
|
], LinearGaugeScaleProperties.prototype, "fillMode", 2);
|
|
__decorateClass([
|
|
Property73
|
|
], LinearGaugeScaleProperties.prototype, "fill", 2);
|
|
__decorateClass([
|
|
Property73
|
|
], LinearGaugeScaleProperties.prototype, "fillOpacity", 2);
|
|
__decorateClass([
|
|
Property73
|
|
], LinearGaugeScaleProperties.prototype, "stroke", 2);
|
|
__decorateClass([
|
|
Property73
|
|
], LinearGaugeScaleProperties.prototype, "strokeWidth", 2);
|
|
__decorateClass([
|
|
Property73
|
|
], LinearGaugeScaleProperties.prototype, "strokeOpacity", 2);
|
|
__decorateClass([
|
|
Property73
|
|
], LinearGaugeScaleProperties.prototype, "lineDash", 2);
|
|
__decorateClass([
|
|
Property73
|
|
], LinearGaugeScaleProperties.prototype, "lineDashOffset", 2);
|
|
__decorateClass([
|
|
Property73
|
|
], LinearGaugeScaleProperties.prototype, "defaultFill", 2);
|
|
__decorateClass([
|
|
Property73
|
|
], LinearGaugeScaleProperties.prototype, "interval", 2);
|
|
__decorateClass([
|
|
Property73
|
|
], LinearGaugeScaleProperties.prototype, "label", 2);
|
|
var LinearGaugeLabelProperties = class extends AutoSizedLabel {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.placement = "inside-center";
|
|
this.avoidCollisions = true;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property73
|
|
], LinearGaugeLabelProperties.prototype, "text", 2);
|
|
__decorateClass([
|
|
Property73
|
|
], LinearGaugeLabelProperties.prototype, "placement", 2);
|
|
__decorateClass([
|
|
Property73
|
|
], LinearGaugeLabelProperties.prototype, "avoidCollisions", 2);
|
|
var LinearGaugeSeriesProperties = class extends SeriesProperties2 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.value = 0;
|
|
this.segmentation = new GaugeSegmentationProperties();
|
|
this.defaultColorRange = [];
|
|
this.targets = new PropertiesArray7(LinearGaugeTargetProperties);
|
|
this.defaultTarget = new LinearGaugeTargetProperties();
|
|
this.defaultScale = new LinearGaugeScaleProperties();
|
|
this.direction = "vertical";
|
|
this.thickness = 1;
|
|
this.cornerRadius = 0;
|
|
this.cornerMode = "container";
|
|
this.margin = 0;
|
|
this.scale = new LinearGaugeScaleProperties();
|
|
this.bar = new LinearGaugeBarProperties();
|
|
this.label = new LinearGaugeLabelProperties();
|
|
this.tooltip = makeSeriesTooltip11();
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property73
|
|
], LinearGaugeSeriesProperties.prototype, "value", 2);
|
|
__decorateClass([
|
|
Property73
|
|
], LinearGaugeSeriesProperties.prototype, "segmentation", 2);
|
|
__decorateClass([
|
|
Property73
|
|
], LinearGaugeSeriesProperties.prototype, "defaultColorRange", 2);
|
|
__decorateClass([
|
|
Property73
|
|
], LinearGaugeSeriesProperties.prototype, "targets", 2);
|
|
__decorateClass([
|
|
Property73
|
|
], LinearGaugeSeriesProperties.prototype, "defaultTarget", 2);
|
|
__decorateClass([
|
|
Property73
|
|
], LinearGaugeSeriesProperties.prototype, "defaultScale", 2);
|
|
__decorateClass([
|
|
Property73
|
|
], LinearGaugeSeriesProperties.prototype, "direction", 2);
|
|
__decorateClass([
|
|
Property73
|
|
], LinearGaugeSeriesProperties.prototype, "thickness", 2);
|
|
__decorateClass([
|
|
Property73
|
|
], LinearGaugeSeriesProperties.prototype, "cornerRadius", 2);
|
|
__decorateClass([
|
|
Property73
|
|
], LinearGaugeSeriesProperties.prototype, "cornerMode", 2);
|
|
__decorateClass([
|
|
Property73
|
|
], LinearGaugeSeriesProperties.prototype, "margin", 2);
|
|
__decorateClass([
|
|
Property73
|
|
], LinearGaugeSeriesProperties.prototype, "scale", 2);
|
|
__decorateClass([
|
|
Property73
|
|
], LinearGaugeSeriesProperties.prototype, "bar", 2);
|
|
__decorateClass([
|
|
Property73
|
|
], LinearGaugeSeriesProperties.prototype, "label", 2);
|
|
__decorateClass([
|
|
Property73
|
|
], LinearGaugeSeriesProperties.prototype, "tooltip", 2);
|
|
function createLinearGradient(fills, fillMode, defaultColorRange, scale, horizontal) {
|
|
const colorStops = getColorStops(fills, defaultColorRange, scale.domain, fillMode);
|
|
return {
|
|
type: "gradient",
|
|
gradient: "linear",
|
|
colorSpace: "oklch",
|
|
colorStops,
|
|
rotation: horizontal ? 90 : 0,
|
|
bounds: "series"
|
|
};
|
|
}
|
|
|
|
// packages/ag-charts-enterprise/src/series/linear-gauge/linearGaugeUtil.ts
|
|
import { _ModuleSupport as _ModuleSupport154 } from "ag-charts-community";
|
|
import { cachedTextMeasurer as cachedTextMeasurer6, isArray as isArray3, measureTextSegments as measureTextSegments2, toPlainText as toPlainText6, toTextString as toTextString2 } from "ag-charts-core";
|
|
var { BBox: BBox19 } = _ModuleSupport154;
|
|
function datumRect(datum) {
|
|
const { x0, y0, x1, y1, horizontalInset, verticalInset } = datum;
|
|
const x = Math.min(x0, x1) + horizontalInset;
|
|
const y = Math.min(y0, y1) + verticalInset;
|
|
const width = Math.max(Math.abs(x1 - x0) - 2 * horizontalInset, 0);
|
|
const height = Math.max(Math.abs(y1 - y0) - 2 * verticalInset, 0);
|
|
return { x, y, width, height };
|
|
}
|
|
function clipBBoxVisibility(datum, clipBBox) {
|
|
if (clipBBox == null)
|
|
return true;
|
|
const rect = datumRect(datum);
|
|
const delta3 = 1e-6;
|
|
const x0 = rect.x + delta3;
|
|
const y0 = rect.y + delta3;
|
|
const x1 = rect.x + rect.width - delta3;
|
|
const y1 = rect.y + rect.height - delta3;
|
|
const clipX0 = clipBBox.x;
|
|
const clipX1 = clipBBox.x + clipBBox.width;
|
|
const clipY0 = clipBBox.y;
|
|
const clipY1 = clipBBox.y + clipBBox.height;
|
|
return Math.max(x0, clipX0) <= Math.min(x1, clipX1) && Math.max(y0, clipY0) <= Math.min(y1, clipY1);
|
|
}
|
|
function hasClipBBox(datum) {
|
|
const { clipX0, clipX1, clipY0, clipY1 } = datum;
|
|
return clipX0 != null && clipX1 != null || clipY0 != null && clipY1 != null;
|
|
}
|
|
function computeClipBBox(datum) {
|
|
if (!hasClipBBox(datum))
|
|
return;
|
|
const { x0, y0, x1, y1 } = datum;
|
|
const { x, y, width, height } = datumRect(datum);
|
|
let { clipX0, clipX1, clipY0, clipY1 } = datum;
|
|
if (clipX0 == null || clipX1 == null) {
|
|
clipX0 = x0;
|
|
clipX1 = x1;
|
|
}
|
|
if (clipY0 == null || clipY1 == null) {
|
|
clipY0 = y0;
|
|
clipY1 = y1;
|
|
}
|
|
const clipX = Math.min(clipX0, clipX1);
|
|
const clipY = Math.min(clipY0, clipY1);
|
|
const clipWidth = Math.abs(clipX1 - clipX0);
|
|
const clipHeight = Math.abs(clipY1 - clipY0);
|
|
clipX0 = Math.max(x, clipX);
|
|
clipY0 = Math.max(y, clipY);
|
|
clipX1 = Math.min(x + width, clipX + clipWidth);
|
|
clipY1 = Math.min(y + height, clipY + clipHeight);
|
|
return new BBox19(
|
|
Math.min(clipX0, clipX1),
|
|
Math.min(clipY0, clipY1),
|
|
Math.abs(clipX1 - clipX0),
|
|
Math.abs(clipY1 - clipY0)
|
|
);
|
|
}
|
|
function prepareLinearGaugeSeriesAnimationFunctions(initialLoad, horizontal) {
|
|
const phase = initialLoad ? "initial" : "update";
|
|
const node = {
|
|
fromFn(sect, datum) {
|
|
const previousDatum = sect.previousDatum;
|
|
let { x0, y0, x1, y1, clipX0, clipY0, clipX1, clipY1 } = previousDatum ?? datum;
|
|
const { horizontalInset, verticalInset } = datum;
|
|
const previousHadClipBBox = previousDatum != null && hasClipBBox(previousDatum);
|
|
const nextHasClipBBox = hasClipBBox(datum);
|
|
if (previousHadClipBBox && nextHasClipBBox) {
|
|
} else if (!previousHadClipBBox && nextHasClipBBox) {
|
|
({ x0, y0, x1, y1, clipX0, clipY0, clipX1, clipY1 } = datum);
|
|
if (initialLoad) {
|
|
if (horizontal) {
|
|
clipX1 = datum.clipX0;
|
|
} else {
|
|
clipY1 = datum.clipY0;
|
|
}
|
|
}
|
|
} else if (previousHadClipBBox && !nextHasClipBBox) {
|
|
({ x0, y0, x1, y1 } = datum);
|
|
clipX0 = void 0;
|
|
clipY0 = void 0;
|
|
clipX1 = void 0;
|
|
clipY1 = void 0;
|
|
} else if (initialLoad) {
|
|
if (horizontal) {
|
|
x1 = x0;
|
|
} else {
|
|
y1 = y0;
|
|
}
|
|
}
|
|
return { x0, y0, x1, y1, clipX0, clipY0, clipX1, clipY1, horizontalInset, verticalInset, phase };
|
|
},
|
|
toFn(_sect, datum) {
|
|
const { x0, y0, x1, y1, clipX0, clipY0, clipX1, clipY1, horizontalInset, verticalInset } = datum;
|
|
return { x0, y0, x1, y1, clipX0, clipY0, clipX1, clipY1, horizontalInset, verticalInset };
|
|
},
|
|
applyFn(rect, params) {
|
|
rect.setProperties(resetLinearGaugeSeriesResetRectFunction(rect, params));
|
|
}
|
|
};
|
|
return { node };
|
|
}
|
|
function resetLinearGaugeSeriesResetRectFunction(_node, datum) {
|
|
const { x, y, width, height } = datumRect(datum);
|
|
const clipBBox = computeClipBBox(datum);
|
|
const visible = clipBBoxVisibility(datum, clipBBox);
|
|
return { x, y, width, height, clipBBox, visible };
|
|
}
|
|
var horizontalTextAligns = {
|
|
["Before" /* Before */]: "right",
|
|
["Center" /* Center */]: "center",
|
|
["After" /* After */]: "left"
|
|
};
|
|
var verticalTextBaselines = {
|
|
["Before" /* Before */]: "top",
|
|
["Center" /* Center */]: "middle",
|
|
["After" /* After */]: "bottom"
|
|
};
|
|
var horizontalAlignFactors = {
|
|
["Before" /* Before */]: -1,
|
|
["Center" /* Center */]: -0.5,
|
|
["After" /* After */]: 0
|
|
};
|
|
var verticalAlignFactors2 = {
|
|
["Before" /* Before */]: 0,
|
|
["Center" /* Center */]: -0.5,
|
|
["After" /* After */]: -1
|
|
};
|
|
function formatLinearGaugeLabels(series, ctx, selection, opts, bboxes, datumOverrides) {
|
|
const { seriesRect, gaugeRect, barRect } = bboxes;
|
|
const { padding: padding2, horizontal } = opts;
|
|
selection.each((label, labelDatum) => {
|
|
const labelText = getLabelText(series.id, ctx, labelDatum, datumOverrides?.label);
|
|
let boundingWidth;
|
|
let boundingHeight;
|
|
if (labelDatum.placement === "outside-start") {
|
|
if (horizontal) {
|
|
boundingWidth = gaugeRect.x;
|
|
boundingHeight = seriesRect.height;
|
|
} else {
|
|
boundingWidth = seriesRect.width;
|
|
boundingHeight = seriesRect.height - (gaugeRect.y + gaugeRect.height);
|
|
}
|
|
} else if (labelDatum.placement === "outside-end") {
|
|
if (horizontal) {
|
|
boundingWidth = seriesRect.width - (gaugeRect.x + gaugeRect.width);
|
|
boundingHeight = seriesRect.height;
|
|
} else {
|
|
boundingWidth = seriesRect.width;
|
|
boundingHeight = gaugeRect.y;
|
|
}
|
|
} else if (labelDatum.avoidCollisions) {
|
|
boundingWidth = gaugeRect.width;
|
|
boundingHeight = gaugeRect.height;
|
|
}
|
|
let layout;
|
|
if (labelText == null) {
|
|
return;
|
|
} else if (boundingWidth != null && boundingHeight != null) {
|
|
const sizeFittingHeight = () => ({
|
|
width: boundingWidth,
|
|
height: boundingHeight,
|
|
meta: null
|
|
});
|
|
const labelMeta = formatSingleLabel(toPlainText6(labelText), labelDatum, { padding: padding2 }, sizeFittingHeight);
|
|
layout = labelMeta?.[0];
|
|
} else {
|
|
const measurer3 = cachedTextMeasurer6(labelDatum);
|
|
const { width, height } = isArray3(labelText) ? measureTextSegments2(labelText, labelDatum) : measurer3.measureLines(toTextString2(labelText));
|
|
layout = {
|
|
text: labelText,
|
|
fontSize: labelDatum.fontSize,
|
|
lineHeight: labelDatum.lineHeight ?? measurer3.lineHeight(),
|
|
width,
|
|
height
|
|
};
|
|
}
|
|
if (layout == null) {
|
|
label.visible = false;
|
|
return;
|
|
}
|
|
const scale0 = horizontal ? gaugeRect.x : gaugeRect.y + gaugeRect.height;
|
|
const scale1 = horizontal ? gaugeRect.x + gaugeRect.width : gaugeRect.y;
|
|
const bar0 = horizontal ? barRect.x : barRect.y + barRect.height;
|
|
const bar1 = horizontal ? barRect.x + barRect.width : barRect.y;
|
|
const offset = labelDatum.spacing * (horizontal ? 1 : -1);
|
|
let bounds0;
|
|
let bounds1;
|
|
let s;
|
|
let align;
|
|
switch (labelDatum.placement) {
|
|
case "outside-start":
|
|
bounds0 = -Infinity;
|
|
bounds1 = Infinity;
|
|
s = scale0 - offset;
|
|
align = "Before" /* Before */;
|
|
break;
|
|
case "outside-end":
|
|
bounds0 = -Infinity;
|
|
bounds1 = Infinity;
|
|
s = scale1 + offset;
|
|
align = "After" /* After */;
|
|
break;
|
|
case "inside-start":
|
|
bounds0 = scale0;
|
|
bounds1 = bar1;
|
|
s = scale0 + offset;
|
|
align = "After" /* After */;
|
|
break;
|
|
case "inside-end":
|
|
bounds0 = bar1;
|
|
bounds1 = scale1;
|
|
s = scale1 - offset;
|
|
align = "Before" /* Before */;
|
|
break;
|
|
case "inside-center":
|
|
bounds0 = scale0;
|
|
bounds1 = scale1;
|
|
s = (scale0 + scale1) / 2;
|
|
align = "Center" /* Center */;
|
|
break;
|
|
case "bar-inside":
|
|
bounds0 = bar0;
|
|
bounds1 = bar1;
|
|
s = (bar0 + bar1) / 2;
|
|
align = "Center" /* Center */;
|
|
break;
|
|
case "bar-inside-end":
|
|
bounds0 = bar0;
|
|
bounds1 = bar1;
|
|
s = bar1 - offset;
|
|
align = "Before" /* Before */;
|
|
break;
|
|
case "bar-outside-end":
|
|
bounds0 = bar1;
|
|
bounds1 = scale1;
|
|
s = bar1 + offset;
|
|
align = "After" /* After */;
|
|
break;
|
|
case "bar-end":
|
|
bounds0 = -Infinity;
|
|
bounds1 = Infinity;
|
|
s = bar1;
|
|
align = "Center" /* Center */;
|
|
break;
|
|
}
|
|
const x = horizontal ? s : gaugeRect.x + gaugeRect.width / 2;
|
|
const y = horizontal ? gaugeRect.y + gaugeRect.height / 2 : s;
|
|
let s0;
|
|
let s1;
|
|
if (horizontal) {
|
|
s0 = x + horizontalAlignFactors[align] * layout.width;
|
|
s1 = s0 + layout.width;
|
|
} else {
|
|
s0 = y + verticalAlignFactors2[align] * layout.height;
|
|
s1 = s0 + layout.height;
|
|
}
|
|
const inside = Math.min(s0, s1) >= Math.min(bounds0, bounds1) && Math.max(s0, s1) <= Math.max(bounds0, bounds1);
|
|
if (labelDatum.avoidCollisions && !inside) {
|
|
label.visible = false;
|
|
return;
|
|
}
|
|
label.visible = true;
|
|
label.text = layout.text;
|
|
label.fontSize = layout.fontSize;
|
|
label.lineHeight = layout.lineHeight;
|
|
label.textAlign = horizontal ? horizontalTextAligns[align] : "center";
|
|
label.textBaseline = horizontal ? "middle" : verticalTextBaselines[align];
|
|
label.x = x;
|
|
label.y = y;
|
|
});
|
|
}
|
|
|
|
// packages/ag-charts-enterprise/src/series/linear-gauge/linearGaugeSeries.ts
|
|
var {
|
|
fromToMotion: fromToMotion2,
|
|
resetMotion: resetMotion3,
|
|
SeriesNodePickMode: SeriesNodePickMode8,
|
|
createDatumId: createDatumId10,
|
|
BBox: BBox20,
|
|
Group: Group12,
|
|
PointerEvents: PointerEvents5,
|
|
Selection: Selection7,
|
|
Rect: Rect8,
|
|
Text: Text3,
|
|
TransformableText: TransformableText2,
|
|
Marker: Marker3,
|
|
LinearScale: LinearScale4,
|
|
generateTicks: generateTicks2,
|
|
NiceMode
|
|
} = _ModuleSupport155;
|
|
var horizontalTargetPlacementRotation = {
|
|
before: 180,
|
|
middle: 0,
|
|
after: 0
|
|
};
|
|
var verticalTargetPlacementRotation = {
|
|
before: 90,
|
|
middle: 0,
|
|
after: -90
|
|
};
|
|
var LinearGaugeSeries = class extends _ModuleSupport155.Series {
|
|
constructor(moduleCtx) {
|
|
super({
|
|
moduleCtx,
|
|
pickModes: [SeriesNodePickMode8.EXACT_SHAPE_MATCH, SeriesNodePickMode8.NEAREST_NODE]
|
|
});
|
|
this.properties = new LinearGaugeSeriesProperties();
|
|
this.seriesRect = BBox20.NaN;
|
|
this.gaugeRect = BBox20.NaN;
|
|
this.scale = new LinearScale4();
|
|
this.originX = 0;
|
|
this.originY = 0;
|
|
this.scaleGroup = this.contentGroup.appendChild(new Group12({ name: "scaleGroup" }));
|
|
this.itemGroup = this.contentGroup.appendChild(new Group12({ name: "itemGroup" }));
|
|
this.itemTargetGroup = this.contentGroup.appendChild(new Group12({ name: "itemTargetGroup" }));
|
|
this.itemTargetLabelGroup = this.contentGroup.appendChild(new Group12({ name: "itemTargetLabelGroup" }));
|
|
this.itemLabelGroup = this.contentGroup.appendChild(new Group12({ name: "itemLabelGroup" }));
|
|
this.highlightTargetGroup = this.highlightGroup.appendChild(
|
|
new Group12({ name: "itemTargetLabelGroup" })
|
|
);
|
|
this.tickGroup = this.contentGroup.appendChild(new Group12({ name: "tickGroup" }));
|
|
this.scaleSelection = Selection7.select(
|
|
this.scaleGroup,
|
|
() => this.nodeFactory()
|
|
);
|
|
this.datumSelection = Selection7.select(
|
|
this.itemGroup,
|
|
() => this.nodeFactory()
|
|
);
|
|
this.targetSelection = Selection7.select(
|
|
this.itemTargetGroup,
|
|
() => this.markerFactory()
|
|
);
|
|
this.targetLabelSelection = Selection7.select(this.itemTargetLabelGroup, Text3);
|
|
this.labelSelection = Selection7.select(
|
|
this.itemLabelGroup,
|
|
Text3
|
|
);
|
|
this.highlightTargetSelection = Selection7.select(this.highlightTargetGroup, () => this.markerFactory());
|
|
this.tickSelection = Selection7.select(this.tickGroup, TransformableText2);
|
|
this.datumUnion = new DatumUnion();
|
|
this.animationState = new StateMachine12("empty", {
|
|
empty: {
|
|
update: {
|
|
target: "ready",
|
|
action: () => this.animateEmptyUpdateReady()
|
|
},
|
|
reset: "empty",
|
|
skip: "ready"
|
|
},
|
|
ready: {
|
|
updateData: "waiting",
|
|
clear: "clearing",
|
|
resize: () => this.animateReadyResize(),
|
|
reset: "empty",
|
|
skip: "ready"
|
|
},
|
|
waiting: {
|
|
update: {
|
|
target: "ready",
|
|
action: () => this.animateWaitingUpdateReady()
|
|
},
|
|
reset: "empty",
|
|
skip: "ready"
|
|
},
|
|
clearing: {
|
|
update: {
|
|
target: "empty"
|
|
},
|
|
reset: "empty",
|
|
skip: "ready"
|
|
}
|
|
});
|
|
this.scaleGroup.pointerEvents = PointerEvents5.None;
|
|
this.tickGroup.pointerEvents = PointerEvents5.None;
|
|
}
|
|
get range() {
|
|
return this.horizontal ? [0, this.gaugeRect.width] : [0, this.gaugeRect.height];
|
|
}
|
|
get horizontal() {
|
|
return this.properties.direction === "horizontal";
|
|
}
|
|
get hasData() {
|
|
return true;
|
|
}
|
|
nodeFactory() {
|
|
const rect = new Rect8();
|
|
rect.crisp = true;
|
|
return rect;
|
|
}
|
|
markerFactory() {
|
|
return new Marker3();
|
|
}
|
|
processData() {
|
|
this.nodeDataRefresh = true;
|
|
this.animationState.transition("updateData");
|
|
}
|
|
formatLabel(value) {
|
|
return formatLabel(value, this.properties.scale);
|
|
}
|
|
getShapeFillBBox() {
|
|
const { properties, originX, originY, horizontal, scale } = this;
|
|
const { thickness } = properties;
|
|
const length = findRangeExtent2(scale.range);
|
|
const bbox = new BBox20(originX, originY, horizontal ? length : thickness, horizontal ? thickness : length);
|
|
return {
|
|
axis: bbox,
|
|
series: bbox
|
|
};
|
|
}
|
|
getTargets() {
|
|
const { properties } = this;
|
|
const defaultTarget = properties.defaultTarget;
|
|
return Array.from(properties.targets).map((target) => {
|
|
const {
|
|
text: text2 = defaultTarget.text,
|
|
value = defaultTarget.value ?? 0,
|
|
shape = defaultTarget.shape ?? "triangle",
|
|
rotation = defaultTarget.rotation ?? 0,
|
|
placement = defaultTarget.placement ?? "middle",
|
|
spacing = defaultTarget.spacing ?? 0,
|
|
size = defaultTarget.size ?? 0
|
|
} = target;
|
|
const {
|
|
enabled: labelEnabled = defaultTarget.label.enabled,
|
|
color: labelColor = defaultTarget.label.color ?? "black",
|
|
fontStyle: labelFontStyle = defaultTarget.label.fontStyle ?? "normal",
|
|
fontWeight: labelFontWeight = defaultTarget.label.fontWeight ?? "normal",
|
|
fontSize: labelFontSize = defaultTarget.label.fontSize,
|
|
fontFamily: labelFontFamily = defaultTarget.label.fontFamily,
|
|
spacing: labelSpacing = defaultTarget.label.spacing ?? 0
|
|
} = target.label;
|
|
return {
|
|
text: text2,
|
|
value,
|
|
shape,
|
|
placement,
|
|
spacing,
|
|
size,
|
|
rotation,
|
|
label: {
|
|
enabled: labelEnabled,
|
|
color: labelColor,
|
|
fontStyle: labelFontStyle,
|
|
fontWeight: labelFontWeight,
|
|
fontSize: labelFontSize,
|
|
fontFamily: labelFontFamily,
|
|
spacing: labelSpacing
|
|
},
|
|
style: target.getStyle(defaultTarget)
|
|
};
|
|
});
|
|
}
|
|
getTargetPoint(target) {
|
|
const { properties, originX, originY, horizontal, scale, gaugeRect } = this;
|
|
const { thickness } = properties;
|
|
const { value, placement, spacing, size } = target;
|
|
const mainOffset = scale.convert(value);
|
|
let crossOffset;
|
|
switch (placement) {
|
|
case "before":
|
|
crossOffset = -(spacing + size / 2);
|
|
break;
|
|
case "after":
|
|
crossOffset = thickness + spacing + size / 2;
|
|
break;
|
|
default:
|
|
crossOffset = thickness / 2;
|
|
break;
|
|
}
|
|
return {
|
|
x: originX + gaugeRect.x + (horizontal ? mainOffset : crossOffset),
|
|
y: originY + gaugeRect.y + (horizontal ? crossOffset : mainOffset)
|
|
};
|
|
}
|
|
getTargetLabel(target) {
|
|
const { size, placement, label } = target;
|
|
const { spacing, color: fill, fontStyle, fontWeight, fontSize, fontFamily } = label;
|
|
const lineHeight = void 0;
|
|
const offset = size / 2 + spacing;
|
|
let textAlign;
|
|
let textBaseline;
|
|
let offsetX = 0;
|
|
let offsetY = 0;
|
|
if (this.horizontal) {
|
|
textAlign = "center";
|
|
if (placement === "after") {
|
|
textBaseline = "top";
|
|
offsetY = offset;
|
|
} else {
|
|
textBaseline = "bottom";
|
|
offsetY = -offset;
|
|
}
|
|
} else {
|
|
textBaseline = "middle";
|
|
if (placement === "before") {
|
|
textAlign = "right";
|
|
offsetX = -offset;
|
|
} else {
|
|
textAlign = "left";
|
|
offsetX = offset;
|
|
}
|
|
}
|
|
return {
|
|
offsetX,
|
|
offsetY,
|
|
fill,
|
|
textAlign,
|
|
textBaseline,
|
|
fontStyle,
|
|
fontWeight,
|
|
fontSize,
|
|
fontFamily,
|
|
lineHeight
|
|
};
|
|
}
|
|
labelDatum(label, value) {
|
|
const {
|
|
placement,
|
|
avoidCollisions,
|
|
spacing,
|
|
text: text2,
|
|
color: fill,
|
|
fontSize,
|
|
minimumFontSize,
|
|
fontStyle,
|
|
fontWeight,
|
|
fontFamily,
|
|
lineHeight,
|
|
wrapping,
|
|
overflowStrategy,
|
|
formatter = (params) => this.formatLabel(params.value)
|
|
} = label;
|
|
return {
|
|
placement,
|
|
avoidCollisions,
|
|
spacing,
|
|
text: text2,
|
|
value,
|
|
fill,
|
|
fontSize,
|
|
minimumFontSize,
|
|
fontStyle,
|
|
fontWeight,
|
|
fontFamily,
|
|
lineHeight,
|
|
wrapping,
|
|
overflowStrategy,
|
|
formatter
|
|
};
|
|
}
|
|
verticalLabelInset() {
|
|
const { label } = this.properties;
|
|
const measurer3 = cachedTextMeasurer7(label);
|
|
const lines = label.text?.split("\n");
|
|
const labelSize = (label.lineHeight ?? measurer3.lineHeight()) * (lines?.length ?? 1);
|
|
return label.spacing + labelSize;
|
|
}
|
|
horizontalLabelInset() {
|
|
const { scale, properties } = this;
|
|
const { scale: scaleProps, label } = properties;
|
|
const lines = label.text?.split("\n");
|
|
const measurer3 = cachedTextMeasurer7(label);
|
|
const ticks = scaleProps.interval.values ?? scale.ticks({
|
|
nice: [false, false],
|
|
interval: scaleProps.interval.step,
|
|
minTickCount: 0,
|
|
maxTickCount: 6,
|
|
tickCount: 5
|
|
})?.ticks ?? [];
|
|
const linesOrTicks = lines ?? ticks?.map((tick) => getLabelText(this.id, this.ctx, this.labelDatum(label, tick)) ?? "");
|
|
const labelSize = linesOrTicks.reduce((accum, text2) => {
|
|
const { width } = isArray4(text2) ? measureTextSegments3(text2, label) : measurer3.measureLines(toTextString3(text2));
|
|
return Math.max(accum, width);
|
|
}, 0);
|
|
return label.spacing + labelSize;
|
|
}
|
|
tickFormatter(domain, ticks) {
|
|
const { format, formatter } = this.properties.scale.label;
|
|
let tickFormatter;
|
|
if (format != null) {
|
|
tickFormatter = tickFormat(ticks, typeof format === "string" ? format : void 0);
|
|
}
|
|
return (value, index) => {
|
|
let r = void 0;
|
|
if (formatter) {
|
|
r ?? (r = formatWithContext(this.ctx, formatter, { value, index, domain, boundSeries: void 0 }));
|
|
}
|
|
r ?? (r = tickFormatter?.(value));
|
|
return r ?? this.formatLabel(value);
|
|
};
|
|
}
|
|
createNodeData() {
|
|
const { id: seriesId, properties, horizontal, scale, seriesRect } = this;
|
|
const {
|
|
value,
|
|
segmentation,
|
|
thickness,
|
|
cornerRadius,
|
|
cornerMode,
|
|
bar,
|
|
scale: scaleProps,
|
|
label,
|
|
defaultColorRange,
|
|
defaultScale
|
|
} = properties;
|
|
scale.domain = [scaleProps.min, scaleProps.max];
|
|
scale.range = horizontal ? [0, seriesRect.width] : [seriesRect.height, 0];
|
|
let axisRotation;
|
|
let sideFlag;
|
|
if (horizontal) {
|
|
sideFlag = 1;
|
|
axisRotation = Math.PI / -2;
|
|
} else if (scaleProps.label.placement === "before") {
|
|
sideFlag = 1;
|
|
axisRotation = 0;
|
|
} else {
|
|
sideFlag = -1;
|
|
axisRotation = 0;
|
|
}
|
|
let x0;
|
|
let x1;
|
|
let y0;
|
|
let y1;
|
|
if (horizontal) {
|
|
x0 = 0;
|
|
x1 = seriesRect.width;
|
|
y0 = (seriesRect.height - thickness) / 2;
|
|
y1 = y0 + thickness;
|
|
if (label.placement === "outside-start") {
|
|
x0 += this.horizontalLabelInset();
|
|
} else if (label.placement === "outside-end") {
|
|
x1 -= this.horizontalLabelInset();
|
|
}
|
|
} else {
|
|
x0 = (seriesRect.width - thickness) / 2;
|
|
x1 = x0 + thickness;
|
|
y1 = 0;
|
|
y0 = seriesRect.height;
|
|
if (label.placement === "outside-start") {
|
|
y0 -= this.verticalLabelInset();
|
|
} else if (label.placement === "outside-end") {
|
|
y1 += this.verticalLabelInset();
|
|
}
|
|
}
|
|
this.gaugeRect = new BBox20(Math.min(x0, x1), Math.min(y0, y1), Math.abs(x1 - x0), Math.abs(y1 - y0));
|
|
const originX = 0;
|
|
const originY = 0;
|
|
scale.domain = [scaleProps.min, scaleProps.max];
|
|
scale.range = horizontal ? [x0, x1] : [y0, y1];
|
|
const scaleLabel = mergeDefaults13({ parallel: horizontal }, scaleProps.label, defaultScale.label);
|
|
const {
|
|
tickData: { ticks: tickData }
|
|
} = generateTicks2({
|
|
scale,
|
|
label: scaleLabel,
|
|
interval: scaleProps.interval,
|
|
tickFormatter: (domain, ticks) => this.tickFormatter(domain, ticks),
|
|
domain: scale.domain,
|
|
range: this.range,
|
|
reverse: false,
|
|
primaryTickCount: void 0,
|
|
defaultTickMinSpacing: 0,
|
|
visibleRange: [0, 1],
|
|
niceMode: [NiceMode.Off, NiceMode.Off],
|
|
labelOffset: 0,
|
|
axisRotation,
|
|
sideFlag
|
|
});
|
|
const isReversed = false;
|
|
const targets = this.getTargets();
|
|
const nodeData = [];
|
|
const targetData = [];
|
|
const labelData = [];
|
|
const scaleData = [];
|
|
const [m0, m1] = scale.range;
|
|
const mainAxisSize = Math.abs(m1 - m0);
|
|
const containerX = horizontal ? scale.convert(value) : x1;
|
|
const containerY = horizontal ? y1 : scale.convert(value);
|
|
const inset = segmentation.enabled ? segmentation.spacing / 2 : 0;
|
|
const horizontalInset = horizontal ? inset : 0;
|
|
const verticalInset = horizontal ? 0 : inset;
|
|
const barThickness = Math.min(bar.thickness ?? Math.round(bar.thicknessRatio * thickness), thickness);
|
|
const barInset = -(thickness - barThickness) / 2;
|
|
const barXInset = horizontal ? 0 : barInset;
|
|
const barYInset = horizontal ? barInset : 0;
|
|
const cornersOnAllItems = cornerMode === "item";
|
|
const maxTicks = Math.ceil(mainAxisSize);
|
|
let segments = segmentation.enabled ? segmentation.interval.getSegments(scale, maxTicks) : void 0;
|
|
const barStyle = bar.getStyle(defaultColorRange, horizontal, scale);
|
|
const scaleStyle = scaleProps.getStyle(bar.enabled, defaultColorRange, horizontal, scale);
|
|
if (segments == null && cornersOnAllItems) {
|
|
const segmentStart = Math.min(...scale.domain);
|
|
const segmentEnd = Math.max(...scale.domain);
|
|
const datum = { value, segmentStart, segmentEnd };
|
|
if (bar.enabled) {
|
|
const barAppliedCornerRadius = Math.min(cornerRadius, barThickness / 2, mainAxisSize / 2);
|
|
const barCornerInset = barAppliedCornerRadius * (isReversed ? -1 : 1);
|
|
const barCornerXInset = horizontal ? barCornerInset : 0;
|
|
const barCornerYInset = horizontal ? 0 : barCornerInset;
|
|
nodeData.push({
|
|
series: this,
|
|
itemId: `value`,
|
|
datum,
|
|
datumIndex: { type: 0 /* Node */ },
|
|
type: 0 /* Node */,
|
|
x0: originX + x0 - barCornerXInset - barXInset,
|
|
y0: originY + y0 - barCornerYInset - barYInset,
|
|
x1: originX + containerX + barCornerXInset + barXInset,
|
|
y1: originY + containerY + barCornerYInset + barYInset,
|
|
clipX0: void 0,
|
|
clipY0: void 0,
|
|
clipX1: void 0,
|
|
clipY1: void 0,
|
|
topLeftCornerRadius: cornerRadius,
|
|
topRightCornerRadius: cornerRadius,
|
|
bottomRightCornerRadius: cornerRadius,
|
|
bottomLeftCornerRadius: cornerRadius,
|
|
horizontalInset,
|
|
verticalInset,
|
|
style: barStyle
|
|
});
|
|
}
|
|
const scaleAppliedCornerRadius = Math.min(cornerRadius, thickness / 2, mainAxisSize / 2);
|
|
const scaleCornerInset = scaleAppliedCornerRadius * (isReversed ? -1 : 1);
|
|
const scaleCornerXInset = horizontal ? scaleCornerInset : 0;
|
|
const scaleCornerYInset = horizontal ? 0 : scaleCornerInset;
|
|
scaleData.push({
|
|
series: this,
|
|
itemId: `scale`,
|
|
datum,
|
|
datumIndex: { type: 0 /* Node */ },
|
|
type: 0 /* Node */,
|
|
x0: originX + x0 - scaleCornerXInset,
|
|
y0: originY + y0 - scaleCornerYInset,
|
|
x1: originX + x1 + scaleCornerXInset,
|
|
y1: originY + y1 + scaleCornerYInset,
|
|
clipX0: void 0,
|
|
clipY0: void 0,
|
|
clipX1: void 0,
|
|
clipY1: void 0,
|
|
topLeftCornerRadius: cornerRadius,
|
|
topRightCornerRadius: cornerRadius,
|
|
bottomRightCornerRadius: cornerRadius,
|
|
bottomLeftCornerRadius: cornerRadius,
|
|
horizontalInset,
|
|
verticalInset,
|
|
style: scaleStyle
|
|
});
|
|
} else {
|
|
segments ?? (segments = scale.domain);
|
|
const clipX0 = originX + x0 - barXInset;
|
|
const clipY0 = originY + y0 - barYInset;
|
|
const clipX1 = originX + containerX + barXInset;
|
|
const clipY1 = originY + containerY + barYInset;
|
|
for (let i = 0; i < segments.length - 1; i += 1) {
|
|
const segmentStart = segments[i + 0];
|
|
const segmentEnd = segments[i + 1];
|
|
const datum = { value, segmentStart, segmentEnd };
|
|
const isStart = i === 0;
|
|
const isEnd = i === segments.length - 2;
|
|
const itemStart = scale.convert(segmentStart);
|
|
const itemEnd = scale.convert(segmentEnd);
|
|
const startCornerRadius = cornersOnAllItems || isStart ? cornerRadius : 0;
|
|
const endCornerRadius = cornersOnAllItems || isEnd ? cornerRadius : 0;
|
|
const topLeftCornerRadius = horizontal ? startCornerRadius : endCornerRadius;
|
|
const topRightCornerRadius = endCornerRadius;
|
|
const bottomRightCornerRadius = horizontal ? endCornerRadius : startCornerRadius;
|
|
const bottomLeftCornerRadius = startCornerRadius;
|
|
if (bar.enabled) {
|
|
nodeData.push({
|
|
series: this,
|
|
itemId: `value-${i}`,
|
|
datum,
|
|
datumIndex: { type: 0 /* Node */ },
|
|
type: 0 /* Node */,
|
|
x0: originX + (horizontal ? itemStart : x0),
|
|
y0: originY + (horizontal ? y0 : itemStart),
|
|
x1: originX + (horizontal ? itemEnd : x1),
|
|
y1: originY + (horizontal ? y1 : itemEnd),
|
|
clipX0,
|
|
clipY0,
|
|
clipX1,
|
|
clipY1,
|
|
topLeftCornerRadius,
|
|
topRightCornerRadius,
|
|
bottomRightCornerRadius,
|
|
bottomLeftCornerRadius,
|
|
horizontalInset,
|
|
verticalInset,
|
|
style: barStyle
|
|
});
|
|
}
|
|
scaleData.push({
|
|
series: this,
|
|
itemId: `scale-${i}`,
|
|
datum,
|
|
datumIndex: { type: 0 /* Node */ },
|
|
type: 0 /* Node */,
|
|
x0: originX + (horizontal ? itemStart : x0),
|
|
y0: originY + (horizontal ? y0 : itemStart),
|
|
x1: originX + (horizontal ? itemEnd : x1),
|
|
y1: originY + (horizontal ? y1 : itemEnd),
|
|
clipX0: void 0,
|
|
clipY0: void 0,
|
|
clipX1: void 0,
|
|
clipY1: void 0,
|
|
topLeftCornerRadius,
|
|
topRightCornerRadius,
|
|
bottomRightCornerRadius,
|
|
bottomLeftCornerRadius,
|
|
horizontalInset,
|
|
verticalInset,
|
|
style: scaleStyle
|
|
});
|
|
}
|
|
}
|
|
for (const dataArray of [scaleData, nodeData]) {
|
|
for (const datum of dataArray) {
|
|
const dx0 = datum.clipX0 ?? datum.x0;
|
|
const dx1 = datum.clipX1 ?? datum.x1;
|
|
const dy0 = datum.clipY0 ?? datum.y0;
|
|
const dy1 = datum.clipY1 ?? datum.y1;
|
|
datum.midPoint = { x: (dx0 + dx1) / 2, y: (dy0 + dy1) / 2 };
|
|
}
|
|
}
|
|
if (label.enabled) {
|
|
labelData.push(this.labelDatum(label, value));
|
|
}
|
|
const targetPlacementRotation2 = horizontal ? horizontalTargetPlacementRotation : verticalTargetPlacementRotation;
|
|
for (let i = 0; i < targets.length; i += 1) {
|
|
const target = targets[i];
|
|
const { value: targetValue, text: text2, shape, size, style } = target;
|
|
const targetPoint = this.getTargetPoint(target);
|
|
const targetRotation = toRadians4(target.rotation + targetPlacementRotation2[target.placement]);
|
|
targetData.push({
|
|
series: this,
|
|
itemId: `target-${i}`,
|
|
midPoint: targetPoint,
|
|
datum: { value: targetValue },
|
|
datumIndex: { type: 1 /* Target */, index: i },
|
|
type: 1 /* Target */,
|
|
value: targetValue,
|
|
text: text2,
|
|
x: targetPoint.x,
|
|
y: targetPoint.y,
|
|
shape,
|
|
size,
|
|
rotation: targetRotation,
|
|
label: this.getTargetLabel(target),
|
|
style
|
|
});
|
|
}
|
|
return {
|
|
itemId: seriesId,
|
|
nodeData,
|
|
tickData,
|
|
targetData,
|
|
labelData,
|
|
scaleData
|
|
};
|
|
}
|
|
findNodeDatum(itemId) {
|
|
return findGaugeNodeDatum(this, itemId);
|
|
}
|
|
updateSelections(resize) {
|
|
if (this.nodeDataRefresh || resize) {
|
|
this.contextNodeData = this.createNodeData();
|
|
this.nodeDataRefresh = false;
|
|
}
|
|
}
|
|
highlightDatum(node) {
|
|
if (node?.series === this && node.type === 1 /* Target */) {
|
|
return node;
|
|
}
|
|
}
|
|
update({ seriesRect }) {
|
|
const {
|
|
datumSelection,
|
|
labelSelection,
|
|
targetSelection,
|
|
targetLabelSelection,
|
|
scaleSelection,
|
|
highlightTargetSelection,
|
|
tickSelection
|
|
} = this;
|
|
this.seriesRect = seriesRect ?? BBox20.NaN;
|
|
const resize = this.checkResize(seriesRect);
|
|
this.updateSelections(resize);
|
|
this.contentGroup.visible = this.visible;
|
|
this.contentGroup.opacity = this.getOpacity();
|
|
const nodeData = this.contextNodeData?.nodeData ?? [];
|
|
const labelData = this.contextNodeData?.labelData ?? [];
|
|
const targetData = this.contextNodeData?.targetData ?? [];
|
|
const scaleData = this.contextNodeData?.scaleData ?? [];
|
|
const tickData = this.contextNodeData?.tickData ?? [];
|
|
const highlightTargetDatum = this.highlightDatum(this.ctx.highlightManager.getActiveHighlight());
|
|
this.scaleSelection = this.updateScaleSelection({ scaleData, scaleSelection });
|
|
this.updateScaleNodes({ scaleSelection });
|
|
this.targetSelection = this.updateTargetSelection({ targetData, targetSelection });
|
|
this.updateTargetNodes({ targetSelection, isHighlight: false });
|
|
this.targetLabelSelection = this.updateTargetLabelSelection({ targetData, targetLabelSelection });
|
|
this.updateTargetLabelNodes({ targetLabelSelection });
|
|
this.datumSelection = this.updateDatumSelection({ nodeData, datumSelection });
|
|
this.updateDatumNodes({ datumSelection });
|
|
this.labelSelection = this.updateLabelSelection({ labelData, labelSelection });
|
|
this.updateLabelNodes({ labelSelection });
|
|
this.highlightTargetSelection = this.updateTargetSelection({
|
|
targetData: highlightTargetDatum == null ? [] : [highlightTargetDatum],
|
|
targetSelection: highlightTargetSelection
|
|
});
|
|
this.updateTargetNodes({ targetSelection: highlightTargetSelection, isHighlight: true });
|
|
this.tickSelection = this.updateTickSelection({ tickData, tickSelection });
|
|
this.updateTickNodes({ tickSelection });
|
|
if (resize) {
|
|
this.animationState.transition("resize");
|
|
}
|
|
this.animationState.transition("update");
|
|
}
|
|
updateDatumSelection(opts) {
|
|
return opts.datumSelection.update(opts.nodeData, void 0, (datum) => {
|
|
return createDatumId10(opts.nodeData.length, datum.itemId);
|
|
});
|
|
}
|
|
updateDatumNodes(opts) {
|
|
const { datumSelection } = opts;
|
|
const { ctx } = this;
|
|
const animationDisabled = ctx.animationManager.isSkipped();
|
|
const fillBBox = this.getShapeFillBBox();
|
|
datumSelection.each((rect, datum) => {
|
|
const { topLeftCornerRadius, topRightCornerRadius, bottomRightCornerRadius, bottomLeftCornerRadius } = datum;
|
|
rect.setStyleProperties(datum.style, fillBBox);
|
|
rect.topLeftCornerRadius = topLeftCornerRadius;
|
|
rect.topRightCornerRadius = topRightCornerRadius;
|
|
rect.bottomRightCornerRadius = bottomRightCornerRadius;
|
|
rect.bottomLeftCornerRadius = bottomLeftCornerRadius;
|
|
rect.pointerEvents = this.properties.bar.enabled ? _ModuleSupport155.PointerEvents.All : _ModuleSupport155.PointerEvents.None;
|
|
if (animationDisabled || rect.previousDatum == null) {
|
|
rect.setProperties(resetLinearGaugeSeriesResetRectFunction(rect, datum));
|
|
}
|
|
});
|
|
const { horizontal } = this;
|
|
this.datumUnion.update(datumSelection, this.itemGroup, _ModuleSupport155.Rect, (node, first, last) => {
|
|
const left = Math.min(first.x, last.x);
|
|
const right = Math.max(first.x + first.width, last.x + last.width);
|
|
const top = Math.min(first.y, last.y);
|
|
const bottom = Math.max(first.y + first.height, last.y + last.height);
|
|
const width = right - left;
|
|
const height = bottom - top;
|
|
node.pointerEvents = _ModuleSupport155.PointerEvents.None;
|
|
node.x = left;
|
|
node.y = top;
|
|
node.width = width;
|
|
node.height = height;
|
|
node.topLeftCornerRadius = horizontal ? first.topLeftCornerRadius : last.topLeftCornerRadius;
|
|
node.topRightCornerRadius = last.topRightCornerRadius;
|
|
node.bottomRightCornerRadius = horizontal ? last.bottomRightCornerRadius : first.bottomRightCornerRadius;
|
|
node.bottomLeftCornerRadius = first.bottomLeftCornerRadius;
|
|
const firstClipBBox = first.clipBBox;
|
|
const lastClipBBox = last.clipBBox ?? firstClipBBox;
|
|
if (firstClipBBox && lastClipBBox) {
|
|
node.clipBBox = BBox20.merge([firstClipBBox, lastClipBBox]).intersection(
|
|
horizontal ? new BBox20(left, -Infinity, width, Infinity) : new BBox20(-Infinity, top, Infinity, height)
|
|
);
|
|
} else {
|
|
node.clipBBox = void 0;
|
|
}
|
|
});
|
|
}
|
|
updateScaleSelection(opts) {
|
|
return opts.scaleSelection.update(opts.scaleData, void 0, (datum) => {
|
|
return createDatumId10(opts.scaleData.length, datum.itemId);
|
|
});
|
|
}
|
|
updateScaleNodes(opts) {
|
|
const { scaleSelection } = opts;
|
|
const fillBBox = this.getShapeFillBBox();
|
|
scaleSelection.each((rect, datum) => {
|
|
const { topLeftCornerRadius, topRightCornerRadius, bottomRightCornerRadius, bottomLeftCornerRadius } = datum;
|
|
rect.setStyleProperties(datum.style, fillBBox);
|
|
rect.setProperties(resetLinearGaugeSeriesResetRectFunction(rect, datum));
|
|
rect.topLeftCornerRadius = topLeftCornerRadius;
|
|
rect.topRightCornerRadius = topRightCornerRadius;
|
|
rect.bottomRightCornerRadius = bottomRightCornerRadius;
|
|
rect.bottomLeftCornerRadius = bottomLeftCornerRadius;
|
|
rect.setProperties(resetLinearGaugeSeriesResetRectFunction(rect, datum));
|
|
});
|
|
}
|
|
updateTargetSelection(opts) {
|
|
return opts.targetSelection.update(opts.targetData, void 0, (target) => target.itemId);
|
|
}
|
|
updateTargetNodes(opts) {
|
|
const { targetSelection, isHighlight } = opts;
|
|
targetSelection.each((target, datum) => {
|
|
const { x, y, shape, size, rotation } = datum;
|
|
const style = this.getTargetStyle(isHighlight, datum);
|
|
target.setStyleProperties(style);
|
|
target.size = size;
|
|
target.shape = shape === "line" ? lineMarker : shape;
|
|
target.translationX = x;
|
|
target.translationY = y;
|
|
target.rotation = rotation;
|
|
});
|
|
}
|
|
getTargetStyle(isHighlight, { datumIndex, style }) {
|
|
const highlightStyle = this.getHighlightStyle(isHighlight, datumIndex);
|
|
return mergeDefaults13(highlightStyle, {
|
|
...style,
|
|
opacity: 1
|
|
});
|
|
}
|
|
updateTargetLabelSelection(opts) {
|
|
return opts.targetLabelSelection.update(opts.targetData);
|
|
}
|
|
updateTargetLabelNodes(opts) {
|
|
const { targetLabelSelection } = opts;
|
|
targetLabelSelection.each((label, target) => {
|
|
const { x, y, text: text2 } = target;
|
|
const { offsetX, offsetY, fill, fontStyle, fontWeight, fontSize, fontFamily, textAlign, textBaseline } = target.label;
|
|
label.visible = true;
|
|
label.x = x + offsetX;
|
|
label.y = y + offsetY;
|
|
label.text = text2;
|
|
label.fill = fill;
|
|
label.fontStyle = fontStyle;
|
|
label.fontWeight = fontWeight;
|
|
label.fontSize = fontSize;
|
|
label.fontFamily = fontFamily;
|
|
label.textAlign = textAlign;
|
|
label.textBaseline = textBaseline;
|
|
});
|
|
}
|
|
updateTickSelection(opts) {
|
|
return opts.tickSelection.update(opts.tickData, void 0, (datum) => datum.tickId);
|
|
}
|
|
updateTickNodes(opts) {
|
|
const { gaugeRect, properties } = this;
|
|
const defaultScale = properties.defaultScale;
|
|
const {
|
|
enabled,
|
|
color: color7,
|
|
fontFamily = defaultScale.label.fontFamily,
|
|
fontSize = defaultScale.label.fontSize,
|
|
fontStyle,
|
|
fontWeight = defaultScale.label.fontWeight,
|
|
spacing
|
|
} = properties.scale.label;
|
|
let { placement } = properties.scale.label;
|
|
const rotation = toRadians4(properties.scale.label.rotation ?? 0);
|
|
let textAlign;
|
|
let textBaseline;
|
|
let textX;
|
|
let textY;
|
|
if (this.horizontal) {
|
|
placement ?? (placement = "after");
|
|
textAlign = "center";
|
|
textBaseline = placement === "before" ? "bottom" : "top";
|
|
textY = this.originY + gaugeRect.y + (placement === "before" ? -spacing : gaugeRect.height + spacing);
|
|
} else {
|
|
placement ?? (placement = "before");
|
|
textAlign = placement === "before" ? "end" : "start";
|
|
textBaseline = "middle";
|
|
textX = this.originX + gaugeRect.x + (placement === "before" ? -spacing : gaugeRect.width + spacing);
|
|
}
|
|
opts.tickSelection.each((label, datum) => {
|
|
if (!enabled) {
|
|
label.visible = false;
|
|
return;
|
|
}
|
|
const x = textX ?? datum.translation;
|
|
const y = textY ?? datum.translation;
|
|
label.visible = true;
|
|
label.text = datum.tickLabel;
|
|
label.fill = color7;
|
|
label.fontFamily = fontFamily;
|
|
label.fontSize = fontSize;
|
|
label.fontStyle = fontStyle;
|
|
label.fontWeight = fontWeight;
|
|
label.textBaseline = textBaseline;
|
|
label.textAlign = textAlign;
|
|
label.x = x;
|
|
label.y = y;
|
|
label.rotationCenterX = x;
|
|
label.rotationCenterY = y;
|
|
label.rotation = rotation;
|
|
});
|
|
}
|
|
updateLabelSelection(opts) {
|
|
return opts.labelSelection.update(opts.labelData, void 0, (_datum) => "primary");
|
|
}
|
|
updateLabelNodes(opts) {
|
|
const { labelSelection } = opts;
|
|
const animationDisabled = this.ctx.animationManager.isSkipped();
|
|
labelSelection.each((label, datum) => {
|
|
label.fill = datum.fill;
|
|
label.fontStyle = datum.fontStyle;
|
|
label.fontWeight = datum.fontWeight;
|
|
label.fontFamily = datum.fontFamily;
|
|
});
|
|
if (animationDisabled || this.labelsHaveExplicitText()) {
|
|
this.formatLabelText();
|
|
}
|
|
}
|
|
labelsHaveExplicitText() {
|
|
for (const { datum } of this.labelSelection) {
|
|
if (datum.text == null) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
formatLabelText(datum) {
|
|
const { labelSelection, horizontal, scale, seriesRect, gaugeRect } = this;
|
|
const { x, y, width, height } = gaugeRect;
|
|
const value = datum?.label ?? this.properties.value;
|
|
let barRect;
|
|
if (horizontal) {
|
|
const xValue = scale.convert(value);
|
|
barRect = new BBox20(x, y, xValue - x, height);
|
|
} else {
|
|
const yValue = scale.convert(value);
|
|
barRect = new BBox20(x, yValue, width, height - yValue);
|
|
}
|
|
const bboxes = { seriesRect, gaugeRect, barRect };
|
|
const { margin: padding2 } = this.properties;
|
|
formatLinearGaugeLabels(this, this.ctx, labelSelection, { padding: padding2, horizontal }, bboxes, datum);
|
|
}
|
|
resetAllAnimation() {
|
|
this.ctx.animationManager.stopByAnimationGroupId(this.id);
|
|
resetMotion3([this.datumSelection], resetLinearGaugeSeriesResetRectFunction);
|
|
this.formatLabelText();
|
|
}
|
|
resetAnimation(phase) {
|
|
if (phase === "initial") {
|
|
this.animationState.transition("reset");
|
|
} else if (phase === "ready") {
|
|
this.animationState.transition("skip");
|
|
}
|
|
}
|
|
animateLabelText(params = {}) {
|
|
const { animationManager } = this.ctx;
|
|
let labelFrom = 0;
|
|
let labelTo = 0;
|
|
this.labelSelection.each((label, datum) => {
|
|
label.opacity = 1;
|
|
labelFrom = label.previousDatum?.value ?? params.from ?? datum.value;
|
|
labelTo = datum.value;
|
|
});
|
|
if (this.labelsHaveExplicitText()) {
|
|
} else if (labelFrom === labelTo) {
|
|
this.formatLabelText({ label: labelTo });
|
|
} else {
|
|
const animationId = `${this.id}_labels`;
|
|
animationManager.animate({
|
|
id: animationId,
|
|
groupId: "label",
|
|
from: { label: labelFrom },
|
|
to: { label: labelTo },
|
|
phase: params.phase ?? "update",
|
|
ease: easeOut2,
|
|
onUpdate: (datum) => this.formatLabelText(datum),
|
|
onStop: () => this.formatLabelText({ label: labelTo })
|
|
});
|
|
}
|
|
}
|
|
animateEmptyUpdateReady() {
|
|
const { animationManager } = this.ctx;
|
|
const { node } = prepareLinearGaugeSeriesAnimationFunctions(true, this.horizontal);
|
|
fromToMotion2(this.id, "node", animationManager, [this.datumSelection], node, (_sector, datum) => datum.itemId);
|
|
fromToMotion2(this.id, "label", animationManager, [this.labelSelection], fadeInFns, () => "primary");
|
|
this.animateLabelText({ from: 0, phase: "initial" });
|
|
}
|
|
animateWaitingUpdateReady() {
|
|
const { animationManager } = this.ctx;
|
|
const { node } = prepareLinearGaugeSeriesAnimationFunctions(false, this.horizontal);
|
|
fromToMotion2(this.id, "node", animationManager, [this.datumSelection], node, (_sector, datum) => datum.itemId);
|
|
this.animateLabelText();
|
|
}
|
|
animateReadyResize() {
|
|
this.resetAllAnimation();
|
|
}
|
|
getSeriesDomain() {
|
|
return { domain: [0, 1] };
|
|
}
|
|
dataCount() {
|
|
return Number.NaN;
|
|
}
|
|
getSeriesRange() {
|
|
return [Number.NaN, Number.NaN];
|
|
}
|
|
getLegendData() {
|
|
return [];
|
|
}
|
|
getTooltipContent(datumIndex) {
|
|
const { id: seriesId, properties } = this;
|
|
const { tooltip } = properties;
|
|
if (datumIndex == null)
|
|
return;
|
|
let value;
|
|
let text2;
|
|
let fallbackLabel;
|
|
if (datumIndex.type === 0 /* Node */) {
|
|
value = properties.value;
|
|
text2 = properties.label.text;
|
|
fallbackLabel = this.ctx.localeManager.t("ariaLabelGaugeValue");
|
|
} else {
|
|
({ value, text: text2 } = properties.targets[datumIndex.index]);
|
|
fallbackLabel = this.ctx.localeManager.t("ariaLabelGaugeTarget");
|
|
}
|
|
if (value == null)
|
|
return;
|
|
return this.formatTooltipWithContext(
|
|
tooltip,
|
|
{
|
|
data: [{ label: text2, fallbackLabel, value: this.formatLabel(value) }]
|
|
},
|
|
{ seriesId, title: void 0, datum: void 0, value }
|
|
);
|
|
}
|
|
pickNodeClosestDatum(point) {
|
|
return pickGaugeNearestDatum(this, point);
|
|
}
|
|
pickFocus(opts) {
|
|
return pickGaugeFocus(this, opts);
|
|
}
|
|
getCaptionText() {
|
|
return this.formatLabel(this.properties.value);
|
|
}
|
|
getCategoryValue(_datumIndex) {
|
|
return;
|
|
}
|
|
datumIndexForCategoryValue(_categoryValue) {
|
|
return;
|
|
}
|
|
hasItemStylers() {
|
|
return this.properties.label.itemStyler != null;
|
|
}
|
|
};
|
|
LinearGaugeSeries.className = "LinearGaugeSeries";
|
|
LinearGaugeSeries.type = "linear-gauge";
|
|
|
|
// packages/ag-charts-enterprise/src/series/linear-gauge/linearGaugeModule.ts
|
|
var themeTemplate2 = {
|
|
minWidth: 200,
|
|
minHeight: 200,
|
|
tooltip: {
|
|
enabled: false
|
|
},
|
|
series: {
|
|
thickness: 50,
|
|
defaultColorRange: {
|
|
$if: [
|
|
{ $eq: [{ $palette: "type" }, "inbuilt"] },
|
|
{ $interpolate: [{ $palette: "secondDivergingColors" }, 5] },
|
|
SAFE_RANGE2_OPERATION3
|
|
]
|
|
},
|
|
scale: {
|
|
// @ts-expect-error undocumented option
|
|
defaultFill: { $path: ["/1", { $palette: "fill" }, { $palette: "hierarchyColors" }] },
|
|
// TODO: mix backgroundColor and foregroundColor?
|
|
stroke: { $path: ["/2", SAFE_STROKE_FILL_OPERATION, { $palette: "hierarchyColors" }] },
|
|
// TODO: mix backgroundColor and foregroundColor?
|
|
strokeWidth: { $isUserOption: ["./stroke", 2, 0] },
|
|
label: {
|
|
spacing: 11
|
|
}
|
|
},
|
|
bar: {
|
|
strokeWidth: { $isUserOption: ["./stroke", 2, 0] }
|
|
},
|
|
segmentation: {
|
|
enabled: false,
|
|
interval: {},
|
|
spacing: 1
|
|
},
|
|
defaultTarget: {
|
|
fill: { $ref: "foregroundColor" },
|
|
stroke: { $ref: "foregroundColor" },
|
|
size: 10,
|
|
shape: "triangle",
|
|
placement: "after",
|
|
spacing: 5,
|
|
label: {
|
|
enabled: true,
|
|
fontWeight: { $ref: "fontWeight" },
|
|
fontSize: { $ref: "fontSize" },
|
|
fontFamily: { $ref: "fontFamily" },
|
|
color: { $ref: "textColor" },
|
|
spacing: 5
|
|
}
|
|
},
|
|
defaultScale: {
|
|
label: {
|
|
fontWeight: { $ref: "fontWeight" },
|
|
fontSize: { $ref: "fontSize" },
|
|
fontFamily: { $ref: "fontFamily" },
|
|
color: { $ref: "textColor" }
|
|
}
|
|
},
|
|
label: {
|
|
...LABEL_BOXING_DEFAULTS8,
|
|
enabled: false,
|
|
placement: "inside-start",
|
|
fontFamily: { $ref: "fontFamily" },
|
|
fontWeight: { $ref: "fontWeight" },
|
|
fontSize: { $rem: 2 },
|
|
minimumFontSize: FONT_SIZE2.SMALL,
|
|
spacing: 18,
|
|
color: { $ref: "chartBackgroundColor" }
|
|
},
|
|
margin: 4,
|
|
tooltip: {
|
|
range: { $path: ["/tooltip/range", 10] }
|
|
}
|
|
}
|
|
};
|
|
var LinearGaugeModule = {
|
|
type: "series",
|
|
name: "linear-gauge",
|
|
chartType: "standalone",
|
|
enterprise: true,
|
|
dependencies: [GaugePresetModule],
|
|
version: VERSION34,
|
|
options: linearGaugeSeriesOptionsDef2,
|
|
themeTemplate: themeTemplate2,
|
|
create: (ctx) => new LinearGaugeSeries(ctx)
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/series/map-line/mapLineModule.ts
|
|
import { VERSION as VERSION36 } from "ag-charts-community";
|
|
import {
|
|
LABEL_BOXING_DEFAULTS as LABEL_BOXING_DEFAULTS9,
|
|
MULTI_SERIES_HIGHLIGHT_STYLE as MULTI_SERIES_HIGHLIGHT_STYLE4,
|
|
SAFE_RANGE2_OPERATION as SAFE_RANGE2_OPERATION4,
|
|
SAFE_STROKE_FILL_OPERATION as SAFE_STROKE_FILL_OPERATION2
|
|
} from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/charts/topologyChartModule.ts
|
|
import { VERSION as VERSION35, _ModuleSupport as _ModuleSupport157 } from "ag-charts-community";
|
|
|
|
// packages/ag-charts-enterprise/src/charts/topologyChart.ts
|
|
import { _ModuleSupport as _ModuleSupport156 } from "ag-charts-community";
|
|
import { ChartAxisDirection as ChartAxisDirection44, Property as Property74, createId as createId7 } from "ag-charts-core";
|
|
var { Chart: Chart2, MercatorScale } = _ModuleSupport156;
|
|
function isTopologySeries(series) {
|
|
return series.type === "map-shape" || series.type === "map-line" || series.type === "map-marker" || series.type === "map-shape-background" || series.type === "map-line-background";
|
|
}
|
|
var TopologyChart = class extends Chart2 {
|
|
constructor(options, resources) {
|
|
super(options, resources);
|
|
this.xAxis = { id: createId7(_ModuleSupport156.Axis), direction: ChartAxisDirection44.X };
|
|
this.yAxis = { id: createId7(_ModuleSupport156.Axis), direction: ChartAxisDirection44.Y };
|
|
this.ctx.zoomManager.setAxes([this.xAxis, this.yAxis]);
|
|
}
|
|
getChartType() {
|
|
return "topology";
|
|
}
|
|
updateData() {
|
|
super.updateData();
|
|
const options = this.getOptions();
|
|
if (this.topology !== options.topology) {
|
|
this.topology = options.topology;
|
|
}
|
|
const { topology } = this;
|
|
for (const series of this.series) {
|
|
if (isTopologySeries(series)) {
|
|
series.setChartTopology(topology);
|
|
}
|
|
}
|
|
}
|
|
performLayout(ctx) {
|
|
const { seriesRoot, annotationRoot } = this;
|
|
const seriesRect = ctx.layoutBox.clone().shrink(this.seriesArea.getPadding());
|
|
this.seriesRect = seriesRect;
|
|
this.animationRect = seriesRect;
|
|
const mapSeries = this.series;
|
|
const combinedBbox = mapSeries.reduce((combined, series) => {
|
|
if (!series.visible)
|
|
return combined;
|
|
const bbox = series.topologyBounds;
|
|
if (bbox == null)
|
|
return combined;
|
|
if (combined == null)
|
|
return bbox;
|
|
return combined.merge(bbox);
|
|
}, void 0);
|
|
let scale;
|
|
if (combinedBbox != null) {
|
|
const { lon0, lat0, lon1, lat1 } = combinedBbox;
|
|
const domain = [
|
|
[lon0, lat0],
|
|
[lon1, lat1]
|
|
];
|
|
const bounds = MercatorScale.bounds(domain);
|
|
const { width, height } = seriesRect;
|
|
const viewBoxScale = Math.min(width / bounds.width, height / bounds.height);
|
|
const viewBoxWidth = bounds.width * viewBoxScale;
|
|
const viewBoxHeight = bounds.height * viewBoxScale;
|
|
const viewBoxOriginX = (width - viewBoxWidth) / 2;
|
|
const viewBoxOriginY = (height - viewBoxHeight) / 2;
|
|
const x0 = viewBoxOriginX;
|
|
const y0 = viewBoxOriginY;
|
|
const x1 = viewBoxOriginX + viewBoxWidth;
|
|
const y1 = viewBoxOriginY + viewBoxHeight;
|
|
const xZoom = this.ctx.zoomManager.getAxisZoom(this.xAxis.id);
|
|
const yZoom = this.ctx.zoomManager.getAxisZoom(this.yAxis.id);
|
|
const xSpan = (x1 - x0) / (xZoom.max - xZoom.min);
|
|
const xStart = x0 - xSpan * xZoom.min;
|
|
const ySpan = (y1 - y0) / (1 - yZoom.min - (1 - yZoom.max));
|
|
const yStart = y0 - ySpan * (1 - yZoom.max);
|
|
scale = new MercatorScale(domain, [
|
|
[xStart, yStart],
|
|
[xStart + xSpan, yStart + ySpan]
|
|
]);
|
|
}
|
|
for (const series of mapSeries) {
|
|
series.scale = scale;
|
|
}
|
|
const seriesVisible = this.series.some((s) => s.visible);
|
|
seriesRoot.visible = seriesVisible;
|
|
for (const group of [seriesRoot, annotationRoot]) {
|
|
group.translationX = Math.floor(seriesRect.x);
|
|
group.translationY = Math.floor(seriesRect.y);
|
|
group.setClipRect(seriesRect.clone());
|
|
}
|
|
this.ctx.layoutManager.emitLayoutComplete(ctx, {
|
|
series: { visible: seriesVisible, rect: seriesRect, paddedRect: ctx.layoutBox }
|
|
});
|
|
}
|
|
};
|
|
TopologyChart.className = "TopologyChart";
|
|
TopologyChart.type = "topology";
|
|
__decorateClass([
|
|
Property74
|
|
], TopologyChart.prototype, "topology", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/charts/topologyChartModule.ts
|
|
var { topologyChartOptionsDefs } = _ModuleSupport157;
|
|
var TopologyChartModule = {
|
|
type: "chart",
|
|
name: "topology",
|
|
enterprise: true,
|
|
version: VERSION35,
|
|
options: topologyChartOptionsDefs,
|
|
create(options, resources) {
|
|
return new TopologyChart(options, resources);
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/series/map-util/mapThemeDefaults.ts
|
|
import { deepClone as deepClone3, jsonWalk } from "ag-charts-core";
|
|
var MAP_THEME_DEFAULTS = {
|
|
zoom: {
|
|
axes: "xy",
|
|
anchorPointX: "pointer",
|
|
anchorPointY: "pointer",
|
|
buttons: {
|
|
// @ts-expect-error undocumented options
|
|
anchorPointX: "middle",
|
|
anchorPointY: "middle"
|
|
}
|
|
},
|
|
legend: {
|
|
enabled: false
|
|
}
|
|
};
|
|
function applyMapPalette(object) {
|
|
const clone = deepClone3(object);
|
|
jsonWalk(clone, (value) => {
|
|
if (typeof value === "object" && "$palette" in value) {
|
|
value["$mapPalette"] = value["$palette"];
|
|
delete value["$palette"];
|
|
}
|
|
});
|
|
return clone;
|
|
}
|
|
|
|
// packages/ag-charts-enterprise/src/series/map-line/mapLineSeries.ts
|
|
import { _ModuleSupport as _ModuleSupport162 } from "ag-charts-community";
|
|
import { Logger as Logger17, cachedTextMeasurer as cachedTextMeasurer8, mergeDefaults as mergeDefaults14 } from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/series/map-util/geoGeometry.ts
|
|
import { _ModuleSupport as _ModuleSupport158 } from "ag-charts-community";
|
|
import { SceneChangeDetection as SceneChangeDetection8, SceneObjectChangeDetection, objectsEqual as objectsEqual2 } from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/series/map-util/lineStringUtil.ts
|
|
var delta2 = 1e-9;
|
|
function lineSegmentDistanceToPointSquared(a, b, x, y) {
|
|
const [ax, ay] = a;
|
|
const [bx, by] = b;
|
|
const abx = bx - ax;
|
|
const aby = by - ay;
|
|
const l = abx * abx + aby * aby;
|
|
let x0;
|
|
let y0;
|
|
if (Math.abs(l) < delta2) {
|
|
x0 = ax;
|
|
y0 = ay;
|
|
} else {
|
|
let t = ((x - ax) * abx + (y - ay) * aby) / l;
|
|
t = Math.max(0, Math.min(1, t));
|
|
x0 = ax + t * (bx - ax);
|
|
y0 = ay + t * (by - ay);
|
|
}
|
|
const dx2 = x - x0;
|
|
const dy2 = y - y0;
|
|
return dx2 * dx2 + dy2 * dy2;
|
|
}
|
|
function lineStringDistance(lineString, x, y) {
|
|
let minDistanceSquared = Infinity;
|
|
let p0 = lineString.at(-1);
|
|
for (const p1 of lineString) {
|
|
minDistanceSquared = Math.min(minDistanceSquared, lineSegmentDistanceToPointSquared(p0, p1, x, y));
|
|
p0 = p1;
|
|
}
|
|
return Math.sqrt(minDistanceSquared);
|
|
}
|
|
function lineStringLength(lineSegment) {
|
|
let [x0, y0] = lineSegment[0];
|
|
let totalDistance = 0;
|
|
for (let i = 1; i < lineSegment.length; i += 1) {
|
|
const [x1, y1] = lineSegment[i];
|
|
const distance = Math.hypot(x1 - x0, y1 - y0);
|
|
totalDistance += distance;
|
|
x0 = x1;
|
|
y0 = y1;
|
|
}
|
|
return totalDistance;
|
|
}
|
|
function lineStringCenter(lineSegment) {
|
|
if (lineSegment.length === 0)
|
|
return;
|
|
const targetDistance = lineStringLength(lineSegment) / 2;
|
|
let [x0, y0] = lineSegment[0];
|
|
let totalDistance = 0;
|
|
for (let i = 1; i < lineSegment.length; i += 1) {
|
|
const [x1, y1] = lineSegment[i];
|
|
const segmentDistance = Math.hypot(x1 - x0, y1 - y0);
|
|
const nextDistance = totalDistance + segmentDistance;
|
|
if (nextDistance > targetDistance) {
|
|
const ratio8 = (targetDistance - totalDistance) / segmentDistance;
|
|
const point = [x0 + (x1 - x0) * ratio8, y0 + (y1 - y0) * ratio8];
|
|
const angle = Math.atan2(y1 - y0, x1 - x0);
|
|
return { point, angle };
|
|
}
|
|
totalDistance = nextDistance;
|
|
x0 = x1;
|
|
y0 = y1;
|
|
}
|
|
}
|
|
|
|
// packages/ag-charts-enterprise/src/series/map-util/lonLatBbox.ts
|
|
var LonLatBBox = class _LonLatBBox {
|
|
constructor(lon0, lat0, lon1, lat1) {
|
|
this.lon0 = lon0;
|
|
this.lat0 = lat0;
|
|
this.lon1 = lon1;
|
|
this.lat1 = lat1;
|
|
}
|
|
extend(lon0, lat0, lon1, lat1) {
|
|
this.lon0 = Math.min(this.lon0, lon0);
|
|
this.lat0 = Math.min(this.lat0, lat0);
|
|
this.lon1 = Math.max(this.lon1, lon1);
|
|
this.lat1 = Math.max(this.lat1, lat1);
|
|
return this;
|
|
}
|
|
merge(other) {
|
|
return this.extend(other.lon0, other.lat0, other.lon1, other.lat1);
|
|
}
|
|
static extend(into, lon0, lat0, lon1, lat1) {
|
|
return into ? into.extend(lon0, lat0, lon1, lat1) : new _LonLatBBox(lon0, lat0, lon1, lat1);
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/series/map-util/polygonUtil.ts
|
|
function polygonBbox(polygon, into) {
|
|
for (const coordinates of polygon) {
|
|
const [lon, lat] = coordinates;
|
|
into = LonLatBBox.extend(into, lon, lat, lon, lat);
|
|
}
|
|
return into;
|
|
}
|
|
function polygonCentroid(polygon) {
|
|
if (polygon.length === 0)
|
|
return;
|
|
let x = 0;
|
|
let y = 0;
|
|
let k = 0;
|
|
let [x0, y0] = polygon.at(-1);
|
|
for (const [x1, y1] of polygon) {
|
|
const c = x0 * y1 - x1 * y0;
|
|
k += c;
|
|
x += (x0 + x1) * c;
|
|
y += (y0 + y1) * c;
|
|
x0 = x1;
|
|
y0 = y1;
|
|
}
|
|
k *= 3;
|
|
return [x / k, y / k];
|
|
}
|
|
function polygonDistance(polygons, x, y) {
|
|
let inside = false;
|
|
let minDistanceSquared = Infinity;
|
|
for (const polygon of polygons) {
|
|
let p0 = polygon.at(-1);
|
|
let [x0, y0] = p0;
|
|
for (const p1 of polygon) {
|
|
const [x1, y1] = p1;
|
|
if (y1 > y !== y0 > y && x < (x0 - x1) * (y - y1) / (y0 - y1) + x1) {
|
|
inside = !inside;
|
|
}
|
|
minDistanceSquared = Math.min(minDistanceSquared, lineSegmentDistanceToPointSquared(p0, p1, x, y));
|
|
p0 = p1;
|
|
x0 = x1;
|
|
y0 = y1;
|
|
}
|
|
}
|
|
return (inside ? -1 : 1) * Math.sqrt(minDistanceSquared);
|
|
}
|
|
|
|
// packages/ag-charts-enterprise/src/series/map-util/geoGeometry.ts
|
|
var { Path: Path11, ExtendedPath2D: ExtendedPath2D5, BBox: BBox21 } = _ModuleSupport158;
|
|
var GeoGeometry = class extends Path11 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.projectedGeometry = void 0;
|
|
this.renderMode = 3 /* All */;
|
|
// Keep non-filled shapes separate so we don't fill them
|
|
this.strokePath = new ExtendedPath2D5();
|
|
}
|
|
computeBBox() {
|
|
if (this.dirtyPath || this.isDirtyPath()) {
|
|
this.updatePath();
|
|
this.dirtyPath = false;
|
|
}
|
|
return this.bbox?.clone();
|
|
}
|
|
updatePath() {
|
|
const { projectedGeometry } = this;
|
|
this.strokePath.clear();
|
|
this.path.clear();
|
|
this.bbox = projectedGeometry == null ? void 0 : this.drawGeometry(projectedGeometry, void 0);
|
|
}
|
|
drawPath(ctx) {
|
|
super.drawPath(ctx);
|
|
this.renderStroke(ctx, this.strokePath.getPath2D());
|
|
}
|
|
containsPoint(x, y) {
|
|
const { projectedGeometry } = this;
|
|
if (projectedGeometry == null)
|
|
return false;
|
|
if (!this.getBBox().containsPoint(x, y))
|
|
return false;
|
|
return this.geometryDistance(projectedGeometry, x, y) <= 0;
|
|
}
|
|
distanceSquared(x, y) {
|
|
const { projectedGeometry } = this;
|
|
if (projectedGeometry == null)
|
|
return Infinity;
|
|
const distance = this.geometryDistance(projectedGeometry, x, y);
|
|
return distance > 0 ? distance * distance : 0;
|
|
}
|
|
geometryDistance(geometry, x, y) {
|
|
const { renderMode, strokeWidth } = this;
|
|
const drawPolygons = (renderMode & 1 /* Polygons */) !== 0;
|
|
const drawLines = (renderMode & 2 /* Lines */) !== 0;
|
|
const minStrokeDistance = Math.max(strokeWidth / 2, 1) + 1;
|
|
switch (geometry.type) {
|
|
case "GeometryCollection":
|
|
return geometry.geometries.reduce(
|
|
(minDistance, g) => Math.min(minDistance, this.geometryDistance(g, x, y)),
|
|
Infinity
|
|
);
|
|
case "MultiPolygon":
|
|
return drawPolygons ? geometry.coordinates.reduce(
|
|
(minDistance, polygon) => Math.min(minDistance, Math.max(polygonDistance(polygon, x, y), 0)),
|
|
Infinity
|
|
) : Infinity;
|
|
case "Polygon":
|
|
return drawPolygons ? Math.max(polygonDistance(geometry.coordinates, x, y), 0) : Infinity;
|
|
case "MultiLineString":
|
|
return drawLines ? geometry.coordinates.reduce((minDistance, lineString) => {
|
|
return Math.min(
|
|
minDistance,
|
|
Math.max(lineStringDistance(lineString, x, y) - minStrokeDistance, 0)
|
|
);
|
|
}, Infinity) : Infinity;
|
|
case "LineString":
|
|
return drawLines ? Math.max(lineStringDistance(geometry.coordinates, x, y) - minStrokeDistance, 0) : Infinity;
|
|
case "MultiPoint":
|
|
case "Point":
|
|
default:
|
|
return Infinity;
|
|
}
|
|
}
|
|
shouldDrawPolygons() {
|
|
return (this.renderMode & 1 /* Polygons */) !== 0;
|
|
}
|
|
shouldDrawLines() {
|
|
return (this.renderMode & 2 /* Lines */) !== 0;
|
|
}
|
|
drawGeometryCollection(geometries, bbox) {
|
|
for (const g of geometries) {
|
|
bbox = this.drawGeometry(g, bbox);
|
|
}
|
|
return bbox;
|
|
}
|
|
drawMultiPolygon(coordinates, bbox) {
|
|
if (!this.shouldDrawPolygons())
|
|
return bbox;
|
|
for (const polygon of coordinates) {
|
|
bbox = this.drawPolygon(this.path, polygon, bbox);
|
|
}
|
|
return bbox;
|
|
}
|
|
drawSinglePolygon(coordinates, bbox) {
|
|
if (!this.shouldDrawPolygons())
|
|
return bbox;
|
|
return this.drawPolygon(this.path, coordinates, bbox);
|
|
}
|
|
drawMultiLineString(coordinates, bbox) {
|
|
if (!this.shouldDrawLines())
|
|
return bbox;
|
|
for (const lineString of coordinates) {
|
|
bbox = this.drawLineString(this.strokePath, lineString, bbox, false);
|
|
}
|
|
return bbox;
|
|
}
|
|
drawSingleLineString(coordinates, bbox) {
|
|
if (!this.shouldDrawLines())
|
|
return bbox;
|
|
return this.drawLineString(this.strokePath, coordinates, bbox, false);
|
|
}
|
|
drawGeometry(geometry, bbox) {
|
|
switch (geometry.type) {
|
|
case "GeometryCollection":
|
|
return this.drawGeometryCollection(geometry.geometries, bbox);
|
|
case "MultiPolygon":
|
|
return this.drawMultiPolygon(geometry.coordinates, bbox);
|
|
case "Polygon":
|
|
return this.drawSinglePolygon(geometry.coordinates, bbox);
|
|
case "MultiLineString":
|
|
return this.drawMultiLineString(geometry.coordinates, bbox);
|
|
case "LineString":
|
|
return this.drawSingleLineString(geometry.coordinates, bbox);
|
|
case "Point":
|
|
case "MultiPoint":
|
|
return bbox;
|
|
}
|
|
}
|
|
drawPolygon(path, polygons, bbox) {
|
|
if (polygons.length < 1)
|
|
return bbox;
|
|
bbox = this.drawLineString(path, polygons[0], bbox, true);
|
|
for (let i = 1; i < polygons.length; i += 1) {
|
|
const enclave = polygons[i];
|
|
this.drawLineString(path, enclave, void 0, true);
|
|
}
|
|
return bbox;
|
|
}
|
|
drawLineString(path, coordinates, bbox, isClosed) {
|
|
if (coordinates.length < 2)
|
|
return bbox;
|
|
const end = isClosed ? coordinates.length - 1 : coordinates.length;
|
|
for (let i = 0; i < end; i += 1) {
|
|
const [x, y] = coordinates[i];
|
|
if (i === 0) {
|
|
path.moveTo(x, y);
|
|
} else {
|
|
path.lineTo(x, y);
|
|
}
|
|
if (bbox == null) {
|
|
bbox = new BBox21(x, y, 0, 0);
|
|
} else {
|
|
const { x: x0, y: y0 } = bbox;
|
|
const x1 = x0 + bbox.width;
|
|
const y1 = y0 + bbox.height;
|
|
bbox.x = Math.min(x0, x);
|
|
bbox.y = Math.min(y0, y);
|
|
bbox.width = Math.max(x1, x) - bbox.x;
|
|
bbox.height = Math.max(y1, y) - bbox.y;
|
|
}
|
|
}
|
|
if (isClosed) {
|
|
path.closePath();
|
|
}
|
|
return bbox;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
SceneObjectChangeDetection({ equals: objectsEqual2 })
|
|
], GeoGeometry.prototype, "projectedGeometry", 2);
|
|
__decorateClass([
|
|
SceneChangeDetection8()
|
|
], GeoGeometry.prototype, "renderMode", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/series/map-util/geometryUtil.ts
|
|
import "ag-charts-community";
|
|
import "ag-charts-core";
|
|
function calculatePolygonArea(polygon) {
|
|
const bbox = polygonBbox(polygon[0], void 0);
|
|
if (bbox == null)
|
|
return 0;
|
|
return Math.abs(bbox.lat1 - bbox.lat0) * Math.abs(bbox.lon1 - bbox.lon0);
|
|
}
|
|
function findLargestByMetric(items, metric) {
|
|
let maxValue;
|
|
let maxItem;
|
|
for (const item of items) {
|
|
const value = metric(item);
|
|
if (value == null)
|
|
continue;
|
|
if (maxValue == null || value > maxValue) {
|
|
maxValue = value;
|
|
maxItem = item;
|
|
}
|
|
}
|
|
return maxItem;
|
|
}
|
|
function geometryBbox(geometry, into) {
|
|
if (geometry.bbox != null) {
|
|
const [lon0, lat0, lon1, lat1] = geometry.bbox;
|
|
into = LonLatBBox.extend(into, lon0, lat0, lon1, lat1);
|
|
return into;
|
|
}
|
|
switch (geometry.type) {
|
|
case "GeometryCollection":
|
|
for (const g of geometry.geometries) {
|
|
into = geometryBbox(g, into);
|
|
}
|
|
break;
|
|
case "MultiPolygon":
|
|
for (const c of geometry.coordinates) {
|
|
if (c.length > 0) {
|
|
into = polygonBbox(c[0], into);
|
|
}
|
|
}
|
|
break;
|
|
case "Polygon":
|
|
if (geometry.coordinates.length > 0) {
|
|
into = polygonBbox(geometry.coordinates[0], into);
|
|
}
|
|
break;
|
|
case "MultiLineString":
|
|
for (const c of geometry.coordinates) {
|
|
into = polygonBbox(c, into);
|
|
}
|
|
break;
|
|
case "LineString":
|
|
into = polygonBbox(geometry.coordinates, into);
|
|
break;
|
|
case "MultiPoint":
|
|
for (const p of geometry.coordinates) {
|
|
const [lon, lat] = p;
|
|
into = LonLatBBox.extend(into, lon, lat, lon, lat);
|
|
}
|
|
break;
|
|
case "Point": {
|
|
const [lon, lat] = geometry.coordinates;
|
|
into = LonLatBBox.extend(into, lon, lat, lon, lat);
|
|
break;
|
|
}
|
|
}
|
|
return into;
|
|
}
|
|
function largestPolygon(geometry) {
|
|
switch (geometry.type) {
|
|
case "Polygon":
|
|
return geometry.coordinates;
|
|
case "MultiPolygon":
|
|
return findLargestByMetric(geometry.coordinates, calculatePolygonArea);
|
|
case "GeometryCollection": {
|
|
const polygons = geometry.geometries.map(largestPolygon).filter((p) => p != null);
|
|
return findLargestByMetric(polygons, calculatePolygonArea);
|
|
}
|
|
case "MultiLineString":
|
|
case "LineString":
|
|
case "MultiPoint":
|
|
case "Point":
|
|
return;
|
|
}
|
|
}
|
|
function largestLineString(geometry) {
|
|
switch (geometry.type) {
|
|
case "LineString":
|
|
return geometry.coordinates;
|
|
case "MultiLineString":
|
|
return findLargestByMetric(geometry.coordinates, lineStringLength);
|
|
case "GeometryCollection": {
|
|
const lineStrings = geometry.geometries.map(largestLineString).filter((l) => l != null);
|
|
return findLargestByMetric(lineStrings, lineStringLength);
|
|
}
|
|
case "MultiPolygon":
|
|
case "Polygon":
|
|
case "MultiPoint":
|
|
case "Point":
|
|
return;
|
|
}
|
|
}
|
|
function containsType(geometry, type) {
|
|
if (geometry == null)
|
|
return false;
|
|
switch (geometry.type) {
|
|
case "GeometryCollection":
|
|
return geometry.geometries.some((g) => containsType(g, type));
|
|
case "MultiPolygon":
|
|
case "Polygon":
|
|
return (type & 1 /* Polygon */) !== 0;
|
|
case "MultiLineString":
|
|
case "LineString":
|
|
return (type & 2 /* LineString */) !== 0;
|
|
case "MultiPoint":
|
|
case "Point":
|
|
return (type & 4 /* Point */) !== 0;
|
|
}
|
|
}
|
|
function projectGeometry(geometry, scale) {
|
|
switch (geometry.type) {
|
|
case "GeometryCollection":
|
|
return {
|
|
type: "GeometryCollection",
|
|
geometries: geometry.geometries.map((g) => projectGeometry(g, scale))
|
|
};
|
|
case "Polygon":
|
|
return {
|
|
type: "Polygon",
|
|
coordinates: projectPolygon(geometry.coordinates, scale)
|
|
};
|
|
case "MultiPolygon":
|
|
return {
|
|
type: "MultiPolygon",
|
|
coordinates: projectMultiPolygon(geometry.coordinates, scale)
|
|
};
|
|
case "MultiLineString":
|
|
return {
|
|
type: "MultiLineString",
|
|
coordinates: projectPolygon(geometry.coordinates, scale)
|
|
};
|
|
case "LineString":
|
|
return {
|
|
type: "LineString",
|
|
coordinates: projectLineString(geometry.coordinates, scale)
|
|
};
|
|
case "MultiPoint":
|
|
return {
|
|
type: "MultiPoint",
|
|
coordinates: projectLineString(geometry.coordinates, scale)
|
|
};
|
|
case "Point":
|
|
return {
|
|
type: "Point",
|
|
coordinates: scale.convert(geometry.coordinates)
|
|
};
|
|
}
|
|
}
|
|
function projectMultiPolygon(multiPolygon, scale) {
|
|
return multiPolygon.map((polygon) => projectPolygon(polygon, scale));
|
|
}
|
|
function projectPolygon(polygon, scale) {
|
|
return polygon.map((lineString) => projectLineString(lineString, scale));
|
|
}
|
|
function projectLineString(lineString, scale) {
|
|
return lineString.map((lonLat) => scale.convert(lonLat));
|
|
}
|
|
|
|
// packages/ag-charts-enterprise/src/series/map-util/mapUtil.ts
|
|
function prepareMapMarkerAnimationFunctions() {
|
|
const fromFn = (marker, _datum, status) => {
|
|
if (status === "removed") {
|
|
return { scalingX: 1, scalingY: 1 };
|
|
} else if (marker.previousDatum == null) {
|
|
return { scalingX: 0, scalingY: 0 };
|
|
}
|
|
return { scalingX: marker.scalingX, scalingY: marker.scalingY };
|
|
};
|
|
const toFn = (_marker, _datum, status) => {
|
|
if (status === "removed") {
|
|
return { scalingX: 0, scalingY: 0 };
|
|
}
|
|
return { scalingX: 1, scalingY: 1 };
|
|
};
|
|
return { fromFn, toFn };
|
|
}
|
|
function findFocusedGeoGeometry(series, opts) {
|
|
const datum = series.contextNodeData?.nodeData[opts.datumIndex];
|
|
if (datum === void 0)
|
|
return void 0;
|
|
for (const node of series.datumSelection.nodes()) {
|
|
if (node.datum === datum) {
|
|
return node;
|
|
}
|
|
}
|
|
return void 0;
|
|
}
|
|
|
|
// packages/ag-charts-enterprise/src/series/map-util/topologySeries.ts
|
|
import { _ModuleSupport as _ModuleSupport160 } from "ag-charts-community";
|
|
var TopologySeriesProperties = class extends _ModuleSupport160.SeriesProperties {
|
|
};
|
|
var TopologySeries = class extends _ModuleSupport160.DataModelSeries {
|
|
constructor(options) {
|
|
super(options);
|
|
this.cleanup.register(
|
|
this.ctx.eventsHub.on("data:update", () => {
|
|
}),
|
|
this.ctx.eventsHub.on("legend:item-click", (event) => {
|
|
this.onLegendItemClick(event);
|
|
}),
|
|
this.ctx.eventsHub.on("legend:item-double-click", (event) => {
|
|
this.onLegendItemDoubleClick(event);
|
|
})
|
|
);
|
|
}
|
|
getSeriesDomain() {
|
|
return { domain: [Number.NaN, Number.NaN] };
|
|
}
|
|
getSeriesRange() {
|
|
return [Number.NaN, Number.NaN];
|
|
}
|
|
getHighlightedDatum() {
|
|
let highlightedDatum = this.ctx.highlightManager?.getActiveHighlight();
|
|
const { legendItemName } = this.properties;
|
|
const matchingLegendItemName = legendItemName != null && highlightedDatum?.datum == null && legendItemName === highlightedDatum?.legendItemName;
|
|
if (highlightedDatum != null && (highlightedDatum.series !== this && !matchingLegendItemName || highlightedDatum.datum == null)) {
|
|
highlightedDatum = void 0;
|
|
}
|
|
return highlightedDatum;
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/series/map-line/mapLineSeriesProperties.ts
|
|
import { _ModuleSupport as _ModuleSupport161 } from "ag-charts-community";
|
|
import { Property as Property75 } from "ag-charts-core";
|
|
var { SeriesProperties: SeriesProperties3, makeSeriesTooltip: makeSeriesTooltip12, Label: Label10 } = _ModuleSupport161;
|
|
var MapLineSeriesProperties = class extends SeriesProperties3 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.topology = void 0;
|
|
this.idKey = "";
|
|
this.topologyIdKey = "name";
|
|
this.idName = void 0;
|
|
this.labelKey = void 0;
|
|
this.labelName = void 0;
|
|
this.colorRange = void 0;
|
|
this.maxStrokeWidth = void 0;
|
|
this.stroke = "black";
|
|
this.strokeOpacity = 1;
|
|
this.strokeWidth = 0;
|
|
this.lineDash = [0];
|
|
this.lineDashOffset = 0;
|
|
this.label = new Label10();
|
|
this.tooltip = makeSeriesTooltip12();
|
|
}
|
|
getStyle() {
|
|
const { stroke: stroke3, strokeOpacity, strokeWidth, lineDash, lineDashOffset } = this;
|
|
return {
|
|
stroke: stroke3,
|
|
strokeOpacity,
|
|
strokeWidth,
|
|
lineDash,
|
|
lineDashOffset,
|
|
opacity: 1
|
|
};
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property75
|
|
], MapLineSeriesProperties.prototype, "topology", 2);
|
|
__decorateClass([
|
|
Property75
|
|
], MapLineSeriesProperties.prototype, "title", 2);
|
|
__decorateClass([
|
|
Property75
|
|
], MapLineSeriesProperties.prototype, "legendItemName", 2);
|
|
__decorateClass([
|
|
Property75
|
|
], MapLineSeriesProperties.prototype, "idKey", 2);
|
|
__decorateClass([
|
|
Property75
|
|
], MapLineSeriesProperties.prototype, "topologyIdKey", 2);
|
|
__decorateClass([
|
|
Property75
|
|
], MapLineSeriesProperties.prototype, "idName", 2);
|
|
__decorateClass([
|
|
Property75
|
|
], MapLineSeriesProperties.prototype, "labelKey", 2);
|
|
__decorateClass([
|
|
Property75
|
|
], MapLineSeriesProperties.prototype, "labelName", 2);
|
|
__decorateClass([
|
|
Property75
|
|
], MapLineSeriesProperties.prototype, "sizeKey", 2);
|
|
__decorateClass([
|
|
Property75
|
|
], MapLineSeriesProperties.prototype, "sizeName", 2);
|
|
__decorateClass([
|
|
Property75
|
|
], MapLineSeriesProperties.prototype, "colorKey", 2);
|
|
__decorateClass([
|
|
Property75
|
|
], MapLineSeriesProperties.prototype, "colorName", 2);
|
|
__decorateClass([
|
|
Property75
|
|
], MapLineSeriesProperties.prototype, "sizeDomain", 2);
|
|
__decorateClass([
|
|
Property75
|
|
], MapLineSeriesProperties.prototype, "colorRange", 2);
|
|
__decorateClass([
|
|
Property75
|
|
], MapLineSeriesProperties.prototype, "maxStrokeWidth", 2);
|
|
__decorateClass([
|
|
Property75
|
|
], MapLineSeriesProperties.prototype, "stroke", 2);
|
|
__decorateClass([
|
|
Property75
|
|
], MapLineSeriesProperties.prototype, "strokeOpacity", 2);
|
|
__decorateClass([
|
|
Property75
|
|
], MapLineSeriesProperties.prototype, "strokeWidth", 2);
|
|
__decorateClass([
|
|
Property75
|
|
], MapLineSeriesProperties.prototype, "lineDash", 2);
|
|
__decorateClass([
|
|
Property75
|
|
], MapLineSeriesProperties.prototype, "lineDashOffset", 2);
|
|
__decorateClass([
|
|
Property75
|
|
], MapLineSeriesProperties.prototype, "itemStyler", 2);
|
|
__decorateClass([
|
|
Property75
|
|
], MapLineSeriesProperties.prototype, "label", 2);
|
|
__decorateClass([
|
|
Property75
|
|
], MapLineSeriesProperties.prototype, "tooltip", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/series/map-line/mapLineSeries.ts
|
|
var {
|
|
getMissCount: getMissCount2,
|
|
getLabelStyles: getLabelStyles2,
|
|
createDatumId: createDatumId11,
|
|
SeriesNodePickMode: SeriesNodePickMode9,
|
|
valueProperty: valueProperty11,
|
|
ColorScale: ColorScale2,
|
|
LinearScale: LinearScale5,
|
|
Selection: Selection8,
|
|
Text: Text4,
|
|
Transformable: Transformable3
|
|
} = _ModuleSupport162;
|
|
var MapLineSeries = class extends TopologySeries {
|
|
constructor(moduleCtx) {
|
|
super({
|
|
moduleCtx,
|
|
categoryKey: void 0,
|
|
propertyKeys: {
|
|
size: ["colorKey"],
|
|
color: ["colorKey"],
|
|
label: ["labelKey"]
|
|
},
|
|
propertyNames: {
|
|
size: ["sizeName"],
|
|
color: ["colorName"],
|
|
label: ["labelName"]
|
|
},
|
|
pickModes: [SeriesNodePickMode9.EXACT_SHAPE_MATCH, SeriesNodePickMode9.NEAREST_NODE],
|
|
usesPlacedLabels: true
|
|
});
|
|
this.properties = new MapLineSeriesProperties();
|
|
this._chartTopology = void 0;
|
|
this.colorScale = new ColorScale2();
|
|
this.sizeScale = new LinearScale5();
|
|
this.datumSelection = Selection8.select(
|
|
this.contentGroup,
|
|
() => this.nodeFactory()
|
|
);
|
|
this.labelSelection = Selection8.select(this.labelGroup, Text4);
|
|
this.highlightDatumSelection = Selection8.select(
|
|
this.highlightNodeGroup,
|
|
() => this.nodeFactory()
|
|
);
|
|
this.highlightLabelSelection = Selection8.select(this.highlightLabelGroup, Text4);
|
|
this.placedLabelData = [];
|
|
this._previousDatumMidPoint = void 0;
|
|
}
|
|
getNodeData() {
|
|
return this.contextNodeData?.nodeData;
|
|
}
|
|
get topology() {
|
|
return this.properties.topology ?? this._chartTopology;
|
|
}
|
|
get hasData() {
|
|
return super.hasData && this.topology != null;
|
|
}
|
|
renderToOffscreenCanvas() {
|
|
return true;
|
|
}
|
|
setZIndex(zIndex) {
|
|
super.setZIndex(zIndex);
|
|
this.contentGroup.zIndex = [1 /* ShapeLine */, zIndex];
|
|
this.highlightGroup.zIndex = [4 /* ShapeLineHighlight */, zIndex];
|
|
return true;
|
|
}
|
|
setChartTopology(topology) {
|
|
this._chartTopology = topology;
|
|
if (this.topology === topology) {
|
|
this.nodeDataRefresh = true;
|
|
}
|
|
}
|
|
isLabelEnabled() {
|
|
return this.properties.labelKey != null && this.properties.label.enabled;
|
|
}
|
|
nodeFactory() {
|
|
const geoGeometry = new GeoGeometry();
|
|
geoGeometry.renderMode = 2 /* Lines */;
|
|
geoGeometry.lineJoin = "round";
|
|
geoGeometry.lineCap = "round";
|
|
return geoGeometry;
|
|
}
|
|
async processData(dataController) {
|
|
if (this.data == null)
|
|
return;
|
|
const { data, topology, sizeScale, colorScale } = this;
|
|
const { topologyIdKey, idKey, sizeKey, colorKey, labelKey, sizeDomain, colorRange } = this.properties;
|
|
const featureById = /* @__PURE__ */ new Map();
|
|
for (const feature of topology?.features.values() ?? []) {
|
|
const property = feature.properties?.[topologyIdKey];
|
|
if (property == null || !containsType(feature.geometry, 2 /* LineString */))
|
|
continue;
|
|
featureById.set(property, feature);
|
|
}
|
|
const sizeScaleType = this.sizeScale.type;
|
|
const colorScaleType = this.colorScale.type;
|
|
const mercatorScaleType = this.scale?.type;
|
|
const { dataModel, processedData } = await this.requestDataModel(dataController, data, {
|
|
props: [
|
|
valueProperty11(idKey, mercatorScaleType, { id: "idValue", includeProperty: false }),
|
|
valueProperty11(idKey, mercatorScaleType, {
|
|
id: "featureValue",
|
|
includeProperty: false,
|
|
processor: () => (datum) => featureById.get(datum)
|
|
}),
|
|
...labelKey == null ? [] : [valueProperty11(labelKey, "category", { id: "labelValue" })],
|
|
...sizeKey == null ? [] : [valueProperty11(sizeKey, sizeScaleType, { id: "sizeValue" })],
|
|
...colorKey == null ? [] : [valueProperty11(colorKey, colorScaleType, { id: "colorValue" })]
|
|
]
|
|
});
|
|
const featureValues = dataModel.resolveColumnById(this, `featureValue`, processedData);
|
|
this.topologyBounds = featureValues.reduce((current, feature) => {
|
|
const geometry = feature?.geometry;
|
|
if (geometry == null)
|
|
return current;
|
|
return geometryBbox(geometry, current);
|
|
}, void 0);
|
|
if (sizeKey != null) {
|
|
const sizeIdx = dataModel.resolveProcessedDataIndexById(this, `sizeValue`);
|
|
const processedSize = processedData.domain.values[sizeIdx] ?? [];
|
|
sizeScale.domain = sizeDomain ?? processedSize;
|
|
}
|
|
if (colorRange != null && this.isColorScaleValid()) {
|
|
const colorKeyIdx = dataModel.resolveProcessedDataIndexById(this, "colorValue");
|
|
colorScale.domain = processedData.domain.values[colorKeyIdx];
|
|
colorScale.range = colorRange;
|
|
colorScale.update();
|
|
}
|
|
if (topology == null) {
|
|
Logger17.warnOnce(`no topology was provided for [MapLineSeries]; nothing will be rendered.`);
|
|
}
|
|
}
|
|
isColorScaleValid() {
|
|
const { colorKey } = this.properties;
|
|
if (!colorKey) {
|
|
return false;
|
|
}
|
|
const { dataModel, processedData } = this;
|
|
if (!dataModel || !processedData) {
|
|
return false;
|
|
}
|
|
const colorIdx = dataModel.resolveProcessedDataIndexById(this, "colorValue");
|
|
const dataCount = processedData.input.count;
|
|
const missCount = getMissCount2(this, processedData.defs.values[colorIdx].missing);
|
|
const colorDataMissing = dataCount === 0 || dataCount === missCount;
|
|
return !colorDataMissing;
|
|
}
|
|
getLabelDatum(datum, datumIndex, idValue, labelValue, projectedGeometry, measurer3) {
|
|
if (labelValue == null || projectedGeometry == null || idValue == null)
|
|
return;
|
|
const lineString = largestLineString(projectedGeometry);
|
|
if (lineString == null)
|
|
return;
|
|
const { idKey, idName, sizeKey, sizeName, colorKey, colorName, labelKey, labelName, label } = this.properties;
|
|
if (labelKey == null || !label.enabled)
|
|
return;
|
|
const labelText = this.getLabelText(
|
|
labelValue,
|
|
datum,
|
|
labelKey,
|
|
"label",
|
|
[],
|
|
label,
|
|
{
|
|
value: labelValue,
|
|
datum,
|
|
idKey,
|
|
idName,
|
|
sizeKey,
|
|
sizeName,
|
|
colorKey,
|
|
colorName,
|
|
labelKey,
|
|
labelName
|
|
}
|
|
);
|
|
if (labelText == null)
|
|
return;
|
|
const labelSize = measurer3.measureLines(String(labelText));
|
|
const labelCenter = lineStringCenter(lineString);
|
|
if (labelCenter == null)
|
|
return;
|
|
const [x, y] = labelCenter.point;
|
|
const { width, height } = labelSize;
|
|
return {
|
|
point: { x, y, size: 0 },
|
|
label: { width, height, text: labelText },
|
|
anchor: void 0,
|
|
placement: void 0,
|
|
datumIndex,
|
|
idValue
|
|
};
|
|
}
|
|
resolveColumn(key, columnId, processedData) {
|
|
if (key == null || this.dataModel == null)
|
|
return void 0;
|
|
return this.dataModel.resolveColumnById(this, columnId, processedData);
|
|
}
|
|
resolveLineDataColumns(processedData) {
|
|
const { sizeKey, colorKey, labelKey } = this.properties;
|
|
return {
|
|
idValues: this.dataModel.resolveColumnById(this, "idValue", processedData),
|
|
featureValues: this.dataModel.resolveColumnById(this, "featureValue", processedData),
|
|
labelValues: this.resolveColumn(labelKey, "labelValue", processedData),
|
|
sizeValues: this.resolveColumn(sizeKey, "sizeValue", processedData),
|
|
colorValues: this.resolveColumn(colorKey, "colorValue", processedData)
|
|
};
|
|
}
|
|
prepareProjectedLineGeometries(idValues, featureValues, processedData) {
|
|
const projectedGeometries = /* @__PURE__ */ new Map();
|
|
for (const [datumIndex] of processedData.dataSources.get(this.id)?.data.entries() ?? []) {
|
|
const id = idValues[datumIndex];
|
|
const geometry = featureValues[datumIndex]?.geometry;
|
|
const projectedGeometry = geometry != null && this.scale != null ? projectGeometry(geometry, this.scale) : void 0;
|
|
if (id != null && projectedGeometry != null) {
|
|
projectedGeometries.set(id, projectedGeometry);
|
|
}
|
|
}
|
|
return projectedGeometries;
|
|
}
|
|
warnMissingGeometries(missingGeometries) {
|
|
if (missingGeometries.length === 0)
|
|
return;
|
|
const missingGeometriesCap = 10;
|
|
if (missingGeometries.length > missingGeometriesCap) {
|
|
const excessItems = missingGeometries.length - missingGeometriesCap;
|
|
missingGeometries.length = missingGeometriesCap;
|
|
missingGeometries.push(`(+${excessItems} more)`);
|
|
}
|
|
Logger17.warnOnce(`some data items do not have matches in the provided topology`, missingGeometries);
|
|
}
|
|
createNodeData() {
|
|
const { id: seriesId, dataModel, processedData, sizeScale, properties } = this;
|
|
const { label, legendItemName, colorKey } = properties;
|
|
if (dataModel == null || processedData == null)
|
|
return;
|
|
if (!this.visible) {
|
|
return { itemId: seriesId, nodeData: [], labelData: [] };
|
|
}
|
|
const columns = this.resolveLineDataColumns(processedData);
|
|
const maxStrokeWidth = properties.maxStrokeWidth ?? properties.strokeWidth;
|
|
sizeScale.range = [Math.min(properties.strokeWidth, maxStrokeWidth), maxStrokeWidth];
|
|
const measurer3 = cachedTextMeasurer8(label);
|
|
const projectedGeometries = this.prepareProjectedLineGeometries(
|
|
columns.idValues,
|
|
columns.featureValues,
|
|
processedData
|
|
);
|
|
const nodeData = [];
|
|
const labelData = [];
|
|
const missingGeometries = [];
|
|
const rawData = processedData.dataSources.get(this.id)?.data ?? [];
|
|
for (const [datumIndex, datum] of rawData.entries()) {
|
|
const dataValues = {
|
|
idValue: columns.idValues[datumIndex],
|
|
colorValue: columns.colorValues?.[datumIndex],
|
|
sizeValue: columns.sizeValues?.[datumIndex],
|
|
labelValue: columns.labelValues?.[datumIndex]
|
|
};
|
|
const projectedGeometry = projectedGeometries.get(dataValues.idValue);
|
|
if (projectedGeometry == null) {
|
|
missingGeometries.push(dataValues.idValue);
|
|
}
|
|
if (colorKey != null && dataValues.colorValue == null) {
|
|
continue;
|
|
}
|
|
const labelDatum = this.getLabelDatum(
|
|
datum,
|
|
datumIndex,
|
|
dataValues.idValue,
|
|
dataValues.labelValue,
|
|
projectedGeometry,
|
|
measurer3
|
|
);
|
|
if (labelDatum != null) {
|
|
labelData.push(labelDatum);
|
|
}
|
|
nodeData.push({
|
|
series: this,
|
|
datum,
|
|
datumIndex,
|
|
...dataValues,
|
|
projectedGeometry,
|
|
legendItemName,
|
|
style: this.getItemStyle(
|
|
{ datumIndex, datum, colorValue: dataValues.colorValue, sizeValue: dataValues.sizeValue },
|
|
false
|
|
)
|
|
});
|
|
}
|
|
this.warnMissingGeometries(missingGeometries);
|
|
return {
|
|
itemId: seriesId,
|
|
nodeData,
|
|
labelData
|
|
};
|
|
}
|
|
updateSelections() {
|
|
if (this.nodeDataRefresh) {
|
|
this.contextNodeData = this.createNodeData();
|
|
this.nodeDataRefresh = false;
|
|
}
|
|
}
|
|
update() {
|
|
const { datumSelection, highlightDatumSelection } = this;
|
|
this.updateSelections();
|
|
this.contentGroup.visible = this.visible;
|
|
this.labelGroup.visible = this.visible;
|
|
const drawingMode = this.ctx.chartService.highlight?.drawingMode ?? "overlay";
|
|
const highlightedDatum = this.getHighlightedDatum();
|
|
const nodeData = this.contextNodeData?.nodeData ?? [];
|
|
this.datumSelection = this.updateDatumSelection({ nodeData, datumSelection });
|
|
this.updateDatumStyles({ datumSelection, isHighlight: false });
|
|
this.updateDatumNodes({ datumSelection, isHighlight: false, drawingMode: "overlay" });
|
|
this.highlightDatumSelection = this.updateDatumSelection({
|
|
nodeData: highlightedDatum == null ? [] : [highlightedDatum],
|
|
datumSelection: highlightDatumSelection
|
|
});
|
|
this.updateDatumStyles({ datumSelection: highlightDatumSelection, isHighlight: true });
|
|
this.updateDatumNodes({ datumSelection: highlightDatumSelection, isHighlight: true, drawingMode });
|
|
this.updateLabelNodes({ labelSelection: this.labelSelection, isHighlight: false });
|
|
this.updateHighlightLabelSelection(highlightedDatum);
|
|
}
|
|
updateDatumSelection(opts) {
|
|
return opts.datumSelection.update(opts.nodeData, void 0, (datum) => createDatumId11(datum.idValue));
|
|
}
|
|
getItemStyle({ datumIndex = 0, datum, colorValue, sizeValue }, isHighlight) {
|
|
const { properties, colorScale, sizeScale } = this;
|
|
const { colorRange, itemStyler } = properties;
|
|
const baseStyle = properties.getStyle();
|
|
if (colorValue != null) {
|
|
baseStyle.stroke = this.isColorScaleValid() ? colorScale.convert(colorValue) : colorRange?.[0] ?? properties.stroke;
|
|
}
|
|
const highlightStyle = this.getHighlightStyle(isHighlight, datumIndex);
|
|
const style = mergeDefaults14(highlightStyle, baseStyle);
|
|
if (sizeValue != null) {
|
|
style.strokeWidth = sizeScale.convert(sizeValue, { clamp: true });
|
|
}
|
|
let overrides;
|
|
if (itemStyler != null) {
|
|
overrides = this.cachedDatumCallback(createDatumId11(datumIndex, isHighlight ? "highlight" : "node"), () => {
|
|
const params = this.makeItemStylerParams(datum, datumIndex, isHighlight, style);
|
|
return this.callWithContext(itemStyler, params);
|
|
});
|
|
}
|
|
return overrides ? mergeDefaults14(style, overrides) : style;
|
|
}
|
|
makeItemStylerParams(datum, datumIndex, isHighlight, style) {
|
|
const { id: seriesId } = this;
|
|
const activeHighlight = this.ctx.highlightManager?.getActiveHighlight();
|
|
const highlightState = this.getHighlightStateString(activeHighlight, isHighlight, datumIndex);
|
|
return {
|
|
seriesId,
|
|
datum,
|
|
highlightState,
|
|
...style
|
|
};
|
|
}
|
|
updateDatumStyles({
|
|
datumSelection,
|
|
isHighlight
|
|
}) {
|
|
datumSelection.each((_, nodeDatum) => {
|
|
nodeDatum.style = this.getItemStyle(nodeDatum, isHighlight);
|
|
});
|
|
}
|
|
updateDatumNodes({
|
|
datumSelection,
|
|
drawingMode
|
|
}) {
|
|
datumSelection.each((geoGeometry, nodeDatum) => {
|
|
const { projectedGeometry, style } = nodeDatum;
|
|
if (projectedGeometry == null) {
|
|
geoGeometry.visible = false;
|
|
geoGeometry.projectedGeometry = void 0;
|
|
return;
|
|
}
|
|
geoGeometry.visible = true;
|
|
geoGeometry.projectedGeometry = projectedGeometry;
|
|
geoGeometry.setProperties(style);
|
|
geoGeometry.drawingMode = drawingMode;
|
|
});
|
|
}
|
|
updatePlacedLabelData(labelData) {
|
|
this.placedLabelData = labelData;
|
|
this.labelSelection = this.labelSelection.update(labelData, (text2) => {
|
|
text2.pointerEvents = _ModuleSupport162.PointerEvents.None;
|
|
});
|
|
this.updateLabelNodes({ labelSelection: this.labelSelection, isHighlight: false });
|
|
this.updateHighlightLabelSelection();
|
|
}
|
|
updateLabelNodes({
|
|
isHighlight,
|
|
labelSelection
|
|
}) {
|
|
const { properties } = this;
|
|
const activeHighlight = this.getHighlightedDatum();
|
|
labelSelection.each((label, placedLabel) => {
|
|
const { x, y, width, height, text: text2, datum: labelDatum } = placedLabel;
|
|
const style = getLabelStyles2(this, void 0, properties, properties.label, isHighlight, activeHighlight);
|
|
const { color: fill, fontStyle, fontWeight, fontSize, fontFamily } = style;
|
|
label.visible = true;
|
|
label.x = x + width / 2;
|
|
label.y = y + height / 2;
|
|
label.text = text2;
|
|
label.fill = fill;
|
|
label.fontStyle = fontStyle;
|
|
label.fontWeight = fontWeight;
|
|
label.fontSize = fontSize;
|
|
label.fontFamily = fontFamily;
|
|
label.textAlign = "center";
|
|
label.textBaseline = "middle";
|
|
const datumIndex = labelDatum?.datumIndex;
|
|
label.fillOpacity = this.getHighlightStyle(isHighlight, datumIndex).opacity ?? 1;
|
|
label.setBoxing(style);
|
|
});
|
|
}
|
|
updateHighlightLabelSelection(highlightedDatum = this.getHighlightedDatum()) {
|
|
const highlightId = highlightedDatum?.idValue;
|
|
const highlightLabels = highlightId == null || !this.isLabelEnabled() ? [] : this.placedLabelData.filter((label) => label.datum.idValue === highlightId);
|
|
this.highlightLabelSelection = this.highlightLabelSelection.update(highlightLabels);
|
|
if (highlightLabels.length === 0) {
|
|
this.highlightLabelSelection.cleanup();
|
|
}
|
|
this.updateLabelNodes({ labelSelection: this.highlightLabelSelection, isHighlight: true });
|
|
}
|
|
resetAnimation() {
|
|
}
|
|
getLabelData() {
|
|
if (!this.isLabelEnabled())
|
|
return [];
|
|
return this.contextNodeData?.labelData ?? [];
|
|
}
|
|
pickNodeClosestDatum({ x, y }) {
|
|
let minDistanceSquared = Infinity;
|
|
let minDatum;
|
|
this.datumSelection.each((node, datum) => {
|
|
const distanceSquared = node.distanceSquared(x, y);
|
|
if (distanceSquared < minDistanceSquared) {
|
|
minDistanceSquared = distanceSquared;
|
|
minDatum = datum;
|
|
}
|
|
});
|
|
return minDatum == null ? void 0 : { datum: minDatum, distance: Math.sqrt(minDistanceSquared) };
|
|
}
|
|
datumMidPoint(datum) {
|
|
const { _previousDatumMidPoint } = this;
|
|
if (_previousDatumMidPoint?.datum === datum) {
|
|
return _previousDatumMidPoint.point;
|
|
}
|
|
const projectedGeometry = datum.projectedGeometry;
|
|
const lineString = projectedGeometry == null ? void 0 : largestLineString(projectedGeometry);
|
|
const center = lineString == null ? void 0 : lineStringCenter(lineString)?.point;
|
|
const point = center == null ? void 0 : { x: center[0], y: center[1] };
|
|
this._previousDatumMidPoint = { datum, point };
|
|
return point;
|
|
}
|
|
legendItemSymbol(datumIndex) {
|
|
const { dataModel, processedData, properties } = this;
|
|
const { strokeWidth, strokeOpacity, lineDash } = properties;
|
|
let { stroke: stroke3 } = properties;
|
|
if (datumIndex != null && this.isColorScaleValid()) {
|
|
const colorValues = dataModel.resolveColumnById(this, "colorValue", processedData);
|
|
const colorValue = colorValues[datumIndex];
|
|
if (colorValue != null) {
|
|
stroke3 = this.colorScale.convert(colorValue);
|
|
}
|
|
}
|
|
return {
|
|
marker: {
|
|
fill: void 0,
|
|
fillOpacity: 0,
|
|
stroke: void 0,
|
|
strokeWidth: 0,
|
|
strokeOpacity: 0,
|
|
lineDash: [0],
|
|
lineDashOffset: 0,
|
|
enabled: false
|
|
},
|
|
line: {
|
|
enabled: true,
|
|
stroke: stroke3,
|
|
strokeWidth,
|
|
strokeOpacity,
|
|
lineDash
|
|
}
|
|
};
|
|
}
|
|
getLegendData(legendType) {
|
|
const { processedData, dataModel } = this;
|
|
if (processedData == null || dataModel == null)
|
|
return [];
|
|
const { id: seriesId, visible } = this;
|
|
const { title, legendItemName, idKey, idName, colorKey, colorRange, showInLegend } = this.properties;
|
|
if (legendType === "gradient" && colorKey != null && colorRange != null) {
|
|
const colorDomain = processedData.domain.values[dataModel.resolveProcessedDataIndexById(this, "colorValue")];
|
|
const legendDatum = {
|
|
legendType: "gradient",
|
|
enabled: visible,
|
|
seriesId,
|
|
series: this.getFormatterContext("color"),
|
|
colorRange,
|
|
colorDomain
|
|
};
|
|
return [legendDatum];
|
|
} else if (legendType === "category") {
|
|
const legendDatum = {
|
|
legendType: "category",
|
|
id: seriesId,
|
|
itemId: seriesId,
|
|
seriesId,
|
|
enabled: visible,
|
|
label: { text: legendItemName ?? title ?? idName ?? idKey },
|
|
symbol: this.legendItemSymbol(),
|
|
legendItemName,
|
|
hideInLegend: !showInLegend
|
|
};
|
|
return [legendDatum];
|
|
} else {
|
|
return [];
|
|
}
|
|
}
|
|
getTooltipContent(datumIndex) {
|
|
const {
|
|
id: seriesId,
|
|
dataModel,
|
|
processedData,
|
|
properties,
|
|
ctx: { formatManager }
|
|
} = this;
|
|
const {
|
|
idKey,
|
|
idName,
|
|
colorKey,
|
|
colorName,
|
|
sizeKey,
|
|
sizeName,
|
|
labelKey,
|
|
labelName,
|
|
title,
|
|
legendItemName,
|
|
tooltip
|
|
} = properties;
|
|
if (!dataModel || !processedData)
|
|
return;
|
|
const datum = processedData.dataSources.get(this.id)?.data[datumIndex];
|
|
const idValues = dataModel.resolveColumnById(this, `idValue`, processedData);
|
|
const sizeValue = sizeKey == null ? void 0 : dataModel.resolveColumnById(this, `sizeValue`, processedData)[datumIndex];
|
|
const colorValue = colorKey == null ? void 0 : dataModel.resolveColumnById(this, `colorValue`, processedData)[datumIndex];
|
|
if (colorKey != null && colorValue == null) {
|
|
return;
|
|
}
|
|
const data = [];
|
|
if (this.isLabelEnabled() && labelKey != null && labelKey !== idKey) {
|
|
const labelValue = dataModel.resolveColumnById(this, `labelValue`, processedData)[datumIndex];
|
|
const content = formatManager.format(this.callWithContext.bind(this), {
|
|
type: "category",
|
|
value: labelValue,
|
|
datum,
|
|
seriesId,
|
|
legendItemName,
|
|
key: labelKey,
|
|
source: "tooltip",
|
|
property: "label",
|
|
domain: [],
|
|
boundSeries: this.getFormatterContext("label")
|
|
});
|
|
data.push({ label: labelName, fallbackLabel: labelKey, value: content ?? labelValue });
|
|
}
|
|
if (sizeValue != null && sizeKey != null) {
|
|
const domain = dataModel.getDomain(this, `sizeValue`, "value", processedData).domain;
|
|
const content = formatManager.format(this.callWithContext.bind(this), {
|
|
type: "number",
|
|
value: sizeValue,
|
|
datum,
|
|
seriesId,
|
|
legendItemName,
|
|
key: sizeKey,
|
|
source: "tooltip",
|
|
property: "size",
|
|
domain,
|
|
boundSeries: this.getFormatterContext("size"),
|
|
fractionDigits: void 0,
|
|
visibleDomain: void 0
|
|
});
|
|
data.push({ label: sizeName, fallbackLabel: sizeKey, value: content ?? String(sizeValue) });
|
|
}
|
|
if (colorValue != null && colorKey != null) {
|
|
const domain = dataModel.getDomain(this, `colorValue`, "value", processedData).domain;
|
|
const content = formatManager.format(this.callWithContext.bind(this), {
|
|
type: "number",
|
|
value: colorValue,
|
|
datum,
|
|
seriesId,
|
|
legendItemName,
|
|
key: colorKey,
|
|
source: "tooltip",
|
|
property: "color",
|
|
domain,
|
|
boundSeries: this.getFormatterContext("color"),
|
|
fractionDigits: void 0,
|
|
visibleDomain: void 0
|
|
});
|
|
data.push({ label: colorName, fallbackLabel: colorKey, value: content ?? String(colorValue) });
|
|
}
|
|
const format = this.getItemStyle({ datumIndex, datum, colorValue, sizeValue }, false);
|
|
return this.formatTooltipWithContext(
|
|
tooltip,
|
|
{
|
|
heading: idValues[datumIndex],
|
|
title: title ?? legendItemName,
|
|
symbol: this.legendItemSymbol(datumIndex),
|
|
data
|
|
},
|
|
{
|
|
seriesId,
|
|
datum,
|
|
title,
|
|
idKey,
|
|
idName,
|
|
colorKey,
|
|
colorName,
|
|
sizeKey,
|
|
sizeName,
|
|
labelKey,
|
|
labelName,
|
|
...format
|
|
}
|
|
);
|
|
}
|
|
computeFocusBounds(opts) {
|
|
const geometry = findFocusedGeoGeometry(this, opts);
|
|
return geometry ? Transformable3.toCanvas(this.contentGroup, geometry.getBBox()) : void 0;
|
|
}
|
|
hasItemStylers() {
|
|
return this.properties.itemStyler != null || this.properties.label.itemStyler != null;
|
|
}
|
|
};
|
|
MapLineSeries.className = "MapLineSeries";
|
|
MapLineSeries.type = "map-line";
|
|
|
|
// packages/ag-charts-enterprise/src/series/map-line/mapLineSeriesOptionsDef.ts
|
|
import { _ModuleSupport as _ModuleSupport163 } from "ag-charts-community";
|
|
import {
|
|
and as and3,
|
|
arrayLength as arrayLength2,
|
|
arrayOf as arrayOf3,
|
|
color as color4,
|
|
commonSeriesOptionsDefs as commonSeriesOptionsDefs11,
|
|
constant as constant11,
|
|
geoJson,
|
|
required as required11,
|
|
string as string13,
|
|
undocumented as undocumented11,
|
|
without as without6
|
|
} from "ag-charts-core";
|
|
var { mapLineSeriesThemeableOptionsDef } = _ModuleSupport163;
|
|
var mapLineSeriesOptionsDef = {
|
|
...without6(commonSeriesOptionsDefs11, ["highlightStyle", "highlight"]),
|
|
...mapLineSeriesThemeableOptionsDef,
|
|
type: required11(constant11("map-line")),
|
|
idKey: required11(string13),
|
|
sizeKey: string13,
|
|
colorKey: string13,
|
|
labelKey: string13,
|
|
idName: string13,
|
|
sizeName: string13,
|
|
colorName: string13,
|
|
labelName: string13,
|
|
topology: geoJson,
|
|
topologyIdKey: string13,
|
|
legendItemName: string13,
|
|
title: string13
|
|
};
|
|
mapLineSeriesOptionsDef.colorRange = undocumented11(and3(arrayOf3(color4), arrayLength2(1)));
|
|
|
|
// packages/ag-charts-enterprise/src/series/map-line/mapLineModule.ts
|
|
var MapLineSeriesModule = {
|
|
type: "series",
|
|
name: "map-line",
|
|
chartType: "topology",
|
|
enterprise: true,
|
|
version: VERSION36,
|
|
dependencies: [TopologyChartModule],
|
|
options: mapLineSeriesOptionsDef,
|
|
themeTemplate: {
|
|
...MAP_THEME_DEFAULTS,
|
|
series: {
|
|
stroke: applyMapPalette(SAFE_STROKE_FILL_OPERATION2),
|
|
colorRange: {
|
|
$if: [
|
|
{ $eq: [{ $mapPalette: "type" }, "inbuilt"] },
|
|
{ $mapPalette: "divergingColors" },
|
|
applyMapPalette(SAFE_RANGE2_OPERATION4)
|
|
]
|
|
},
|
|
strokeWidth: 1,
|
|
maxStrokeWidth: 3,
|
|
lineDash: [0],
|
|
lineDashOffset: 0,
|
|
label: {
|
|
...LABEL_BOXING_DEFAULTS9,
|
|
enabled: true,
|
|
fontSize: { $ref: "fontSize" },
|
|
fontFamily: { $ref: "fontFamily" },
|
|
fontWeight: { $ref: "fontWeight" },
|
|
color: { $ref: "textColor" }
|
|
},
|
|
highlight: applyMapPalette(MULTI_SERIES_HIGHLIGHT_STYLE4)
|
|
},
|
|
tooltip: {
|
|
range: "exact"
|
|
}
|
|
},
|
|
create: (ctx) => new MapLineSeries(ctx)
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/series/map-line-background/mapLineBackgroundModule.ts
|
|
import { VERSION as VERSION37 } from "ag-charts-community";
|
|
|
|
// packages/ag-charts-enterprise/src/series/map-line-background/mapLineBackgroundSeries.ts
|
|
import { _ModuleSupport as _ModuleSupport165 } from "ag-charts-community";
|
|
import { Logger as Logger18 } from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/series/map-line-background/mapLineBackgroundSeriesProperties.ts
|
|
import { _ModuleSupport as _ModuleSupport164 } from "ag-charts-community";
|
|
import { Property as Property76 } from "ag-charts-core";
|
|
var { SeriesProperties: SeriesProperties4, makeSeriesTooltip: makeSeriesTooltip13 } = _ModuleSupport164;
|
|
var MapLineBackgroundSeriesProperties = class extends SeriesProperties4 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.topology = void 0;
|
|
this.stroke = "black";
|
|
this.strokeOpacity = 1;
|
|
this.strokeWidth = 0;
|
|
this.lineDash = [0];
|
|
this.lineDashOffset = 0;
|
|
this.tooltip = makeSeriesTooltip13();
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property76
|
|
], MapLineBackgroundSeriesProperties.prototype, "topology", 2);
|
|
__decorateClass([
|
|
Property76
|
|
], MapLineBackgroundSeriesProperties.prototype, "stroke", 2);
|
|
__decorateClass([
|
|
Property76
|
|
], MapLineBackgroundSeriesProperties.prototype, "strokeOpacity", 2);
|
|
__decorateClass([
|
|
Property76
|
|
], MapLineBackgroundSeriesProperties.prototype, "strokeWidth", 2);
|
|
__decorateClass([
|
|
Property76
|
|
], MapLineBackgroundSeriesProperties.prototype, "lineDash", 2);
|
|
__decorateClass([
|
|
Property76
|
|
], MapLineBackgroundSeriesProperties.prototype, "lineDashOffset", 2);
|
|
__decorateClass([
|
|
Property76
|
|
], MapLineBackgroundSeriesProperties.prototype, "tooltip", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/series/map-line-background/mapLineBackgroundSeries.ts
|
|
var { createDatumId: createDatumId12, Group: Group13, Selection: Selection9, PointerEvents: PointerEvents6 } = _ModuleSupport165;
|
|
var MapLineBackgroundSeries = class extends TopologySeries {
|
|
constructor(moduleCtx) {
|
|
super({
|
|
moduleCtx,
|
|
categoryKey: void 0,
|
|
pickModes: []
|
|
});
|
|
this.properties = new MapLineBackgroundSeriesProperties();
|
|
this._chartTopology = void 0;
|
|
this.itemGroup = this.contentGroup.appendChild(new Group13({ name: "itemGroup" }));
|
|
this.datumSelection = Selection9.select(
|
|
this.itemGroup,
|
|
() => this.nodeFactory()
|
|
);
|
|
this.itemGroup.pointerEvents = PointerEvents6.None;
|
|
}
|
|
getNodeData() {
|
|
return this.contextNodeData?.nodeData;
|
|
}
|
|
get topology() {
|
|
return this.properties.topology ?? this._chartTopology;
|
|
}
|
|
get focusable() {
|
|
return false;
|
|
}
|
|
setOptionsData() {
|
|
}
|
|
setChartData() {
|
|
}
|
|
get hasData() {
|
|
return false;
|
|
}
|
|
renderToOffscreenCanvas() {
|
|
return true;
|
|
}
|
|
setChartTopology(topology) {
|
|
this._chartTopology = topology;
|
|
if (this.topology === topology) {
|
|
this.nodeDataRefresh = true;
|
|
}
|
|
}
|
|
setZIndex(zIndex) {
|
|
super.setZIndex(zIndex);
|
|
this.contentGroup.zIndex = [0 /* ShapeLineBackground */, zIndex, 0];
|
|
this.highlightGroup.zIndex = [0 /* ShapeLineBackground */, zIndex, 1];
|
|
return true;
|
|
}
|
|
nodeFactory() {
|
|
const geoGeometry = new GeoGeometry();
|
|
geoGeometry.renderMode = 2 /* Lines */;
|
|
geoGeometry.lineJoin = "round";
|
|
geoGeometry.lineCap = "round";
|
|
geoGeometry.pointerEvents = PointerEvents6.None;
|
|
return geoGeometry;
|
|
}
|
|
processData() {
|
|
const { topology } = this;
|
|
this.topologyBounds = topology?.features.reduce((current, feature) => {
|
|
const geometry = feature.geometry;
|
|
if (geometry == null)
|
|
return current;
|
|
return geometryBbox(geometry, current);
|
|
}, void 0);
|
|
if (topology == null) {
|
|
Logger18.warnOnce(`no topology was provided for [MapShapeBackgroundSeries]; nothing will be rendered.`);
|
|
}
|
|
}
|
|
createNodeData() {
|
|
const { id: seriesId, topology, scale, properties } = this;
|
|
if (topology == null)
|
|
return;
|
|
const { stroke: stroke3, strokeOpacity, lineDash, lineDashOffset, strokeWidth } = properties;
|
|
const nodeData = [];
|
|
const labelData = [];
|
|
for (const [index, feature] of topology.features.entries()) {
|
|
const { geometry } = feature;
|
|
const projectedGeometry = geometry != null && scale != null ? projectGeometry(geometry, scale) : void 0;
|
|
if (projectedGeometry == null)
|
|
continue;
|
|
nodeData.push({
|
|
series: this,
|
|
datum: feature,
|
|
datumIndex: 0,
|
|
index,
|
|
projectedGeometry,
|
|
style: { stroke: stroke3, strokeOpacity, lineDash, lineDashOffset, strokeWidth }
|
|
});
|
|
}
|
|
return {
|
|
itemId: seriesId,
|
|
nodeData,
|
|
labelData
|
|
};
|
|
}
|
|
updateSelections() {
|
|
if (this.nodeDataRefresh) {
|
|
this.contextNodeData = this.createNodeData();
|
|
this.nodeDataRefresh = false;
|
|
}
|
|
}
|
|
update() {
|
|
const { datumSelection } = this;
|
|
this.updateSelections();
|
|
this.contentGroup.visible = this.visible;
|
|
this.labelGroup.visible = this.visible;
|
|
const { nodeData = [] } = this.contextNodeData ?? {};
|
|
this.datumSelection = this.updateDatumSelection({ nodeData, datumSelection });
|
|
this.updateDatumNodes({ datumSelection });
|
|
}
|
|
updateDatumSelection(opts) {
|
|
return opts.datumSelection.update(opts.nodeData, void 0, (datum) => createDatumId12(datum.index));
|
|
}
|
|
updateDatumNodes(opts) {
|
|
const { datumSelection } = opts;
|
|
datumSelection.each((geoGeometry, datum) => {
|
|
const { projectedGeometry } = datum;
|
|
if (projectedGeometry == null) {
|
|
geoGeometry.visible = false;
|
|
geoGeometry.projectedGeometry = void 0;
|
|
return;
|
|
}
|
|
geoGeometry.visible = true;
|
|
geoGeometry.projectedGeometry = projectedGeometry;
|
|
geoGeometry.setProperties(datum.style);
|
|
});
|
|
}
|
|
resetAnimation() {
|
|
}
|
|
getLegendData() {
|
|
return [];
|
|
}
|
|
getTooltipContent(_seriesDatum) {
|
|
return;
|
|
}
|
|
computeFocusBounds(_opts) {
|
|
return void 0;
|
|
}
|
|
hasItemStylers() {
|
|
return false;
|
|
}
|
|
};
|
|
MapLineBackgroundSeries.className = "MapLineBackgroundSeries";
|
|
MapLineBackgroundSeries.type = "map-line-background";
|
|
|
|
// packages/ag-charts-enterprise/src/series/map-line-background/mapLineBackgroundSeriesOptionsDef.ts
|
|
import { _ModuleSupport as _ModuleSupport166 } from "ag-charts-community";
|
|
import { constant as constant12, geoJson as geoJson2, required as required12 } from "ag-charts-core";
|
|
var { mapLineBackgroundSeriesThemeableOptionsDef } = _ModuleSupport166;
|
|
var mapLineBackgroundSeriesOptionsDef = {
|
|
...mapLineBackgroundSeriesThemeableOptionsDef,
|
|
type: required12(constant12("map-line-background")),
|
|
topology: geoJson2
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/series/map-line-background/mapLineBackgroundModule.ts
|
|
var MapLineBackgroundSeriesModule = {
|
|
type: "series",
|
|
name: "map-line-background",
|
|
chartType: "topology",
|
|
enterprise: true,
|
|
version: VERSION37,
|
|
dependencies: [TopologyChartModule],
|
|
options: mapLineBackgroundSeriesOptionsDef,
|
|
themeTemplate: {
|
|
...MAP_THEME_DEFAULTS,
|
|
series: {
|
|
stroke: { $path: ["/1", { $mapPalette: "stroke" }, { $mapPalette: "secondHierarchyColors" }] },
|
|
strokeWidth: 1,
|
|
lineDash: [0],
|
|
lineDashOffset: 0
|
|
}
|
|
},
|
|
create: (ctx) => new MapLineBackgroundSeries(ctx)
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/series/map-marker/mapMarkerModule.ts
|
|
import { VERSION as VERSION38 } from "ag-charts-community";
|
|
import {
|
|
FILL_GRADIENT_RADIAL_REVERSED_DEFAULTS as FILL_GRADIENT_RADIAL_REVERSED_DEFAULTS2,
|
|
FILL_IMAGE_DEFAULTS as FILL_IMAGE_DEFAULTS9,
|
|
FILL_PATTERN_DEFAULTS as FILL_PATTERN_DEFAULTS5,
|
|
LABEL_BOXING_DEFAULTS as LABEL_BOXING_DEFAULTS10,
|
|
MULTI_SERIES_HIGHLIGHT_STYLE as MULTI_SERIES_HIGHLIGHT_STYLE5,
|
|
SAFE_RANGE2_OPERATION as SAFE_RANGE2_OPERATION5,
|
|
ValidationError,
|
|
validate
|
|
} from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/series/map-marker/mapMarkerSeries.ts
|
|
import { _ModuleSupport as _ModuleSupport169 } from "ag-charts-community";
|
|
import {
|
|
Logger as Logger19,
|
|
StateMachine as StateMachine13,
|
|
cachedTextMeasurer as cachedTextMeasurer9,
|
|
mergeDefaults as mergeDefaults15
|
|
} from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/series/map-util/polygonPointSearch.ts
|
|
import { insertListItemsSorted } from "ag-charts-core";
|
|
function polygonPointSearch(polygons, precision, valueFn) {
|
|
const bbox = polygonBbox(polygons[0], void 0);
|
|
if (bbox == null)
|
|
return;
|
|
const boundingXCenter = (bbox.lon0 + bbox.lon1) / 2;
|
|
const boundingYCenter = (bbox.lat0 + bbox.lat1) / 2;
|
|
const boundingWidth = Math.abs(bbox.lon1 - bbox.lon0);
|
|
const boundingHeight = Math.abs(bbox.lat1 - bbox.lat0);
|
|
const centroid = polygonCentroid(polygons[0]);
|
|
const [cx, cy] = centroid;
|
|
const centroidDistanceToPolygon = -polygonDistance(polygons, cx, cy);
|
|
let bestResult;
|
|
const cellValue = (distanceToPolygon, distanceToCentroid) => {
|
|
const centroidDriftFactor = 0.5;
|
|
const centroidDrift = Math.max(distanceToCentroid - centroidDistanceToPolygon, 0);
|
|
return distanceToPolygon - centroidDriftFactor * centroidDrift;
|
|
};
|
|
const createLabelPlacement = (x2, y2, stride) => {
|
|
const { distance: distance2, maxDistance } = valueFn(polygons, x2, y2, stride);
|
|
const distanceToCentroid = Math.hypot(cx - x2, cy - y2);
|
|
const maxXTowardsCentroid = Math.min(Math.max(cx, x2 - stride / 2), x2 + stride / 2);
|
|
const maxYTowardsCentroid = Math.min(Math.max(cy, y2 - stride / 2), y2 + stride / 2);
|
|
const minDistanceToCentroid = Math.hypot(cx - maxXTowardsCentroid, cy - maxYTowardsCentroid);
|
|
const value = cellValue(distance2, distanceToCentroid);
|
|
const maxValue = cellValue(maxDistance, minDistanceToCentroid);
|
|
return { distance: distance2, maxDistance, value, maxValue, x: x2, y: y2, stride };
|
|
};
|
|
const appendLabelPlacement = (into, x2, y2, stride) => {
|
|
const labelPlacement = createLabelPlacement(x2, y2, stride);
|
|
if (labelPlacement.maxDistance >= 0) {
|
|
into.push(labelPlacement);
|
|
}
|
|
};
|
|
const initialStride = Math.min(boundingWidth, boundingHeight) / 2;
|
|
let queue = {
|
|
value: createLabelPlacement(boundingXCenter, boundingYCenter, initialStride),
|
|
next: null
|
|
};
|
|
while (queue != null) {
|
|
const item = queue.value;
|
|
const { distance: distance2, value, maxValue, x: x2, y: y2, stride } = item;
|
|
queue = queue.next;
|
|
if (distance2 > 0 && (bestResult == null || value > bestResult.value)) {
|
|
bestResult = item;
|
|
}
|
|
if (bestResult != null && maxValue - bestResult.value <= precision) {
|
|
continue;
|
|
}
|
|
const nextStride = stride / 2;
|
|
const newLabelPlacements = [];
|
|
appendLabelPlacement(newLabelPlacements, x2 - nextStride, y2 - nextStride, nextStride);
|
|
appendLabelPlacement(newLabelPlacements, x2 + nextStride, y2 - nextStride, nextStride);
|
|
appendLabelPlacement(newLabelPlacements, x2 - nextStride, y2 + nextStride, nextStride);
|
|
appendLabelPlacement(newLabelPlacements, x2 + nextStride, y2 + nextStride, nextStride);
|
|
newLabelPlacements.sort(labelPlacementCmp);
|
|
queue = insertListItemsSorted(queue, newLabelPlacements, labelPlacementCmp);
|
|
}
|
|
if (bestResult == null)
|
|
return;
|
|
const { distance, x, y } = bestResult;
|
|
return { x, y, distance };
|
|
}
|
|
var labelPlacementCmp = (a, b) => b.maxValue - a.maxValue;
|
|
|
|
// packages/ag-charts-enterprise/src/series/map-util/markerUtil.ts
|
|
function polygonMarkerCenter(polygons, precision) {
|
|
const result = polygonPointSearch(polygons, precision, (p, x2, y2, stride) => {
|
|
const distance = -polygonDistance(p, x2, y2);
|
|
const maxDistance = distance + stride * Math.SQRT2;
|
|
return { distance, maxDistance };
|
|
});
|
|
if (result == null)
|
|
return;
|
|
const { x, y } = result;
|
|
return [x, y];
|
|
}
|
|
function markerPositions(geometry, precision) {
|
|
let center;
|
|
switch (geometry.type) {
|
|
case "GeometryCollection":
|
|
return geometry.geometries.flatMap((g) => markerPositions(g, precision));
|
|
case "MultiPoint":
|
|
return geometry.coordinates;
|
|
case "Point":
|
|
return [geometry.coordinates];
|
|
case "MultiPolygon": {
|
|
const polygon = largestPolygon(geometry);
|
|
center = polygon == null ? void 0 : polygonMarkerCenter(polygon, precision);
|
|
break;
|
|
}
|
|
case "Polygon": {
|
|
const polygon = geometry.coordinates;
|
|
center = polygon == null ? void 0 : polygonMarkerCenter(polygon, precision);
|
|
break;
|
|
}
|
|
case "MultiLineString": {
|
|
const lineString = largestLineString(geometry);
|
|
center = lineString == null ? void 0 : lineStringCenter(lineString)?.point;
|
|
break;
|
|
}
|
|
case "LineString": {
|
|
const lineString = geometry.coordinates;
|
|
center = lineStringCenter(lineString)?.point;
|
|
break;
|
|
}
|
|
}
|
|
return center == null ? [] : [center];
|
|
}
|
|
|
|
// packages/ag-charts-enterprise/src/series/map-util/shapeFillBBox.ts
|
|
import { _ModuleSupport as _ModuleSupport167 } from "ag-charts-community";
|
|
var { BBox: BBox22 } = _ModuleSupport167;
|
|
function getTopologyShapeFillBBox(scale) {
|
|
if (!scale)
|
|
return;
|
|
const { range: range2 } = scale;
|
|
const x = range2[0][0];
|
|
const y = range2[0][1];
|
|
const width = range2[1][0] - x;
|
|
const height = range2[1][1] - y;
|
|
const bbox = new BBox22(x, y, width, height);
|
|
return {
|
|
series: bbox,
|
|
axis: bbox
|
|
};
|
|
}
|
|
|
|
// packages/ag-charts-enterprise/src/series/map-marker/mapMarkerSeriesProperties.ts
|
|
import { _ModuleSupport as _ModuleSupport168 } from "ag-charts-community";
|
|
import { Property as Property77 } from "ag-charts-core";
|
|
var { SeriesProperties: SeriesProperties5, makeSeriesTooltip: makeSeriesTooltip14, Label: Label11 } = _ModuleSupport168;
|
|
var MapMarkerSeriesLabel = class extends Label11 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.placement = "bottom";
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property77
|
|
], MapMarkerSeriesLabel.prototype, "placement", 2);
|
|
var MapMarkerSeriesProperties = class extends SeriesProperties5 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.topology = void 0;
|
|
this.idKey = void 0;
|
|
this.topologyIdKey = "name";
|
|
this.idName = void 0;
|
|
this.latitudeKey = void 0;
|
|
this.latitudeName = void 0;
|
|
this.longitudeKey = void 0;
|
|
this.longitudeName = void 0;
|
|
this.labelKey = void 0;
|
|
this.labelName = void 0;
|
|
this.colorRange = void 0;
|
|
this.shape = "circle";
|
|
this.size = 6;
|
|
this.fill = "black";
|
|
this.fillOpacity = 1;
|
|
this.stroke = "black";
|
|
this.strokeWidth = 1;
|
|
this.strokeOpacity = 1;
|
|
this.lineDash = [0];
|
|
this.lineDashOffset = 0;
|
|
this.label = new MapMarkerSeriesLabel();
|
|
this.tooltip = makeSeriesTooltip14();
|
|
}
|
|
getStyle() {
|
|
const { size, shape, fill, fillOpacity, stroke: stroke3, strokeWidth, strokeOpacity, lineDash, lineDashOffset } = this;
|
|
return {
|
|
size,
|
|
shape,
|
|
fill,
|
|
fillOpacity,
|
|
opacity: 1,
|
|
stroke: stroke3,
|
|
strokeWidth,
|
|
strokeOpacity,
|
|
lineDash,
|
|
lineDashOffset
|
|
};
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property77
|
|
], MapMarkerSeriesProperties.prototype, "topology", 2);
|
|
__decorateClass([
|
|
Property77
|
|
], MapMarkerSeriesProperties.prototype, "title", 2);
|
|
__decorateClass([
|
|
Property77
|
|
], MapMarkerSeriesProperties.prototype, "legendItemName", 2);
|
|
__decorateClass([
|
|
Property77
|
|
], MapMarkerSeriesProperties.prototype, "idKey", 2);
|
|
__decorateClass([
|
|
Property77
|
|
], MapMarkerSeriesProperties.prototype, "topologyIdKey", 2);
|
|
__decorateClass([
|
|
Property77
|
|
], MapMarkerSeriesProperties.prototype, "idName", 2);
|
|
__decorateClass([
|
|
Property77
|
|
], MapMarkerSeriesProperties.prototype, "latitudeKey", 2);
|
|
__decorateClass([
|
|
Property77
|
|
], MapMarkerSeriesProperties.prototype, "latitudeName", 2);
|
|
__decorateClass([
|
|
Property77
|
|
], MapMarkerSeriesProperties.prototype, "longitudeKey", 2);
|
|
__decorateClass([
|
|
Property77
|
|
], MapMarkerSeriesProperties.prototype, "longitudeName", 2);
|
|
__decorateClass([
|
|
Property77
|
|
], MapMarkerSeriesProperties.prototype, "labelKey", 2);
|
|
__decorateClass([
|
|
Property77
|
|
], MapMarkerSeriesProperties.prototype, "labelName", 2);
|
|
__decorateClass([
|
|
Property77
|
|
], MapMarkerSeriesProperties.prototype, "sizeKey", 2);
|
|
__decorateClass([
|
|
Property77
|
|
], MapMarkerSeriesProperties.prototype, "sizeName", 2);
|
|
__decorateClass([
|
|
Property77
|
|
], MapMarkerSeriesProperties.prototype, "colorKey", 2);
|
|
__decorateClass([
|
|
Property77
|
|
], MapMarkerSeriesProperties.prototype, "colorName", 2);
|
|
__decorateClass([
|
|
Property77
|
|
], MapMarkerSeriesProperties.prototype, "colorRange", 2);
|
|
__decorateClass([
|
|
Property77
|
|
], MapMarkerSeriesProperties.prototype, "shape", 2);
|
|
__decorateClass([
|
|
Property77
|
|
], MapMarkerSeriesProperties.prototype, "size", 2);
|
|
__decorateClass([
|
|
Property77
|
|
], MapMarkerSeriesProperties.prototype, "maxSize", 2);
|
|
__decorateClass([
|
|
Property77
|
|
], MapMarkerSeriesProperties.prototype, "sizeDomain", 2);
|
|
__decorateClass([
|
|
Property77
|
|
], MapMarkerSeriesProperties.prototype, "fill", 2);
|
|
__decorateClass([
|
|
Property77
|
|
], MapMarkerSeriesProperties.prototype, "fillOpacity", 2);
|
|
__decorateClass([
|
|
Property77
|
|
], MapMarkerSeriesProperties.prototype, "stroke", 2);
|
|
__decorateClass([
|
|
Property77
|
|
], MapMarkerSeriesProperties.prototype, "strokeWidth", 2);
|
|
__decorateClass([
|
|
Property77
|
|
], MapMarkerSeriesProperties.prototype, "strokeOpacity", 2);
|
|
__decorateClass([
|
|
Property77
|
|
], MapMarkerSeriesProperties.prototype, "lineDash", 2);
|
|
__decorateClass([
|
|
Property77
|
|
], MapMarkerSeriesProperties.prototype, "lineDashOffset", 2);
|
|
__decorateClass([
|
|
Property77
|
|
], MapMarkerSeriesProperties.prototype, "itemStyler", 2);
|
|
__decorateClass([
|
|
Property77
|
|
], MapMarkerSeriesProperties.prototype, "label", 2);
|
|
__decorateClass([
|
|
Property77
|
|
], MapMarkerSeriesProperties.prototype, "tooltip", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/series/map-marker/mapMarkerSeries.ts
|
|
var {
|
|
fromToMotion: fromToMotion3,
|
|
getMissCount: getMissCount3,
|
|
createDatumId: createDatumId13,
|
|
SeriesNodePickMode: SeriesNodePickMode10,
|
|
valueProperty: valueProperty12,
|
|
computeMarkerFocusBounds: computeMarkerFocusBounds2,
|
|
ColorScale: ColorScale3,
|
|
LinearScale: LinearScale6,
|
|
Group: Group14,
|
|
Selection: Selection10,
|
|
Text: Text5,
|
|
Marker: Marker4,
|
|
getLabelStyles: getLabelStyles3
|
|
} = _ModuleSupport169;
|
|
var MapMarkerSeries = class extends TopologySeries {
|
|
constructor(moduleCtx) {
|
|
super({
|
|
moduleCtx,
|
|
categoryKey: void 0,
|
|
propertyKeys: {
|
|
size: ["colorKey"],
|
|
color: ["colorKey"],
|
|
label: ["labelKey"]
|
|
},
|
|
propertyNames: {
|
|
size: ["sizeName"],
|
|
color: ["colorName"],
|
|
label: ["labelName"]
|
|
},
|
|
pickModes: [SeriesNodePickMode10.EXACT_SHAPE_MATCH, SeriesNodePickMode10.NEAREST_NODE],
|
|
usesPlacedLabels: true
|
|
});
|
|
this.properties = new MapMarkerSeriesProperties();
|
|
this._chartTopology = void 0;
|
|
this.colorScale = new ColorScale3();
|
|
this.sizeScale = new LinearScale6();
|
|
this.markerGroup = this.contentGroup.appendChild(new Group14({ name: "markerGroup" }));
|
|
this.labelSelection = Selection10.select(this.labelGroup, Text5, false);
|
|
this.highlightLabelSelection = Selection10.select(this.highlightLabelGroup, Text5, false);
|
|
this.markerSelection = Selection10.select(
|
|
this.markerGroup,
|
|
Marker4,
|
|
false
|
|
);
|
|
this.highlightMarkerSelection = Selection10.select(this.highlightNodeGroup, Marker4);
|
|
this.placedLabelData = [];
|
|
this.animationState = new StateMachine13(
|
|
"empty",
|
|
{
|
|
empty: {
|
|
update: {
|
|
target: "ready",
|
|
action: () => this.animateMarkers()
|
|
},
|
|
reset: "empty",
|
|
skip: "ready"
|
|
},
|
|
ready: {
|
|
updateData: "waiting",
|
|
clear: "clearing",
|
|
resize: () => this.resetAllAnimation(),
|
|
reset: "empty",
|
|
skip: "ready"
|
|
},
|
|
waiting: {
|
|
update: {
|
|
target: "ready",
|
|
action: () => this.animateMarkers()
|
|
},
|
|
// chart.ts transitions to updateData on zoom change
|
|
resize: {
|
|
target: "ready",
|
|
action: () => this.resetAllAnimation()
|
|
},
|
|
reset: "empty",
|
|
skip: "ready"
|
|
},
|
|
clearing: {
|
|
update: {
|
|
target: "empty",
|
|
action: () => this.resetAllAnimation()
|
|
},
|
|
reset: "empty",
|
|
skip: "ready"
|
|
}
|
|
},
|
|
() => this.checkProcessedDataAnimatable()
|
|
);
|
|
}
|
|
getNodeData() {
|
|
return this.contextNodeData?.nodeData;
|
|
}
|
|
get topology() {
|
|
return this.properties.topology ?? this._chartTopology;
|
|
}
|
|
get hasData() {
|
|
const hasLatLon = this.properties.latitudeKey != null && this.properties.longitudeKey != null;
|
|
return super.hasData && (this.topology != null || hasLatLon);
|
|
}
|
|
renderToOffscreenCanvas() {
|
|
return true;
|
|
}
|
|
setChartTopology(topology) {
|
|
this._chartTopology = topology;
|
|
if (this.topology === topology) {
|
|
this.nodeDataRefresh = true;
|
|
}
|
|
}
|
|
setZIndex(zIndex) {
|
|
super.setZIndex(zIndex);
|
|
this.contentGroup.zIndex = [2 /* Marker */, zIndex];
|
|
this.highlightGroup.zIndex = [3 /* MarkerHighlight */, zIndex];
|
|
return true;
|
|
}
|
|
isLabelEnabled() {
|
|
return this.properties.labelKey != null && this.properties.label.enabled;
|
|
}
|
|
async processData(dataController) {
|
|
if (this.data == null)
|
|
return;
|
|
const { data, sizeScale, colorScale } = this;
|
|
const { topologyIdKey, idKey, latitudeKey, longitudeKey, sizeKey, colorKey, labelKey, sizeDomain, colorRange } = this.properties;
|
|
const featureById = this.buildFeatureMap(topologyIdKey);
|
|
const sizeScaleType = this.sizeScale.type;
|
|
const colorScaleType = this.colorScale.type;
|
|
const mercatorScaleType = this.scale?.type;
|
|
const hasLatLon = latitudeKey != null && longitudeKey != null;
|
|
const { dataModel, processedData } = await this.requestDataModel(dataController, data, {
|
|
props: [
|
|
...idKey == null ? [] : [
|
|
valueProperty12(idKey, mercatorScaleType, { id: "idValue", includeProperty: false }),
|
|
valueProperty12(idKey, mercatorScaleType, {
|
|
id: "featureValue",
|
|
includeProperty: false,
|
|
processor: () => (datum) => featureById.get(datum)
|
|
})
|
|
],
|
|
...hasLatLon ? [
|
|
valueProperty12(latitudeKey, mercatorScaleType, { id: "latValue" }),
|
|
valueProperty12(longitudeKey, mercatorScaleType, { id: "lonValue" })
|
|
] : [],
|
|
...labelKey ? [valueProperty12(labelKey, "category", { id: "labelValue" })] : [],
|
|
...sizeKey ? [valueProperty12(sizeKey, sizeScaleType, { id: "sizeValue" })] : [],
|
|
...colorKey ? [valueProperty12(colorKey, colorScaleType, { id: "colorValue" })] : []
|
|
]
|
|
});
|
|
const featureValues = idKey == null ? void 0 : dataModel.resolveColumnById(this, `featureValue`, processedData);
|
|
const latValues = hasLatLon ? dataModel.resolveColumnById(this, `latValue`, processedData) : void 0;
|
|
const lonValues = hasLatLon ? dataModel.resolveColumnById(this, `lonValue`, processedData) : void 0;
|
|
this.topologyBounds = processedData.dataSources.get(this.id)?.data.reduce((current, _datum, datumIndex) => {
|
|
const feature = featureValues?.[datumIndex];
|
|
const geometry = feature?.geometry;
|
|
if (geometry != null) {
|
|
current = geometryBbox(geometry, current);
|
|
}
|
|
if (latValues != null && lonValues != null) {
|
|
const lon = lonValues[datumIndex];
|
|
const lat = latValues[datumIndex];
|
|
current = LonLatBBox.extend(current, lon, lat, lon, lat);
|
|
}
|
|
return current;
|
|
}, void 0);
|
|
if (sizeKey != null) {
|
|
const sizeIdx = dataModel.resolveProcessedDataIndexById(this, `sizeValue`);
|
|
const processedSize = processedData.domain.values[sizeIdx] ?? [];
|
|
sizeScale.domain = sizeDomain ?? processedSize;
|
|
}
|
|
if (colorRange != null && this.isColorScaleValid()) {
|
|
const colorKeyIdx = dataModel.resolveProcessedDataIndexById(this, "colorValue");
|
|
colorScale.domain = processedData.domain.values[colorKeyIdx];
|
|
colorScale.range = colorRange;
|
|
colorScale.update();
|
|
}
|
|
this.animationState.transition("updateData");
|
|
}
|
|
isColorScaleValid() {
|
|
const { colorKey } = this.properties;
|
|
if (!colorKey) {
|
|
return false;
|
|
}
|
|
const { dataModel, processedData } = this;
|
|
if (!dataModel || !processedData) {
|
|
return false;
|
|
}
|
|
const colorIdx = dataModel.resolveProcessedDataIndexById(this, "colorValue");
|
|
const dataCount = processedData.input.count;
|
|
const missCount = getMissCount3(this, processedData.defs.values[colorIdx].missing);
|
|
const colorDataMissing = dataCount === 0 || dataCount === missCount;
|
|
return !colorDataMissing;
|
|
}
|
|
getLabelDatum(node, labelValue, measurer3) {
|
|
if (labelValue == null)
|
|
return;
|
|
const {
|
|
idKey,
|
|
idName,
|
|
latitudeKey,
|
|
latitudeName,
|
|
longitudeKey,
|
|
longitudeName,
|
|
sizeKey,
|
|
sizeName,
|
|
colorKey,
|
|
colorName,
|
|
labelKey,
|
|
labelName,
|
|
label,
|
|
shape
|
|
} = this.properties;
|
|
if (labelKey == null || !label.enabled)
|
|
return;
|
|
const { datum, datumIndex, index, idValue, lonValue, latValue, point } = node;
|
|
const { placement } = label;
|
|
const labelText = this.getLabelText(
|
|
labelValue,
|
|
datum,
|
|
labelKey,
|
|
"label",
|
|
[],
|
|
label,
|
|
{
|
|
value: labelValue,
|
|
datum,
|
|
idKey,
|
|
idName,
|
|
latitudeKey,
|
|
latitudeName,
|
|
longitudeKey,
|
|
longitudeName,
|
|
sizeKey,
|
|
sizeName,
|
|
colorKey,
|
|
colorName,
|
|
labelKey,
|
|
labelName
|
|
}
|
|
);
|
|
if (labelText == null)
|
|
return;
|
|
const { width, height } = measurer3.measureLines(String(labelText));
|
|
const anchor = Marker4.anchor(shape);
|
|
return {
|
|
point: { x: point.x, y: point.y, size: point.size },
|
|
label: { width, height, text: labelText },
|
|
anchor,
|
|
placement,
|
|
datumIndex,
|
|
datumId: createDatumId13(index, idValue, lonValue, latValue)
|
|
};
|
|
}
|
|
resolveColumn(key, columnId, processedData) {
|
|
if (key == null || this.dataModel == null)
|
|
return void 0;
|
|
return this.dataModel.resolveColumnById(this, columnId, processedData);
|
|
}
|
|
resolveDataColumns(processedData) {
|
|
const { idKey, latitudeKey, longitudeKey, sizeKey, colorKey, labelKey } = this.properties;
|
|
const hasLatLon = latitudeKey != null && longitudeKey != null;
|
|
return {
|
|
idValues: this.resolveColumn(idKey, "idValue", processedData),
|
|
featureValues: this.resolveColumn(idKey, "featureValue", processedData),
|
|
latValues: hasLatLon ? this.resolveColumn(latitudeKey, "latValue", processedData) : void 0,
|
|
lonValues: hasLatLon ? this.resolveColumn(longitudeKey, "lonValue", processedData) : void 0,
|
|
labelValues: this.resolveColumn(labelKey, "labelValue", processedData),
|
|
sizeValues: this.resolveColumn(sizeKey, "sizeValue", processedData),
|
|
colorValues: this.resolveColumn(colorKey, "colorValue", processedData)
|
|
};
|
|
}
|
|
prepareProjectedGeometries(idValues, featureValues, processedData) {
|
|
if (idValues == null || featureValues == null || this.scale == null)
|
|
return void 0;
|
|
const projectedGeometries = /* @__PURE__ */ new Map();
|
|
for (const [datumIndex] of processedData.dataSources.get(this.id)?.data.entries() ?? []) {
|
|
const id = idValues[datumIndex];
|
|
const geometry = featureValues[datumIndex]?.geometry;
|
|
const projectedGeometry = geometry == null ? void 0 : projectGeometry(geometry, this.scale);
|
|
if (id != null && projectedGeometry != null) {
|
|
projectedGeometries.set(id, projectedGeometry);
|
|
}
|
|
}
|
|
return projectedGeometries;
|
|
}
|
|
calculateMarkerSize(sizeValue) {
|
|
return sizeValue == null ? this.properties.size : this.sizeScale.convert(sizeValue, { clamp: true });
|
|
}
|
|
buildNodeDatum(datum, datumIndex, index, point, dataValues) {
|
|
return {
|
|
series: this,
|
|
datum,
|
|
datumIndex,
|
|
index,
|
|
...dataValues,
|
|
point,
|
|
midPoint: { x: point.x, y: point.y },
|
|
legendItemName: this.properties.legendItemName,
|
|
style: this.getMarkerItemStyle(
|
|
{ datumIndex, datum, colorValue: dataValues.colorValue, sizeValue: dataValues.sizeValue },
|
|
false
|
|
)
|
|
};
|
|
}
|
|
createNodeFromLatLon(datum, datumIndex, lonValue, latValue, dataValues, size, measurer3) {
|
|
if (this.scale == null) {
|
|
throw new Error("Scale is required for createNodeFromLatLon");
|
|
}
|
|
const [x, y] = this.scale.convert([lonValue, latValue]);
|
|
const point = { x, y, size };
|
|
const node = this.buildNodeDatum(datum, datumIndex, -1, point, dataValues);
|
|
const label = this.getLabelDatum(node, dataValues.labelValue, measurer3) ?? void 0;
|
|
return { node, label };
|
|
}
|
|
createNodesFromGeometry(datum, datumIndex, geometry, dataValues, size, measurer3) {
|
|
const nodes = [];
|
|
const labels = [];
|
|
for (const [index, [x, y]] of markerPositions(geometry, 1).entries()) {
|
|
const point = { x, y, size };
|
|
const node = this.buildNodeDatum(datum, datumIndex, index, point, dataValues);
|
|
nodes.push(node);
|
|
const label = this.getLabelDatum(node, dataValues.labelValue, measurer3);
|
|
if (label) {
|
|
labels.push(label);
|
|
}
|
|
}
|
|
return { nodes, labels };
|
|
}
|
|
warnMissingGeometries(missingGeometries) {
|
|
if (missingGeometries.length === 0)
|
|
return;
|
|
const missingGeometriesCap = 10;
|
|
if (missingGeometries.length > missingGeometriesCap) {
|
|
const excessItems = missingGeometries.length - missingGeometriesCap;
|
|
missingGeometries.length = missingGeometriesCap;
|
|
missingGeometries.push(`(+${excessItems} more)`);
|
|
}
|
|
Logger19.warnOnce(`some data items do not have matches in the provided topology`, missingGeometries);
|
|
}
|
|
buildFeatureMap(topologyIdKey) {
|
|
const featureById = /* @__PURE__ */ new Map();
|
|
for (const feature of this.topology?.features.values() ?? []) {
|
|
const property = feature.properties?.[topologyIdKey];
|
|
if (property != null) {
|
|
featureById.set(property, feature);
|
|
}
|
|
}
|
|
return featureById;
|
|
}
|
|
createNodeData() {
|
|
const { id: seriesId, dataModel, processedData, sizeScale, properties, scale } = this;
|
|
const { label } = properties;
|
|
if (dataModel == null || processedData == null || scale == null)
|
|
return;
|
|
if (!this.visible) {
|
|
return { itemId: seriesId, nodeData: [], labelData: [] };
|
|
}
|
|
const columns = this.resolveDataColumns(processedData);
|
|
const markerMaxSize = properties.maxSize ?? properties.size;
|
|
sizeScale.range = [Math.min(properties.size, markerMaxSize), markerMaxSize];
|
|
const measurer3 = cachedTextMeasurer9(label);
|
|
const projectedGeometries = this.prepareProjectedGeometries(
|
|
columns.idValues,
|
|
columns.featureValues,
|
|
processedData
|
|
);
|
|
const nodeData = [];
|
|
const labelData = [];
|
|
const missingGeometries = [];
|
|
const rawData = processedData.dataSources.get(this.id)?.data ?? [];
|
|
for (const [datumIndex, datum] of rawData.entries()) {
|
|
const dataValues = {
|
|
idValue: columns.idValues?.[datumIndex],
|
|
lonValue: columns.lonValues?.[datumIndex],
|
|
latValue: columns.latValues?.[datumIndex],
|
|
colorValue: columns.colorValues?.[datumIndex],
|
|
sizeValue: columns.sizeValues?.[datumIndex],
|
|
labelValue: columns.labelValues?.[datumIndex]
|
|
};
|
|
const size = this.calculateMarkerSize(dataValues.sizeValue);
|
|
const projectedGeometry = dataValues.idValue == null ? void 0 : projectedGeometries?.get(dataValues.idValue);
|
|
if (dataValues.idValue != null && projectedGeometries != null && projectedGeometry == null) {
|
|
missingGeometries.push(dataValues.idValue);
|
|
}
|
|
if (dataValues.lonValue != null && dataValues.latValue != null) {
|
|
const result = this.createNodeFromLatLon(
|
|
datum,
|
|
datumIndex,
|
|
dataValues.lonValue,
|
|
dataValues.latValue,
|
|
dataValues,
|
|
size,
|
|
measurer3
|
|
);
|
|
nodeData.push(result.node);
|
|
if (result.label)
|
|
labelData.push(result.label);
|
|
} else if (projectedGeometry != null) {
|
|
const result = this.createNodesFromGeometry(
|
|
datum,
|
|
datumIndex,
|
|
projectedGeometry,
|
|
dataValues,
|
|
size,
|
|
measurer3
|
|
);
|
|
nodeData.push(...result.nodes);
|
|
labelData.push(...result.labels);
|
|
}
|
|
}
|
|
this.warnMissingGeometries(missingGeometries);
|
|
return {
|
|
itemId: seriesId,
|
|
nodeData,
|
|
labelData
|
|
};
|
|
}
|
|
updateSelections() {
|
|
if (this.nodeDataRefresh) {
|
|
this.contextNodeData = this.createNodeData();
|
|
this.nodeDataRefresh = false;
|
|
}
|
|
}
|
|
checkScaleChange() {
|
|
if (this.previousScale === this.scale)
|
|
return false;
|
|
this.previousScale = this.scale;
|
|
return true;
|
|
}
|
|
update({ seriesRect }) {
|
|
const resize = this.checkResize(seriesRect);
|
|
const scaleChange = this.checkScaleChange();
|
|
const { markerSelection, highlightMarkerSelection } = this;
|
|
const drawingMode = this.ctx.chartService.highlight?.drawingMode ?? "overlay";
|
|
this.updateSelections();
|
|
this.contentGroup.visible = this.visible;
|
|
this.labelGroup.visible = this.visible;
|
|
const highlightedDatum = this.getHighlightedDatum();
|
|
const nodeData = this.contextNodeData?.nodeData ?? [];
|
|
this.markerSelection = this.updateMarkerSelection({ markerData: nodeData, markerSelection });
|
|
this.updateMarkerNodes({ markerSelection, isHighlight: false, highlightedDatum, drawingMode: "overlay" });
|
|
this.highlightMarkerSelection = this.updateMarkerSelection({
|
|
markerData: highlightedDatum == null ? [] : [highlightedDatum],
|
|
markerSelection: highlightMarkerSelection
|
|
});
|
|
this.updateMarkerNodes({
|
|
markerSelection: highlightMarkerSelection,
|
|
isHighlight: true,
|
|
highlightedDatum,
|
|
drawingMode
|
|
});
|
|
this.updateLabelNodes({ labelSelection: this.labelSelection, isHighlight: false });
|
|
this.updateHighlightLabelSelection(highlightedDatum);
|
|
if (scaleChange || resize) {
|
|
this.animationState.transition("resize");
|
|
}
|
|
this.animationState.transition("update");
|
|
}
|
|
updatePlacedLabelData(labelData) {
|
|
this.placedLabelData = labelData;
|
|
this.labelSelection = this.labelSelection.update(labelData, (text2) => {
|
|
text2.pointerEvents = _ModuleSupport169.PointerEvents.None;
|
|
});
|
|
this.updateLabelNodes({ labelSelection: this.labelSelection, isHighlight: false });
|
|
this.updateHighlightLabelSelection();
|
|
}
|
|
updateLabelNodes({
|
|
isHighlight,
|
|
labelSelection
|
|
}) {
|
|
const { properties } = this;
|
|
const activeHighlight = this.ctx.highlightManager?.getActiveHighlight();
|
|
labelSelection.each((label, placedLabel) => {
|
|
const { x, y, width, height, text: text2, datum: labelDatum } = placedLabel;
|
|
const style = getLabelStyles3(
|
|
this,
|
|
void 0,
|
|
properties,
|
|
properties.label,
|
|
isHighlight,
|
|
activeHighlight
|
|
);
|
|
const { color: fill, fontStyle, fontWeight, fontSize, fontFamily } = style;
|
|
label.visible = true;
|
|
label.x = x + width / 2;
|
|
label.y = y + height / 2;
|
|
label.text = text2;
|
|
label.fill = fill;
|
|
label.fontStyle = fontStyle;
|
|
label.fontWeight = fontWeight;
|
|
label.fontSize = fontSize;
|
|
label.fontFamily = fontFamily;
|
|
label.textAlign = "center";
|
|
label.textBaseline = "middle";
|
|
const datumIndex = labelDatum?.datumIndex;
|
|
label.fillOpacity = this.getHighlightStyle(isHighlight, datumIndex).opacity ?? 1;
|
|
label.setBoxing(style);
|
|
});
|
|
}
|
|
getHighlightedLabelId(highlightedDatum = this.getHighlightedDatum()) {
|
|
if (highlightedDatum == null)
|
|
return void 0;
|
|
return createDatumId13(
|
|
highlightedDatum.index,
|
|
highlightedDatum.idValue,
|
|
highlightedDatum.lonValue,
|
|
highlightedDatum.latValue
|
|
);
|
|
}
|
|
updateHighlightLabelSelection(highlightedDatum = this.getHighlightedDatum()) {
|
|
const highlightId = this.getHighlightedLabelId(highlightedDatum);
|
|
const highlightLabels = highlightId == null || !this.isLabelEnabled() ? [] : this.placedLabelData.filter((label) => label.datum.datumId === highlightId);
|
|
this.highlightLabelSelection = this.highlightLabelSelection.update(highlightLabels);
|
|
if (highlightLabels.length === 0) {
|
|
this.highlightLabelSelection.cleanup();
|
|
this.highlightLabelGroup.visible = false;
|
|
return;
|
|
}
|
|
this.highlightLabelGroup.visible = true;
|
|
this.updateLabelNodes({
|
|
labelSelection: this.highlightLabelSelection,
|
|
isHighlight: true
|
|
});
|
|
}
|
|
updateMarkerSelection(opts) {
|
|
const { markerData, markerSelection } = opts;
|
|
return markerSelection.update(
|
|
markerData,
|
|
void 0,
|
|
(datum) => createDatumId13(datum.index, datum.idValue, datum.lonValue, datum.latValue)
|
|
);
|
|
}
|
|
getMarkerItemStyle({ datumIndex, datum, colorValue, sizeValue }, isHighlight) {
|
|
const { properties, colorScale, sizeScale } = this;
|
|
const { colorRange, itemStyler } = properties;
|
|
const highlightStyle = this.getHighlightStyle(isHighlight, datumIndex);
|
|
const baseStyle = mergeDefaults15(highlightStyle, properties.getStyle());
|
|
if (!isHighlight && colorValue != null) {
|
|
baseStyle.fill = this.isColorScaleValid() ? colorScale.convert(colorValue) : colorRange?.[0] ?? baseStyle.fill;
|
|
}
|
|
if (sizeValue != null) {
|
|
baseStyle.size = sizeScale.convert(sizeValue, { clamp: true });
|
|
}
|
|
let style = baseStyle;
|
|
if (itemStyler != null && datumIndex != null) {
|
|
const overrides = this.cachedDatumCallback(
|
|
createDatumId13(datumIndex, isHighlight ? "highlight" : "node"),
|
|
() => {
|
|
const params = this.makeItemStylerParams(datum, datumIndex, isHighlight, style);
|
|
return this.callWithContext(itemStyler, params);
|
|
}
|
|
);
|
|
if (overrides) {
|
|
style = mergeDefaults15(overrides, baseStyle);
|
|
}
|
|
}
|
|
return style;
|
|
}
|
|
makeItemStylerParams(datum, datumIndex, isHighlight, style) {
|
|
const { id: seriesId } = this;
|
|
const activeHighlight = this.ctx.highlightManager?.getActiveHighlight();
|
|
const highlightState = this.getHighlightStateString(activeHighlight, isHighlight, datumIndex);
|
|
const fill = this.filterItemStylerFillParams(style.fill) ?? style.fill;
|
|
return {
|
|
seriesId,
|
|
datum,
|
|
highlightState,
|
|
...style,
|
|
fill
|
|
};
|
|
}
|
|
updateMarkerNodes(opts) {
|
|
const { markerSelection, isHighlight, highlightedDatum, drawingMode } = opts;
|
|
const fillBBox = getTopologyShapeFillBBox(this.scale);
|
|
markerSelection.each((marker, markerDatum) => {
|
|
const { datum, point } = markerDatum;
|
|
const style = this.getMarkerItemStyle(markerDatum, isHighlight);
|
|
marker.shape = style.shape;
|
|
marker.size = style.size;
|
|
marker.setStyleProperties(style, fillBBox);
|
|
marker.x = point.x;
|
|
marker.y = point.y;
|
|
marker.scalingCenterX = point.x;
|
|
marker.scalingCenterY = point.y;
|
|
marker.zIndex = !isHighlight && highlightedDatum != null && datum === highlightedDatum.datum ? 1 : 0;
|
|
marker.drawingMode = drawingMode;
|
|
});
|
|
}
|
|
isProcessedDataAnimatable() {
|
|
return true;
|
|
}
|
|
resetAnimation(phase) {
|
|
if (phase === "initial") {
|
|
this.animationState.transition("reset");
|
|
} else if (phase === "ready") {
|
|
this.animationState.transition("skip");
|
|
}
|
|
}
|
|
resetAllAnimation() {
|
|
this.ctx.animationManager.stopByAnimationGroupId(this.id);
|
|
this.ctx.animationManager.skipCurrentBatch();
|
|
this.labelSelection.cleanup();
|
|
this.markerSelection.cleanup();
|
|
this.highlightMarkerSelection.cleanup();
|
|
this.highlightLabelSelection.cleanup();
|
|
this.highlightLabelGroup.visible = false;
|
|
this.placedLabelData = [];
|
|
}
|
|
animateMarkers() {
|
|
const { animationManager } = this.ctx;
|
|
const fns = prepareMapMarkerAnimationFunctions();
|
|
fromToMotion3(this.id, "markers", animationManager, [this.markerSelection, this.highlightMarkerSelection], fns);
|
|
}
|
|
getLabelData() {
|
|
if (!this.isLabelEnabled())
|
|
return [];
|
|
return this.contextNodeData?.labelData ?? [];
|
|
}
|
|
pickNodeClosestDatum(p) {
|
|
const { x: x0, y: y0 } = p;
|
|
let minDistanceSquared = Infinity;
|
|
let minDatum;
|
|
for (const datum of this.contextNodeData?.nodeData ?? []) {
|
|
const { x, y, size } = datum.point;
|
|
const dx2 = Math.max(Math.abs(x - x0) - size, 0);
|
|
const dy2 = Math.max(Math.abs(y - y0) - size, 0);
|
|
const distanceSquared = dx2 * dx2 + dy2 * dy2;
|
|
if (distanceSquared < minDistanceSquared) {
|
|
minDistanceSquared = distanceSquared;
|
|
minDatum = datum;
|
|
}
|
|
}
|
|
return minDatum == null ? void 0 : { datum: minDatum, distance: Math.sqrt(minDistanceSquared) };
|
|
}
|
|
legendItemSymbol(datumIndex) {
|
|
const { dataModel, processedData, properties } = this;
|
|
const { shape, fillOpacity, stroke: stroke3, strokeWidth, strokeOpacity, lineDash, lineDashOffset } = properties;
|
|
let { fill } = properties;
|
|
if (datumIndex != null && this.isColorScaleValid()) {
|
|
const colorValues = dataModel.resolveColumnById(this, "colorValue", processedData);
|
|
const colorValue = colorValues[datumIndex];
|
|
fill = this.colorScale.convert(colorValue);
|
|
}
|
|
return {
|
|
marker: {
|
|
shape,
|
|
fill,
|
|
fillOpacity,
|
|
stroke: stroke3,
|
|
strokeWidth,
|
|
strokeOpacity,
|
|
lineDash,
|
|
lineDashOffset
|
|
}
|
|
};
|
|
}
|
|
getLegendData(legendType) {
|
|
const { processedData, dataModel } = this;
|
|
if (processedData == null || dataModel == null)
|
|
return [];
|
|
const { id: seriesId, visible } = this;
|
|
const { title, legendItemName, idName, idKey, colorKey, colorRange, showInLegend } = this.properties;
|
|
if (legendType === "gradient" && colorKey != null && colorRange != null) {
|
|
const colorDomain = processedData.domain.values[dataModel.resolveProcessedDataIndexById(this, "colorValue")];
|
|
const legendDatum = {
|
|
legendType: "gradient",
|
|
enabled: visible,
|
|
seriesId,
|
|
series: this.getFormatterContext("color"),
|
|
colorRange,
|
|
colorDomain
|
|
};
|
|
return [legendDatum];
|
|
} else if (legendType === "category") {
|
|
const legendDatum = {
|
|
legendType: "category",
|
|
id: seriesId,
|
|
itemId: seriesId,
|
|
seriesId,
|
|
enabled: visible,
|
|
label: { text: legendItemName ?? title ?? idName ?? idKey ?? seriesId },
|
|
symbol: this.legendItemSymbol(),
|
|
legendItemName,
|
|
hideInLegend: !showInLegend
|
|
};
|
|
return [legendDatum];
|
|
} else {
|
|
return [];
|
|
}
|
|
}
|
|
getTooltipContent(datumIndex) {
|
|
const {
|
|
id: seriesId,
|
|
dataModel,
|
|
processedData,
|
|
properties,
|
|
ctx: { formatManager }
|
|
} = this;
|
|
const {
|
|
idKey,
|
|
idName,
|
|
latitudeKey,
|
|
latitudeName,
|
|
longitudeKey,
|
|
longitudeName,
|
|
colorKey,
|
|
colorName,
|
|
sizeKey,
|
|
sizeName,
|
|
labelKey,
|
|
labelName,
|
|
title,
|
|
legendItemName,
|
|
tooltip
|
|
} = properties;
|
|
if (!dataModel || !processedData)
|
|
return;
|
|
const datum = processedData.dataSources.get(this.id)?.data[datumIndex];
|
|
const sizeValue = sizeKey == null ? void 0 : dataModel.resolveColumnById(this, `sizeValue`, processedData)[datumIndex];
|
|
const colorValue = colorKey == null ? void 0 : dataModel.resolveColumnById(this, `colorValue`, processedData)[datumIndex];
|
|
const data = [];
|
|
if (this.isLabelEnabled() && labelKey != null && labelKey !== idKey) {
|
|
const labelValue = dataModel.resolveColumnById(this, `labelValue`, processedData)[datumIndex];
|
|
const content = formatManager.format(this.callWithContext.bind(this), {
|
|
type: "category",
|
|
value: labelValue,
|
|
datum,
|
|
seriesId,
|
|
legendItemName,
|
|
key: labelKey,
|
|
source: "tooltip",
|
|
property: "label",
|
|
domain: [],
|
|
boundSeries: this.getFormatterContext("label")
|
|
});
|
|
data.push({ label: labelName, fallbackLabel: labelKey, value: content ?? labelValue });
|
|
}
|
|
if (sizeKey != null && sizeValue != null) {
|
|
const domain = dataModel.getDomain(this, `sizeValue`, "value", processedData).domain;
|
|
const content = formatManager.format(this.callWithContext.bind(this), {
|
|
type: "number",
|
|
value: sizeValue,
|
|
datum,
|
|
seriesId,
|
|
legendItemName,
|
|
key: sizeKey,
|
|
source: "tooltip",
|
|
property: "size",
|
|
domain,
|
|
boundSeries: this.getFormatterContext("size"),
|
|
fractionDigits: void 0,
|
|
visibleDomain: void 0
|
|
});
|
|
data.push({ label: sizeName, fallbackLabel: sizeKey, value: content ?? String(sizeValue) });
|
|
}
|
|
if (colorKey != null && colorValue != null) {
|
|
const domain = dataModel.getDomain(this, `colorValue`, "value", processedData).domain;
|
|
const content = formatManager.format(this.callWithContext.bind(this), {
|
|
type: "number",
|
|
value: colorValue,
|
|
datum,
|
|
seriesId,
|
|
legendItemName,
|
|
key: colorKey,
|
|
source: "tooltip",
|
|
property: "color",
|
|
domain,
|
|
boundSeries: this.getFormatterContext("color"),
|
|
fractionDigits: void 0,
|
|
visibleDomain: void 0
|
|
});
|
|
data.push({ label: colorName, fallbackLabel: colorKey, value: content ?? String(colorValue) });
|
|
}
|
|
let heading;
|
|
if (idKey != null) {
|
|
heading = dataModel.resolveColumnById(this, `idValue`, processedData)[datumIndex];
|
|
} else if (latitudeKey != null && longitudeKey != null) {
|
|
const latValue = dataModel.resolveColumnById(this, `latValue`, processedData)[datumIndex];
|
|
const lonValue = dataModel.resolveColumnById(this, `lonValue`, processedData)[datumIndex];
|
|
heading = `${Math.abs(latValue).toFixed(4)}\xB0 ${latValue >= 0 ? "N" : "S"}, ${Math.abs(lonValue).toFixed(4)}\xB0 ${lonValue >= 0 ? "W" : "E"}`;
|
|
}
|
|
const format = this.getMarkerItemStyle({ datumIndex, datum, colorValue, sizeValue }, false);
|
|
return this.formatTooltipWithContext(
|
|
tooltip,
|
|
{
|
|
heading,
|
|
title: title ?? legendItemName,
|
|
symbol: this.legendItemSymbol(datumIndex),
|
|
data
|
|
},
|
|
{
|
|
seriesId,
|
|
datum,
|
|
title,
|
|
idKey,
|
|
idName,
|
|
latitudeKey,
|
|
latitudeName,
|
|
longitudeKey,
|
|
longitudeName,
|
|
colorKey,
|
|
colorName,
|
|
sizeKey,
|
|
sizeName,
|
|
labelKey,
|
|
labelName,
|
|
...format
|
|
}
|
|
);
|
|
}
|
|
getFormattedMarkerStyle(markerDatum) {
|
|
const format = this.getMarkerItemStyle(markerDatum, false);
|
|
return { size: format.size, shape: format.shape };
|
|
}
|
|
computeFocusBounds(opts) {
|
|
return computeMarkerFocusBounds2(this, opts);
|
|
}
|
|
hasItemStylers() {
|
|
return this.properties.itemStyler != null || this.properties.label.itemStyler != null;
|
|
}
|
|
};
|
|
MapMarkerSeries.className = "MapMarkerSeries";
|
|
MapMarkerSeries.type = "map-marker";
|
|
|
|
// packages/ag-charts-enterprise/src/series/map-marker/mapMarkerSeriesOptionsDef.ts
|
|
import { _ModuleSupport as _ModuleSupport170 } from "ag-charts-community";
|
|
import {
|
|
commonSeriesOptionsDefs as commonSeriesOptionsDefs12,
|
|
constant as constant13,
|
|
geoJson as geoJson3,
|
|
required as required13,
|
|
string as string14,
|
|
without as without7
|
|
} from "ag-charts-core";
|
|
var { mapMarkerSeriesThemeableOptionsDef } = _ModuleSupport170;
|
|
var mapMarkerSeriesOptionsDef = {
|
|
...without7(commonSeriesOptionsDefs12, ["highlightStyle", "highlight"]),
|
|
...mapMarkerSeriesThemeableOptionsDef,
|
|
type: required13(constant13("map-marker")),
|
|
idKey: string14,
|
|
latitudeKey: string14,
|
|
longitudeKey: string14,
|
|
sizeKey: string14,
|
|
colorKey: string14,
|
|
labelKey: string14,
|
|
idName: string14,
|
|
latitudeName: string14,
|
|
longitudeName: string14,
|
|
sizeName: string14,
|
|
colorName: string14,
|
|
labelName: string14,
|
|
topology: geoJson3,
|
|
topologyIdKey: string14,
|
|
legendItemName: string14,
|
|
title: string14
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/series/map-marker/mapMarkerModule.ts
|
|
var MapMarkerSeriesModule = {
|
|
type: "series",
|
|
name: "map-marker",
|
|
chartType: "topology",
|
|
enterprise: true,
|
|
version: VERSION38,
|
|
dependencies: [TopologyChartModule],
|
|
options: mapMarkerSeriesOptionsDef,
|
|
themeTemplate: {
|
|
...MAP_THEME_DEFAULTS,
|
|
series: {
|
|
shape: "circle",
|
|
maxSize: 30,
|
|
fill: applyMapPalette({
|
|
$applySwitch: [
|
|
{ $path: "type" },
|
|
{ $mapPalette: "fill" },
|
|
["gradient", FILL_GRADIENT_RADIAL_REVERSED_DEFAULTS2],
|
|
["image", FILL_IMAGE_DEFAULTS9],
|
|
["pattern", FILL_PATTERN_DEFAULTS5]
|
|
]
|
|
}),
|
|
stroke: { $mapPalette: "stroke" },
|
|
colorRange: {
|
|
$if: [
|
|
{ $eq: [{ $mapPalette: "type" }, "inbuilt"] },
|
|
{ $mapPalette: "divergingColors" },
|
|
applyMapPalette(SAFE_RANGE2_OPERATION5)
|
|
]
|
|
},
|
|
fillOpacity: 0.5,
|
|
label: {
|
|
...LABEL_BOXING_DEFAULTS10,
|
|
enabled: false,
|
|
fontSize: { $ref: "fontSize" },
|
|
fontFamily: { $ref: "fontFamily" },
|
|
fontWeight: { $ref: "fontWeight" },
|
|
color: { $ref: "textColor" }
|
|
},
|
|
highlight: applyMapPalette(MULTI_SERIES_HIGHLIGHT_STYLE5)
|
|
},
|
|
tooltip: {
|
|
range: "exact"
|
|
}
|
|
},
|
|
create: (ctx) => new MapMarkerSeries(ctx),
|
|
validate(options, optionsDefs, path) {
|
|
const result = validate(options, optionsDefs, path);
|
|
const { cleared, invalid } = result;
|
|
if (cleared?.idKey == null && (cleared?.latitudeKey == null || cleared?.longitudeKey == null)) {
|
|
const extendPath = (key) => path ? `${path}.${key}` : key;
|
|
const message = `Either \`${extendPath("idKey")}\` or both \`${extendPath("latitudeKey")}\` and \`${extendPath("longitudeKey")}\` are required.`;
|
|
invalid.push(new ValidationError("required", message, null, path));
|
|
}
|
|
return result;
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/series/map-shape/mapShapeModule.ts
|
|
import { VERSION as VERSION39 } from "ag-charts-community";
|
|
import {
|
|
FILL_GRADIENT_LINEAR_DEFAULTS as FILL_GRADIENT_LINEAR_DEFAULTS5,
|
|
FILL_IMAGE_DEFAULTS as FILL_IMAGE_DEFAULTS10,
|
|
FILL_PATTERN_DEFAULTS as FILL_PATTERN_DEFAULTS6,
|
|
LABEL_BOXING_DEFAULTS as LABEL_BOXING_DEFAULTS11,
|
|
MULTI_SERIES_HIGHLIGHT_STYLE as MULTI_SERIES_HIGHLIGHT_STYLE6,
|
|
SAFE_RANGE2_OPERATION as SAFE_RANGE2_OPERATION6
|
|
} from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/series/map-shape/mapShapeSeries.ts
|
|
import { _ModuleSupport as _ModuleSupport172 } from "ag-charts-community";
|
|
import { Logger as Logger20, cachedTextMeasurer as cachedTextMeasurer10, isArray as isArray5, measureTextSegments as measureTextSegments4, mergeDefaults as mergeDefaults16, toPlainText as toPlainText7 } from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/series/map-util/polygonLabelUtil.ts
|
|
function preferredLabelCenter(polygons, { aspectRatio, precision }) {
|
|
const result = polygonPointSearch(polygons, precision, (p, cx, cy, stride) => {
|
|
const width = maxWidthOfRectConstrainedByCenterAndAspectRatioToPolygon(p, cx, cy, aspectRatio);
|
|
const maxWidth2 = width + 2 * stride * aspectRatio;
|
|
const distance2 = width * Math.SQRT2;
|
|
const maxDistance = maxWidth2 * Math.SQRT2;
|
|
return { distance: distance2, maxDistance };
|
|
});
|
|
if (result == null)
|
|
return;
|
|
const { x, y, distance } = result;
|
|
const maxWidth = distance / Math.SQRT2;
|
|
return { x, y, maxWidth };
|
|
}
|
|
function maxWidthOfRectConstrainedByCenterAndAspectRatioToLineSegment(a, b, cx, cy, aspectRatio) {
|
|
const [ax, ay] = a;
|
|
const [bx, by] = b;
|
|
const positiveM = 1 / aspectRatio;
|
|
const abx = bx - ax;
|
|
const aby = by - ay;
|
|
const [topPointX, topPointY] = ay <= by ? a : b;
|
|
const [leftPointX, leftPointY] = ax <= bx ? a : b;
|
|
const [bottomPointX, bottomPointY] = ay <= by ? b : a;
|
|
const [rightPointX, rightPointY] = ax <= bx ? b : a;
|
|
let maxWidth = Infinity;
|
|
if (abx === 0) {
|
|
for (let i = 0; i <= 1; i += 1) {
|
|
const m = i === 0 ? positiveM : -positiveM;
|
|
const y = m * (ax - cx) + cy;
|
|
if (y >= topPointY && y <= bottomPointY) {
|
|
const height = Math.abs(cy - y) * 2;
|
|
const width = height * aspectRatio;
|
|
maxWidth = Math.min(maxWidth, width);
|
|
}
|
|
}
|
|
} else {
|
|
const abm = aby / abx;
|
|
for (let i = 0; i <= 1; i += 1) {
|
|
const m = i === 0 ? positiveM : -positiveM;
|
|
const x = (abm * ax - ay - m * cx + cy) / (abm - m);
|
|
if (x >= leftPointX && x <= rightPointX) {
|
|
const width = Math.abs(cx - x) * 2;
|
|
maxWidth = Math.min(maxWidth, width);
|
|
}
|
|
}
|
|
}
|
|
const positiveMRecip = aspectRatio;
|
|
const centerToTopMRecip = Math.abs((topPointX - cx) / (topPointY - cy));
|
|
const centerToBottomMRecip = Math.abs((bottomPointX - cx) / (bottomPointY - cy));
|
|
if (bottomPointY < cy && centerToBottomMRecip < positiveMRecip) {
|
|
const height = Math.abs(cy - bottomPointY) * 2;
|
|
const width = height * aspectRatio;
|
|
maxWidth = Math.min(maxWidth, width);
|
|
} else if (topPointY > cy && centerToTopMRecip < positiveMRecip) {
|
|
const height = Math.abs(cy - topPointY) * 2;
|
|
const width = height * aspectRatio;
|
|
maxWidth = Math.min(maxWidth, width);
|
|
}
|
|
const centerToLeftM = Math.abs((leftPointY - cy) / (leftPointX - cx));
|
|
const centerToRightM = Math.abs((rightPointY - cy) / (rightPointX - cx));
|
|
if (rightPointX < cx && centerToRightM < positiveM) {
|
|
const width = Math.abs(cx - rightPointX) * 2;
|
|
maxWidth = Math.min(maxWidth, width);
|
|
} else if (leftPointX > cx && centerToLeftM < positiveM) {
|
|
const width = Math.abs(cx - leftPointX) * 2;
|
|
maxWidth = Math.min(maxWidth, width);
|
|
}
|
|
return maxWidth;
|
|
}
|
|
function maxWidthOfRectConstrainedByCenterAndAspectRatioToPolygon(polygons, cx, cy, aspectRatio) {
|
|
let inside = false;
|
|
let minWidth = Infinity;
|
|
for (const polygon of polygons) {
|
|
let p0 = polygon.at(-1);
|
|
let [x0, y0] = p0;
|
|
for (const p1 of polygon) {
|
|
const [x1, y1] = p1;
|
|
if (y1 > cy !== y0 > cy && cx < (x0 - x1) * (cy - y1) / (y0 - y1) + x1) {
|
|
inside = !inside;
|
|
}
|
|
const width = maxWidthOfRectConstrainedByCenterAndAspectRatioToLineSegment(p0, p1, cx, cy, aspectRatio);
|
|
minWidth = Math.min(minWidth, width);
|
|
p0 = p1;
|
|
x0 = x1;
|
|
y0 = y1;
|
|
}
|
|
}
|
|
return (inside ? 1 : -1) * minWidth;
|
|
}
|
|
function applyX(into, cx, x) {
|
|
if (x >= cx) {
|
|
into.maxX = Math.min(into.maxX, x - cx);
|
|
}
|
|
if (x <= cx) {
|
|
into.minX = Math.max(into.minX, x - cx);
|
|
}
|
|
}
|
|
function xExtentsOfRectConstrainedByCenterAndHeightToLineSegment(into, a, b, cx, cy, height) {
|
|
const ry0 = cy - height / 2;
|
|
const ry1 = cy + height / 2;
|
|
const [ax, ay] = a;
|
|
const [bx, by] = b;
|
|
const abx = bx - ax;
|
|
const aby = by - ay;
|
|
const [leftPointX, leftPointY] = ax <= bx ? a : b;
|
|
const [rightPointX, rightPointY] = ax <= bx ? b : a;
|
|
if (abx !== 0) {
|
|
const abm = aby / abx;
|
|
for (let i = 0; i <= 1; i += 1) {
|
|
const y = i === 0 ? ry0 : ry1;
|
|
const x = (y - ay) / abm + ax;
|
|
if (x >= leftPointX && x <= rightPointX) {
|
|
applyX(into, cx, x);
|
|
}
|
|
}
|
|
} else if (Math.max(ry0, Math.min(ay, by)) <= Math.min(ry1, Math.max(ay, by))) {
|
|
applyX(into, cx, ax);
|
|
}
|
|
if (rightPointX < cx && rightPointY >= ry0 && rightPointY <= ry1) {
|
|
applyX(into, cx, rightPointX);
|
|
} else if (leftPointX > cx && leftPointY >= ry0 && leftPointY <= ry1) {
|
|
applyX(into, cx, leftPointX);
|
|
}
|
|
return into;
|
|
}
|
|
function maxWidthInPolygonForRectOfHeight(polygons, cx, cy, height) {
|
|
const result = {
|
|
minX: -Infinity,
|
|
maxX: Infinity
|
|
};
|
|
for (const polygon of polygons) {
|
|
let p0 = polygon.at(-1);
|
|
for (const p1 of polygon) {
|
|
xExtentsOfRectConstrainedByCenterAndHeightToLineSegment(result, p0, p1, cx, cy, height);
|
|
p0 = p1;
|
|
}
|
|
}
|
|
const { minX, maxX } = result;
|
|
if (Number.isFinite(minX) && Number.isFinite(maxX)) {
|
|
return { x: cx + (minX + maxX) / 2, width: maxX - minX };
|
|
} else {
|
|
return { x: cx, width: 0 };
|
|
}
|
|
}
|
|
|
|
// packages/ag-charts-enterprise/src/series/map-shape/mapShapeSeriesProperties.ts
|
|
import { _ModuleSupport as _ModuleSupport171 } from "ag-charts-community";
|
|
import { Property as Property78 } from "ag-charts-core";
|
|
var { SeriesProperties: SeriesProperties6, makeSeriesTooltip: makeSeriesTooltip15 } = _ModuleSupport171;
|
|
var MapShapeSeriesProperties = class extends SeriesProperties6 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.topology = void 0;
|
|
this.idKey = "";
|
|
this.idName = void 0;
|
|
this.topologyIdKey = "name";
|
|
this.labelKey = void 0;
|
|
this.labelName = void 0;
|
|
this.colorRange = void 0;
|
|
this.fill = "black";
|
|
this.fillOpacity = 1;
|
|
this.stroke = "black";
|
|
this.strokeOpacity = 1;
|
|
this.strokeWidth = 0;
|
|
this.lineDash = [0];
|
|
this.lineDashOffset = 0;
|
|
this.padding = 0;
|
|
this.label = new AutoSizedSecondaryLabel();
|
|
this.tooltip = makeSeriesTooltip15();
|
|
}
|
|
getStyle() {
|
|
const { fill, fillOpacity, stroke: stroke3, strokeWidth, strokeOpacity, lineDash, lineDashOffset } = this;
|
|
return {
|
|
fill,
|
|
fillOpacity,
|
|
stroke: stroke3,
|
|
strokeWidth,
|
|
strokeOpacity,
|
|
lineDash,
|
|
lineDashOffset,
|
|
opacity: 1
|
|
};
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property78
|
|
], MapShapeSeriesProperties.prototype, "topology", 2);
|
|
__decorateClass([
|
|
Property78
|
|
], MapShapeSeriesProperties.prototype, "title", 2);
|
|
__decorateClass([
|
|
Property78
|
|
], MapShapeSeriesProperties.prototype, "legendItemName", 2);
|
|
__decorateClass([
|
|
Property78
|
|
], MapShapeSeriesProperties.prototype, "idKey", 2);
|
|
__decorateClass([
|
|
Property78
|
|
], MapShapeSeriesProperties.prototype, "idName", 2);
|
|
__decorateClass([
|
|
Property78
|
|
], MapShapeSeriesProperties.prototype, "topologyIdKey", 2);
|
|
__decorateClass([
|
|
Property78
|
|
], MapShapeSeriesProperties.prototype, "labelKey", 2);
|
|
__decorateClass([
|
|
Property78
|
|
], MapShapeSeriesProperties.prototype, "labelName", 2);
|
|
__decorateClass([
|
|
Property78
|
|
], MapShapeSeriesProperties.prototype, "colorKey", 2);
|
|
__decorateClass([
|
|
Property78
|
|
], MapShapeSeriesProperties.prototype, "colorName", 2);
|
|
__decorateClass([
|
|
Property78
|
|
], MapShapeSeriesProperties.prototype, "colorRange", 2);
|
|
__decorateClass([
|
|
Property78
|
|
], MapShapeSeriesProperties.prototype, "fill", 2);
|
|
__decorateClass([
|
|
Property78
|
|
], MapShapeSeriesProperties.prototype, "fillOpacity", 2);
|
|
__decorateClass([
|
|
Property78
|
|
], MapShapeSeriesProperties.prototype, "stroke", 2);
|
|
__decorateClass([
|
|
Property78
|
|
], MapShapeSeriesProperties.prototype, "strokeOpacity", 2);
|
|
__decorateClass([
|
|
Property78
|
|
], MapShapeSeriesProperties.prototype, "strokeWidth", 2);
|
|
__decorateClass([
|
|
Property78
|
|
], MapShapeSeriesProperties.prototype, "lineDash", 2);
|
|
__decorateClass([
|
|
Property78
|
|
], MapShapeSeriesProperties.prototype, "lineDashOffset", 2);
|
|
__decorateClass([
|
|
Property78
|
|
], MapShapeSeriesProperties.prototype, "padding", 2);
|
|
__decorateClass([
|
|
Property78
|
|
], MapShapeSeriesProperties.prototype, "itemStyler", 2);
|
|
__decorateClass([
|
|
Property78
|
|
], MapShapeSeriesProperties.prototype, "label", 2);
|
|
__decorateClass([
|
|
Property78
|
|
], MapShapeSeriesProperties.prototype, "tooltip", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/series/map-shape/mapShapeSeries.ts
|
|
var {
|
|
getMissCount: getMissCount4,
|
|
createDatumId: createDatumId14,
|
|
SeriesNodePickMode: SeriesNodePickMode11,
|
|
valueProperty: valueProperty13,
|
|
ColorScale: ColorScale4,
|
|
Group: Group15,
|
|
Selection: Selection11,
|
|
Text: Text6,
|
|
PointerEvents: PointerEvents7,
|
|
getLabelStyles: getLabelStyles4
|
|
} = _ModuleSupport172;
|
|
var fixedScale = _ModuleSupport172.MercatorScale.fixedScale();
|
|
var MapShapeSeries = class extends TopologySeries {
|
|
constructor(moduleCtx) {
|
|
super({
|
|
moduleCtx,
|
|
categoryKey: void 0,
|
|
propertyKeys: {
|
|
color: ["colorKey"],
|
|
label: ["labelKey"]
|
|
},
|
|
propertyNames: {
|
|
color: ["colorName"],
|
|
label: ["labelName"]
|
|
},
|
|
pickModes: [SeriesNodePickMode11.EXACT_SHAPE_MATCH, SeriesNodePickMode11.NEAREST_NODE]
|
|
});
|
|
this.properties = new MapShapeSeriesProperties();
|
|
this._chartTopology = void 0;
|
|
this.colorScale = new ColorScale4();
|
|
this.itemGroup = this.contentGroup.appendChild(new Group15({ name: "itemGroup" }));
|
|
this.itemLabelGroup = this.contentGroup.appendChild(new Group15({ name: "itemLabelGroup" }));
|
|
this.datumSelection = Selection11.select(
|
|
this.itemGroup,
|
|
() => this.nodeFactory()
|
|
);
|
|
this.labelSelection = Selection11.select(
|
|
this.itemLabelGroup,
|
|
Text6
|
|
);
|
|
this.highlightDatumSelection = Selection11.select(
|
|
this.highlightNodeGroup,
|
|
() => this.nodeFactory()
|
|
);
|
|
this.highlightLabelSelection = Selection11.select(this.highlightLabelGroup, Text6);
|
|
this.previousLabelLayouts = void 0;
|
|
this._previousDatumMidPoint = void 0;
|
|
this.itemLabelGroup.pointerEvents = PointerEvents7.None;
|
|
}
|
|
getNodeData() {
|
|
return this.contextNodeData?.nodeData;
|
|
}
|
|
get topology() {
|
|
return this.properties.topology ?? this._chartTopology;
|
|
}
|
|
get hasData() {
|
|
return super.hasData && this.topology != null;
|
|
}
|
|
renderToOffscreenCanvas() {
|
|
return true;
|
|
}
|
|
setChartTopology(topology) {
|
|
this._chartTopology = topology;
|
|
if (this.topology === topology) {
|
|
this.nodeDataRefresh = true;
|
|
}
|
|
}
|
|
setZIndex(zIndex) {
|
|
super.setZIndex(zIndex);
|
|
this.contentGroup.zIndex = [1 /* ShapeLine */, zIndex];
|
|
this.highlightGroup.zIndex = [4 /* ShapeLineHighlight */, zIndex];
|
|
return true;
|
|
}
|
|
isLabelEnabled() {
|
|
return this.properties.labelKey != null && this.properties.label.enabled;
|
|
}
|
|
nodeFactory() {
|
|
const geoGeometry = new GeoGeometry();
|
|
geoGeometry.renderMode = 1 /* Polygons */;
|
|
geoGeometry.lineJoin = "round";
|
|
return geoGeometry;
|
|
}
|
|
async processData(dataController) {
|
|
if (this.data == null)
|
|
return;
|
|
const { data, topology, colorScale } = this;
|
|
const { topologyIdKey, idKey, colorKey, labelKey, colorRange } = this.properties;
|
|
const featureById = /* @__PURE__ */ new Map();
|
|
for (const feature of topology?.features.values() ?? []) {
|
|
const property = feature.properties?.[topologyIdKey];
|
|
if (property == null || !containsType(feature.geometry, 1 /* Polygon */))
|
|
continue;
|
|
featureById.set(property, feature);
|
|
}
|
|
const colorScaleType = this.colorScale.type;
|
|
const mercatorScaleType = this.scale?.type;
|
|
const { dataModel, processedData } = await this.requestDataModel(dataController, data, {
|
|
props: [
|
|
valueProperty13(idKey, mercatorScaleType, { id: "idValue", includeProperty: false }),
|
|
valueProperty13(idKey, mercatorScaleType, {
|
|
id: "featureValue",
|
|
includeProperty: false,
|
|
processor: () => (datum) => featureById.get(datum)
|
|
}),
|
|
...labelKey ? [valueProperty13(labelKey, "category", { id: "labelValue" })] : [],
|
|
...colorKey ? [valueProperty13(colorKey, colorScaleType, { id: "colorValue" })] : []
|
|
]
|
|
});
|
|
const featureValues = dataModel.resolveColumnById(this, `featureValue`, processedData);
|
|
this.topologyBounds = featureValues.reduce((current, feature) => {
|
|
const geometry = feature?.geometry;
|
|
if (geometry == null)
|
|
return current;
|
|
return geometryBbox(geometry, current);
|
|
}, void 0);
|
|
if (colorRange != null && this.isColorScaleValid()) {
|
|
const colorKeyIdx = dataModel.resolveProcessedDataIndexById(this, "colorValue");
|
|
colorScale.domain = processedData.domain.values[colorKeyIdx];
|
|
colorScale.range = colorRange;
|
|
colorScale.update();
|
|
}
|
|
if (topology == null) {
|
|
Logger20.warnOnce(`no topology was provided for [MapShapeSeries]; nothing will be rendered.`);
|
|
}
|
|
}
|
|
isColorScaleValid() {
|
|
const { colorKey } = this.properties;
|
|
if (!colorKey) {
|
|
return false;
|
|
}
|
|
const { dataModel, processedData } = this;
|
|
if (!dataModel || !processedData) {
|
|
return false;
|
|
}
|
|
const colorIdx = dataModel.resolveProcessedDataIndexById(this, "colorValue");
|
|
const dataCount = processedData.input.count;
|
|
const missCount = getMissCount4(this, processedData.defs.values[colorIdx].missing);
|
|
const colorDataMissing = dataCount === 0 || dataCount === missCount;
|
|
return !colorDataMissing;
|
|
}
|
|
getLabelLayout(datum, labelValue, measurer3, geometry, previousLabelLayout) {
|
|
if (labelValue == null || geometry == null)
|
|
return;
|
|
const { idKey, idName, colorKey, colorName, labelKey, labelName, padding: padding2, label } = this.properties;
|
|
if (labelKey == null || !label.enabled)
|
|
return;
|
|
const labelText = this.getLabelText(
|
|
labelValue,
|
|
datum,
|
|
labelKey,
|
|
"label",
|
|
[],
|
|
label,
|
|
{
|
|
value: labelValue,
|
|
datum,
|
|
idKey,
|
|
idName,
|
|
colorKey,
|
|
colorName,
|
|
labelKey,
|
|
labelName
|
|
}
|
|
);
|
|
if (labelText == null)
|
|
return;
|
|
const baseSize = isArray5(labelText) ? measureTextSegments4(labelText, label) : measurer3.measureLines(String(labelText));
|
|
const aspectRatio = (baseSize.width + 2 * padding2) / (baseSize.height + 2 * padding2);
|
|
if (previousLabelLayout?.geometry === geometry && previousLabelLayout?.labelText === labelText && previousLabelLayout?.aspectRatio === aspectRatio) {
|
|
return previousLabelLayout;
|
|
}
|
|
const fixedGeometry = projectGeometry(geometry, fixedScale);
|
|
const fixedPolygon = largestPolygon(fixedGeometry);
|
|
if (fixedPolygon == null)
|
|
return;
|
|
const labelPlacement = preferredLabelCenter(fixedPolygon, {
|
|
aspectRatio,
|
|
precision: 1e-3
|
|
});
|
|
if (labelPlacement == null)
|
|
return;
|
|
const { x, y, maxWidth } = labelPlacement;
|
|
return { geometry, labelText, aspectRatio, x, y, maxWidth, fixedPolygon };
|
|
}
|
|
getLabelDatum(labelLayout, scaling, datumIndex, idValue) {
|
|
const { scale } = this;
|
|
if (scale == null)
|
|
return;
|
|
const { padding: padding2, label } = this.properties;
|
|
const { labelText, aspectRatio, x: untruncatedX, y, maxWidth, fixedPolygon } = labelLayout;
|
|
const maxSizeWithoutTruncation = {
|
|
width: Math.ceil(maxWidth * scaling),
|
|
height: Math.ceil(maxWidth * scaling / aspectRatio),
|
|
meta: untruncatedX
|
|
};
|
|
const labelFormatting = formatSingleLabel(
|
|
toPlainText7(labelText),
|
|
label,
|
|
{ padding: padding2 },
|
|
(height, allowTruncation) => {
|
|
if (!allowTruncation) {
|
|
return maxSizeWithoutTruncation;
|
|
}
|
|
const result = maxWidthInPolygonForRectOfHeight(fixedPolygon, untruncatedX, y, height / scaling);
|
|
return {
|
|
width: result.width * scaling,
|
|
height,
|
|
meta: result.x
|
|
};
|
|
}
|
|
);
|
|
if (labelFormatting == null)
|
|
return;
|
|
const [{ text: text2, fontSize, lineHeight, width }, formattingX] = labelFormatting;
|
|
const x = width < maxSizeWithoutTruncation.width ? untruncatedX : formattingX;
|
|
const position = this.scale.convert(fixedScale.invert([x, y]));
|
|
return {
|
|
x: position[0],
|
|
y: position[1],
|
|
text: text2,
|
|
fontSize,
|
|
lineHeight,
|
|
datumIndex,
|
|
idValue,
|
|
datumId: createDatumId14(idValue)
|
|
};
|
|
}
|
|
resolveColumn(key, columnId, processedData) {
|
|
if (key == null || this.dataModel == null)
|
|
return void 0;
|
|
return this.dataModel.resolveColumnById(this, columnId, processedData);
|
|
}
|
|
resolveShapeDataColumns(processedData) {
|
|
const { colorKey, labelKey } = this.properties;
|
|
return {
|
|
idValues: this.dataModel.resolveColumnById(this, "idValue", processedData),
|
|
featureValues: this.dataModel.resolveColumnById(this, "featureValue", processedData),
|
|
labelValues: this.resolveColumn(labelKey, "labelValue", processedData),
|
|
colorValues: this.resolveColumn(colorKey, "colorValue", processedData)
|
|
};
|
|
}
|
|
warnMissingGeometries(missingGeometries) {
|
|
if (missingGeometries.length === 0)
|
|
return;
|
|
const missingGeometriesCap = 10;
|
|
if (missingGeometries.length > missingGeometriesCap) {
|
|
const excessItems = missingGeometries.length - missingGeometriesCap;
|
|
missingGeometries.length = missingGeometriesCap;
|
|
missingGeometries.push(`(+${excessItems} more)`);
|
|
}
|
|
Logger20.warnOnce(`some data items do not have matches in the provided topology`, missingGeometries);
|
|
}
|
|
createNodeData() {
|
|
const { id: seriesId, dataModel, processedData, properties, scale, previousLabelLayouts } = this;
|
|
const { label, legendItemName, colorKey } = properties;
|
|
if (dataModel == null || processedData == null)
|
|
return;
|
|
if (!this.visible) {
|
|
return { itemId: seriesId, nodeData: [], labelData: [] };
|
|
}
|
|
const scaling = scale == null ? Number.NaN : (scale.range[1][0] - scale.range[0][0]) / scale.bounds.width;
|
|
const columns = this.resolveShapeDataColumns(processedData);
|
|
const measurer3 = cachedTextMeasurer10(label);
|
|
const labelLayouts = /* @__PURE__ */ new Map();
|
|
this.previousLabelLayouts = labelLayouts;
|
|
const nodeData = [];
|
|
const labelData = [];
|
|
const missingGeometries = [];
|
|
const rawData = processedData.dataSources.get(this.id)?.data ?? [];
|
|
for (const [datumIndex, datum] of rawData.entries()) {
|
|
const dataValues = {
|
|
idValue: columns.idValues[datumIndex],
|
|
colorValue: columns.colorValues?.[datumIndex],
|
|
labelValue: columns.labelValues?.[datumIndex]
|
|
};
|
|
const geometry = columns.featureValues[datumIndex]?.geometry ?? void 0;
|
|
if (geometry == null) {
|
|
missingGeometries.push(dataValues.idValue);
|
|
}
|
|
if (colorKey != null && dataValues.colorValue == null) {
|
|
continue;
|
|
}
|
|
const labelLayout = this.getLabelLayout(
|
|
datum,
|
|
dataValues.labelValue,
|
|
measurer3,
|
|
geometry,
|
|
previousLabelLayouts?.get(dataValues.idValue)
|
|
);
|
|
if (labelLayout != null) {
|
|
labelLayouts.set(dataValues.idValue, labelLayout);
|
|
}
|
|
const labelDatum = labelLayout != null && scale != null ? this.getLabelDatum(labelLayout, scaling, datumIndex, dataValues.idValue) : void 0;
|
|
if (labelDatum != null) {
|
|
labelData.push(labelDatum);
|
|
}
|
|
const projectedGeometry = geometry != null && scale != null ? projectGeometry(geometry, scale) : void 0;
|
|
nodeData.push({
|
|
series: this,
|
|
datum,
|
|
datumIndex,
|
|
...dataValues,
|
|
projectedGeometry,
|
|
legendItemName,
|
|
style: this.getItemStyle({ datum, datumIndex, colorValue: dataValues.colorValue }, false)
|
|
});
|
|
}
|
|
this.warnMissingGeometries(missingGeometries);
|
|
return {
|
|
itemId: seriesId,
|
|
nodeData,
|
|
labelData
|
|
};
|
|
}
|
|
updateSelections() {
|
|
if (this.nodeDataRefresh) {
|
|
this.contextNodeData = this.createNodeData();
|
|
this.nodeDataRefresh = false;
|
|
}
|
|
}
|
|
update() {
|
|
const { datumSelection, labelSelection, highlightDatumSelection } = this;
|
|
this.updateSelections();
|
|
this.contentGroup.visible = this.visible;
|
|
this.labelGroup.visible = this.visible;
|
|
const drawingMode = this.ctx.chartService.highlight?.drawingMode ?? "overlay";
|
|
const highlightedDatum = this.getHighlightedDatum();
|
|
const nodeData = this.contextNodeData?.nodeData ?? [];
|
|
const labelData = this.contextNodeData?.labelData ?? [];
|
|
this.datumSelection = this.updateDatumSelection({ nodeData, datumSelection });
|
|
this.updateDatumStyles({ datumSelection, isHighlight: false });
|
|
this.updateDatumNodes({ datumSelection, drawingMode: "overlay" });
|
|
this.labelSelection = this.updateLabelSelection({ labelData, labelSelection });
|
|
const highlightLabelData = this.getHighlightLabelData(labelData, highlightedDatum);
|
|
this.highlightLabelSelection = this.updateLabelSelection({
|
|
labelData: highlightLabelData,
|
|
labelSelection: this.highlightLabelSelection
|
|
});
|
|
this.updateLabelNodes({ labelSelection: this.labelSelection, isHighlight: false });
|
|
this.updateLabelNodes({ labelSelection: this.highlightLabelSelection, isHighlight: true });
|
|
this.highlightDatumSelection = this.updateDatumSelection({
|
|
nodeData: highlightedDatum == null ? [] : [highlightedDatum],
|
|
datumSelection: highlightDatumSelection
|
|
});
|
|
this.updateDatumStyles({ datumSelection: highlightDatumSelection, isHighlight: true });
|
|
this.updateDatumNodes({ datumSelection: highlightDatumSelection, drawingMode });
|
|
}
|
|
getHighlightLabelData(labelData, highlightedDatum) {
|
|
if (labelData.length === 0)
|
|
return [];
|
|
const highlightId = createDatumId14(highlightedDatum?.idValue);
|
|
return labelData.filter(
|
|
(labelDatum) => labelDatum.datumId === highlightId && labelDatum.datumIndex === highlightedDatum?.datumIndex
|
|
);
|
|
}
|
|
updateDatumSelection(opts) {
|
|
return opts.datumSelection.update(opts.nodeData, void 0, (datum) => createDatumId14(datum.idValue));
|
|
}
|
|
getItemStyle({ datumIndex, datum, colorValue }, isHighlight) {
|
|
const { properties, colorScale } = this;
|
|
const { colorRange, itemStyler } = properties;
|
|
const baseStyle = properties.getStyle();
|
|
if (colorValue != null) {
|
|
const fillOverride = this.isColorScaleValid() ? colorScale.convert(colorValue) : colorRange?.[0];
|
|
if (fillOverride != null) {
|
|
baseStyle.fill = fillOverride;
|
|
}
|
|
}
|
|
const highlightStyle = this.getHighlightStyle(isHighlight, datumIndex);
|
|
let style = mergeDefaults16(highlightStyle, baseStyle);
|
|
if (itemStyler != null && datumIndex != null) {
|
|
const overrides = this.cachedDatumCallback(
|
|
createDatumId14(datumIndex, isHighlight ? "highlight" : "node"),
|
|
() => {
|
|
const params = this.makeItemStylerParams(datum, datumIndex, isHighlight, style);
|
|
return this.ctx.optionsGraphService.resolvePartial(
|
|
["series", `${this.declarationOrder}`],
|
|
this.callWithContext(itemStyler, params)
|
|
);
|
|
}
|
|
);
|
|
if (overrides) {
|
|
style = mergeDefaults16(overrides, style);
|
|
}
|
|
}
|
|
return style;
|
|
}
|
|
makeItemStylerParams(datum, datumIndex, isHighlight, style) {
|
|
const { id: seriesId } = this;
|
|
const activeHighlight = this.ctx.highlightManager?.getActiveHighlight();
|
|
const highlightState = this.getHighlightStateString(activeHighlight, isHighlight, datumIndex);
|
|
const fill = this.filterItemStylerFillParams(style.fill) ?? style.fill;
|
|
return {
|
|
seriesId,
|
|
datum,
|
|
highlightState,
|
|
...style,
|
|
fill
|
|
};
|
|
}
|
|
updateDatumStyles({
|
|
datumSelection,
|
|
isHighlight
|
|
}) {
|
|
datumSelection.each((_, nodeDatum) => {
|
|
nodeDatum.style = this.getItemStyle(nodeDatum, isHighlight);
|
|
});
|
|
}
|
|
updateDatumNodes({
|
|
datumSelection,
|
|
drawingMode
|
|
}) {
|
|
const fillBBox = getTopologyShapeFillBBox(this.scale);
|
|
datumSelection.each((geoGeometry, nodeDatum) => {
|
|
const { projectedGeometry } = nodeDatum;
|
|
if (projectedGeometry == null) {
|
|
geoGeometry.visible = false;
|
|
geoGeometry.projectedGeometry = void 0;
|
|
return;
|
|
}
|
|
geoGeometry.visible = true;
|
|
geoGeometry.projectedGeometry = projectedGeometry;
|
|
geoGeometry.setStyleProperties(nodeDatum.style, fillBBox);
|
|
geoGeometry.drawingMode = drawingMode;
|
|
});
|
|
}
|
|
updateLabelSelection(opts) {
|
|
const labels = this.isLabelEnabled() ? opts.labelData : [];
|
|
return opts.labelSelection.update(labels);
|
|
}
|
|
updateLabelNodes({
|
|
isHighlight,
|
|
labelSelection
|
|
}) {
|
|
const { properties } = this;
|
|
const activeHighlight = this.ctx.highlightManager?.getActiveHighlight();
|
|
labelSelection.each((label, labelDatum) => {
|
|
const { x, y, text: text2, fontSize, lineHeight, datumIndex } = labelDatum;
|
|
const style = getLabelStyles4(
|
|
this,
|
|
void 0,
|
|
properties,
|
|
properties.label,
|
|
isHighlight,
|
|
activeHighlight
|
|
);
|
|
const { color: fill, fontStyle, fontWeight, fontFamily } = style;
|
|
label.visible = true;
|
|
label.x = x;
|
|
label.y = y;
|
|
label.text = text2;
|
|
label.fill = fill;
|
|
label.fontStyle = fontStyle;
|
|
label.fontWeight = fontWeight;
|
|
label.fontSize = fontSize;
|
|
label.lineHeight = lineHeight;
|
|
label.fontFamily = fontFamily;
|
|
label.textAlign = "center";
|
|
label.textBaseline = "middle";
|
|
label.fillOpacity = this.getHighlightStyle(isHighlight, datumIndex).opacity ?? 1;
|
|
label.setBoxing(style);
|
|
});
|
|
}
|
|
resetAnimation() {
|
|
}
|
|
pickNodeClosestDatum({ x, y }) {
|
|
let minDistanceSquared = Infinity;
|
|
let minDatum;
|
|
this.datumSelection.each((node, datum) => {
|
|
const distanceSquared = node.distanceSquared(x, y);
|
|
if (distanceSquared < minDistanceSquared) {
|
|
minDistanceSquared = distanceSquared;
|
|
minDatum = datum;
|
|
}
|
|
});
|
|
return minDatum == null ? void 0 : { datum: minDatum, distance: Math.sqrt(minDistanceSquared) };
|
|
}
|
|
datumMidPoint(datum) {
|
|
const { _previousDatumMidPoint } = this;
|
|
if (_previousDatumMidPoint?.datum === datum) {
|
|
return _previousDatumMidPoint.point;
|
|
}
|
|
const projectedGeometry = datum.projectedGeometry;
|
|
const polygon = projectedGeometry == null ? void 0 : largestPolygon(projectedGeometry);
|
|
const center = polygon == null ? void 0 : polygonMarkerCenter(polygon, 2);
|
|
const point = center == null ? void 0 : { x: center[0], y: center[1] };
|
|
this._previousDatumMidPoint = { datum, point };
|
|
return point;
|
|
}
|
|
legendItemSymbol(datumIndex) {
|
|
const { dataModel, processedData, properties } = this;
|
|
const { fillOpacity, stroke: stroke3, strokeWidth, strokeOpacity, lineDash, lineDashOffset } = properties;
|
|
let { fill } = properties;
|
|
if (datumIndex != null && this.isColorScaleValid()) {
|
|
const colorValues = dataModel.resolveColumnById(this, "colorValue", processedData);
|
|
const colorValue = colorValues[datumIndex];
|
|
if (colorValue != null) {
|
|
fill = this.colorScale.convert(colorValue);
|
|
}
|
|
}
|
|
return {
|
|
marker: {
|
|
fill,
|
|
fillOpacity,
|
|
stroke: stroke3,
|
|
strokeWidth,
|
|
strokeOpacity,
|
|
lineDash,
|
|
lineDashOffset
|
|
}
|
|
};
|
|
}
|
|
getLegendData(legendType) {
|
|
const { processedData, dataModel } = this;
|
|
if (processedData == null || dataModel == null)
|
|
return [];
|
|
const { id: seriesId, visible } = this;
|
|
const { title, legendItemName, idKey, idName, colorKey, colorRange, showInLegend } = this.properties;
|
|
if (legendType === "gradient" && colorKey != null && colorRange != null) {
|
|
const colorDomain = processedData.domain.values[dataModel.resolveProcessedDataIndexById(this, "colorValue")];
|
|
const legendDatum = {
|
|
legendType: "gradient",
|
|
enabled: visible,
|
|
seriesId,
|
|
series: this.getFormatterContext("color"),
|
|
colorRange,
|
|
colorDomain
|
|
};
|
|
return [legendDatum];
|
|
} else if (legendType === "category") {
|
|
const legendDatum = {
|
|
legendType: "category",
|
|
id: seriesId,
|
|
itemId: seriesId,
|
|
seriesId,
|
|
enabled: visible,
|
|
label: { text: legendItemName ?? title ?? idName ?? idKey },
|
|
symbol: this.legendItemSymbol(),
|
|
legendItemName,
|
|
hideInLegend: !showInLegend
|
|
};
|
|
return [legendDatum];
|
|
} else {
|
|
return [];
|
|
}
|
|
}
|
|
getTooltipContent(datumIndex) {
|
|
const {
|
|
id: seriesId,
|
|
dataModel,
|
|
processedData,
|
|
properties,
|
|
ctx: { formatManager }
|
|
} = this;
|
|
const { idKey, idName, colorKey, colorName, labelKey, labelName, legendItemName, title, tooltip } = properties;
|
|
if (!dataModel || !processedData)
|
|
return;
|
|
const datum = processedData.dataSources.get(this.id)?.data[datumIndex];
|
|
const idValue = dataModel.resolveColumnById(this, `idValue`, processedData)[datumIndex];
|
|
const colorValue = colorKey == null ? void 0 : dataModel.resolveColumnById(this, `colorValue`, processedData)[datumIndex];
|
|
if (colorKey != null && colorValue == null) {
|
|
return;
|
|
}
|
|
const data = [];
|
|
if (this.isLabelEnabled() && labelKey != null && labelKey !== idKey) {
|
|
const labelValue = dataModel.resolveColumnById(this, `labelValue`, processedData)[datumIndex];
|
|
const content = formatManager.format(this.callWithContext.bind(this), {
|
|
type: "category",
|
|
value: labelValue,
|
|
datum,
|
|
seriesId,
|
|
legendItemName,
|
|
key: labelKey,
|
|
source: "tooltip",
|
|
property: "label",
|
|
domain: [],
|
|
boundSeries: this.getFormatterContext("label")
|
|
});
|
|
data.push({ label: labelName, fallbackLabel: labelKey, value: content ?? labelValue });
|
|
}
|
|
if (colorValue != null) {
|
|
const domain = dataModel.getDomain(this, `colorValue`, "value", processedData).domain;
|
|
const content = formatManager.format(this.callWithContext.bind(this), {
|
|
type: "number",
|
|
value: colorValue,
|
|
datum,
|
|
seriesId,
|
|
legendItemName,
|
|
key: colorKey,
|
|
source: "tooltip",
|
|
property: "color",
|
|
domain,
|
|
boundSeries: this.getFormatterContext("color"),
|
|
fractionDigits: void 0,
|
|
visibleDomain: void 0
|
|
});
|
|
data.push({ label: colorName, fallbackLabel: colorKey, value: content ?? String(colorValue) });
|
|
}
|
|
const format = this.getItemStyle({ datum, datumIndex, colorValue }, false);
|
|
return this.formatTooltipWithContext(
|
|
tooltip,
|
|
{
|
|
heading: idValue,
|
|
title: title ?? legendItemName,
|
|
symbol: this.legendItemSymbol(datumIndex),
|
|
data
|
|
},
|
|
{ seriesId, datum, title, idKey, idName, colorKey, colorName, labelKey, labelName, ...format }
|
|
);
|
|
}
|
|
computeFocusBounds(opts) {
|
|
return findFocusedGeoGeometry(this, opts);
|
|
}
|
|
hasItemStylers() {
|
|
return this.properties.itemStyler != null || this.properties.label.itemStyler != null;
|
|
}
|
|
};
|
|
MapShapeSeries.className = "MapShapeSeries";
|
|
MapShapeSeries.type = "map-shape";
|
|
|
|
// packages/ag-charts-enterprise/src/series/map-shape/mapShapeSeriesOptionsDef.ts
|
|
import { _ModuleSupport as _ModuleSupport173 } from "ag-charts-community";
|
|
import {
|
|
commonSeriesOptionsDefs as commonSeriesOptionsDefs13,
|
|
constant as constant14,
|
|
geoJson as geoJson4,
|
|
required as required14,
|
|
string as string15,
|
|
without as without8
|
|
} from "ag-charts-core";
|
|
var { mapShapeSeriesThemeableOptionsDef } = _ModuleSupport173;
|
|
var mapShapeSeriesOptionsDef = {
|
|
...without8(commonSeriesOptionsDefs13, ["highlightStyle", "highlight"]),
|
|
...mapShapeSeriesThemeableOptionsDef,
|
|
type: required14(constant14("map-shape")),
|
|
idKey: required14(string15),
|
|
colorKey: string15,
|
|
labelKey: string15,
|
|
idName: string15,
|
|
colorName: string15,
|
|
labelName: string15,
|
|
topology: geoJson4,
|
|
topologyIdKey: string15,
|
|
legendItemName: string15,
|
|
title: string15
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/series/map-shape/mapShapeModule.ts
|
|
var MapShapeSeriesModule = {
|
|
type: "series",
|
|
name: "map-shape",
|
|
chartType: "topology",
|
|
enterprise: true,
|
|
version: VERSION39,
|
|
dependencies: [TopologyChartModule],
|
|
options: mapShapeSeriesOptionsDef,
|
|
themeTemplate: {
|
|
...MAP_THEME_DEFAULTS,
|
|
series: {
|
|
fill: applyMapPalette({
|
|
$applySwitch: [
|
|
{ $path: "type" },
|
|
{ $mapPalette: "fill" },
|
|
["gradient", FILL_GRADIENT_LINEAR_DEFAULTS5],
|
|
["image", FILL_IMAGE_DEFAULTS10],
|
|
["pattern", FILL_PATTERN_DEFAULTS6]
|
|
]
|
|
}),
|
|
stroke: { $ref: "chartBackgroundColor" },
|
|
colorRange: {
|
|
$if: [
|
|
{ $eq: [{ $mapPalette: "type" }, "inbuilt"] },
|
|
{ $mapPalette: "divergingColors" },
|
|
applyMapPalette(SAFE_RANGE2_OPERATION6)
|
|
]
|
|
},
|
|
fillOpacity: 1,
|
|
strokeWidth: 1,
|
|
lineDash: [0],
|
|
lineDashOffset: 0,
|
|
padding: 2,
|
|
label: {
|
|
...LABEL_BOXING_DEFAULTS11,
|
|
enabled: true,
|
|
color: { $ref: "chartBackgroundColor" },
|
|
fontFamily: { $ref: "fontFamily" },
|
|
fontSize: { $ref: "fontSize" },
|
|
fontWeight: "bold",
|
|
overflowStrategy: "hide"
|
|
},
|
|
highlight: applyMapPalette(MULTI_SERIES_HIGHLIGHT_STYLE6)
|
|
},
|
|
tooltip: {
|
|
range: "exact"
|
|
}
|
|
},
|
|
create: (ctx) => new MapShapeSeries(ctx)
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/series/map-shape-background/mapShapeBackgroundModule.ts
|
|
import { VERSION as VERSION40 } from "ag-charts-community";
|
|
import {
|
|
FILL_GRADIENT_LINEAR_HIERARCHY_DEFAULTS,
|
|
FILL_IMAGE_DEFAULTS as FILL_IMAGE_DEFAULTS11,
|
|
FILL_PATTERN_HIERARCHY_DEFAULTS
|
|
} from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/series/map-shape-background/mapShapeBackgroundSeries.ts
|
|
import { _ModuleSupport as _ModuleSupport175 } from "ag-charts-community";
|
|
import { Logger as Logger21 } from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/series/map-shape-background/mapShapeBackgroundSeriesProperties.ts
|
|
import { _ModuleSupport as _ModuleSupport174 } from "ag-charts-community";
|
|
import { Property as Property79 } from "ag-charts-core";
|
|
var { SeriesProperties: SeriesProperties7, makeSeriesTooltip: makeSeriesTooltip16 } = _ModuleSupport174;
|
|
var MapShapeBackgroundSeriesProperties = class extends SeriesProperties7 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.topology = void 0;
|
|
this.fill = "black";
|
|
this.fillOpacity = 1;
|
|
this.stroke = "black";
|
|
this.strokeOpacity = 1;
|
|
this.strokeWidth = 0;
|
|
this.lineDash = [0];
|
|
this.lineDashOffset = 0;
|
|
this.tooltip = makeSeriesTooltip16();
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property79
|
|
], MapShapeBackgroundSeriesProperties.prototype, "topology", 2);
|
|
__decorateClass([
|
|
Property79
|
|
], MapShapeBackgroundSeriesProperties.prototype, "fill", 2);
|
|
__decorateClass([
|
|
Property79
|
|
], MapShapeBackgroundSeriesProperties.prototype, "fillOpacity", 2);
|
|
__decorateClass([
|
|
Property79
|
|
], MapShapeBackgroundSeriesProperties.prototype, "stroke", 2);
|
|
__decorateClass([
|
|
Property79
|
|
], MapShapeBackgroundSeriesProperties.prototype, "strokeOpacity", 2);
|
|
__decorateClass([
|
|
Property79
|
|
], MapShapeBackgroundSeriesProperties.prototype, "strokeWidth", 2);
|
|
__decorateClass([
|
|
Property79
|
|
], MapShapeBackgroundSeriesProperties.prototype, "lineDash", 2);
|
|
__decorateClass([
|
|
Property79
|
|
], MapShapeBackgroundSeriesProperties.prototype, "lineDashOffset", 2);
|
|
__decorateClass([
|
|
Property79
|
|
], MapShapeBackgroundSeriesProperties.prototype, "tooltip", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/series/map-shape-background/mapShapeBackgroundSeries.ts
|
|
var { createDatumId: createDatumId15, Selection: Selection12, Group: Group16, PointerEvents: PointerEvents8 } = _ModuleSupport175;
|
|
var MapShapeBackgroundSeries = class extends TopologySeries {
|
|
constructor(moduleCtx) {
|
|
super({
|
|
moduleCtx,
|
|
categoryKey: void 0,
|
|
pickModes: []
|
|
});
|
|
this.properties = new MapShapeBackgroundSeriesProperties();
|
|
this._chartTopology = void 0;
|
|
this.itemGroup = this.contentGroup.appendChild(new Group16({ name: "itemGroup" }));
|
|
this.datumSelection = Selection12.select(
|
|
this.itemGroup,
|
|
() => this.nodeFactory()
|
|
);
|
|
this.itemGroup.pointerEvents = PointerEvents8.None;
|
|
}
|
|
get topology() {
|
|
return this.properties.topology ?? this._chartTopology;
|
|
}
|
|
get focusable() {
|
|
return false;
|
|
}
|
|
setOptionsData() {
|
|
}
|
|
setChartData() {
|
|
}
|
|
getNodeData() {
|
|
return;
|
|
}
|
|
get hasData() {
|
|
return false;
|
|
}
|
|
renderToOffscreenCanvas() {
|
|
return true;
|
|
}
|
|
setChartTopology(topology) {
|
|
this._chartTopology = topology;
|
|
if (this.topology === topology) {
|
|
this.nodeDataRefresh = true;
|
|
}
|
|
}
|
|
setZIndex(zIndex) {
|
|
super.setZIndex(zIndex);
|
|
this.contentGroup.zIndex = [0 /* ShapeLineBackground */, zIndex, 0];
|
|
this.highlightGroup.zIndex = [0 /* ShapeLineBackground */, zIndex, 1];
|
|
return true;
|
|
}
|
|
nodeFactory() {
|
|
const geoGeometry = new GeoGeometry();
|
|
geoGeometry.renderMode = 1 /* Polygons */;
|
|
geoGeometry.lineJoin = "round";
|
|
geoGeometry.pointerEvents = PointerEvents8.None;
|
|
return geoGeometry;
|
|
}
|
|
processData() {
|
|
const { topology } = this;
|
|
this.topologyBounds = topology?.features.reduce((current, feature) => {
|
|
const geometry = feature.geometry;
|
|
if (geometry == null)
|
|
return current;
|
|
return geometryBbox(geometry, current);
|
|
}, void 0);
|
|
if (topology == null) {
|
|
Logger21.warnOnce(`no topology was provided for [MapShapeBackgroundSeries]; nothing will be rendered.`);
|
|
}
|
|
}
|
|
createNodeData() {
|
|
const { id: seriesId, topology, scale, properties } = this;
|
|
if (topology == null)
|
|
return;
|
|
const { fill, fillOpacity, stroke: stroke3, strokeWidth, strokeOpacity, lineDash, lineDashOffset } = properties;
|
|
const nodeData = [];
|
|
const labelData = [];
|
|
for (const [index, feature] of topology.features.entries()) {
|
|
const { geometry } = feature;
|
|
const projectedGeometry = geometry != null && scale != null ? projectGeometry(geometry, scale) : void 0;
|
|
if (projectedGeometry == null)
|
|
continue;
|
|
nodeData.push({
|
|
series: this,
|
|
datum: feature,
|
|
datumIndex: 0,
|
|
index,
|
|
projectedGeometry,
|
|
style: { fill, fillOpacity, stroke: stroke3, strokeWidth, strokeOpacity, lineDash, lineDashOffset }
|
|
});
|
|
}
|
|
return {
|
|
itemId: seriesId,
|
|
nodeData,
|
|
labelData
|
|
};
|
|
}
|
|
updateSelections() {
|
|
if (this.nodeDataRefresh) {
|
|
this.contextNodeData = this.createNodeData();
|
|
this.nodeDataRefresh = false;
|
|
}
|
|
}
|
|
update() {
|
|
const { datumSelection } = this;
|
|
this.updateSelections();
|
|
this.contentGroup.visible = this.visible;
|
|
this.labelGroup.visible = this.visible;
|
|
const { nodeData = [] } = this.contextNodeData ?? {};
|
|
this.datumSelection = this.updateDatumSelection({ nodeData, datumSelection });
|
|
this.updateDatumNodes({ datumSelection });
|
|
}
|
|
updateDatumSelection(opts) {
|
|
return opts.datumSelection.update(opts.nodeData, void 0, (datum) => createDatumId15(datum.index));
|
|
}
|
|
updateDatumNodes(opts) {
|
|
const { datumSelection } = opts;
|
|
datumSelection.each((geoGeometry, datum) => {
|
|
const { projectedGeometry } = datum;
|
|
if (projectedGeometry == null) {
|
|
geoGeometry.visible = false;
|
|
geoGeometry.projectedGeometry = void 0;
|
|
return;
|
|
}
|
|
geoGeometry.visible = true;
|
|
geoGeometry.projectedGeometry = projectedGeometry;
|
|
geoGeometry.setProperties(datum.style);
|
|
});
|
|
}
|
|
resetAnimation() {
|
|
}
|
|
getLegendData() {
|
|
return [];
|
|
}
|
|
getTooltipContent(_seriesDatum) {
|
|
return;
|
|
}
|
|
pickFocus() {
|
|
return void 0;
|
|
}
|
|
computeFocusBounds(_opts) {
|
|
return void 0;
|
|
}
|
|
hasItemStylers() {
|
|
return false;
|
|
}
|
|
};
|
|
MapShapeBackgroundSeries.className = "MapShapeBackgroundSeries";
|
|
MapShapeBackgroundSeries.type = "map-shape-background";
|
|
|
|
// packages/ag-charts-enterprise/src/series/map-shape-background/mapShapeBackgroundSeriesOptionsDef.ts
|
|
import { _ModuleSupport as _ModuleSupport176 } from "ag-charts-community";
|
|
import { commonSeriesOptionsDefs as commonSeriesOptionsDefs14, constant as constant15, geoJson as geoJson5, required as required15 } from "ag-charts-core";
|
|
var { mapShapeBackgroundSeriesThemeableOptionsDef } = _ModuleSupport176;
|
|
var mapShapeBackgroundSeriesOptionsDef = {
|
|
...mapShapeBackgroundSeriesThemeableOptionsDef,
|
|
...commonSeriesOptionsDefs14,
|
|
type: required15(constant15("map-shape-background")),
|
|
topology: geoJson5
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/series/map-shape-background/mapShapeBackgroundModule.ts
|
|
var MapShapeBackgroundSeriesModule = {
|
|
type: "series",
|
|
name: "map-shape-background",
|
|
chartType: "topology",
|
|
enterprise: true,
|
|
version: VERSION40,
|
|
dependencies: [TopologyChartModule],
|
|
options: mapShapeBackgroundSeriesOptionsDef,
|
|
themeTemplate: {
|
|
...MAP_THEME_DEFAULTS,
|
|
series: {
|
|
fill: applyMapPalette({
|
|
$applySwitch: [
|
|
{ $path: "type" },
|
|
{ $path: ["/1", { $mapPalette: "fill" }, { $mapPalette: "hierarchyColors" }] },
|
|
["gradient", FILL_GRADIENT_LINEAR_HIERARCHY_DEFAULTS],
|
|
["image", FILL_IMAGE_DEFAULTS11],
|
|
["pattern", FILL_PATTERN_HIERARCHY_DEFAULTS]
|
|
]
|
|
}),
|
|
stroke: { $ref: "chartBackgroundColor" },
|
|
strokeWidth: 1
|
|
}
|
|
},
|
|
create: (ctx) => new MapShapeBackgroundSeries(ctx)
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/series/nightingale/nightingaleModule.ts
|
|
import { PolarChartModule, VERSION as VERSION41 } from "ag-charts-community";
|
|
import { ChartAxisDirection as ChartAxisDirection46, POLAR_AXIS_TYPE as POLAR_AXIS_TYPE2 } from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/series/nightingale/nightingaleSeries.ts
|
|
import { _ModuleSupport as _ModuleSupport182 } from "ag-charts-community";
|
|
import { PolarZIndexMap } from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/series/radial-column/radialColumnSeriesBase.ts
|
|
import { _ModuleSupport as _ModuleSupport178 } from "ag-charts-community";
|
|
import {
|
|
ChartAxisDirection as ChartAxisDirection45,
|
|
isDefined as isDefined3,
|
|
isGradientFill as isGradientFill2,
|
|
normalizeAngle360 as normalizeAngle3605
|
|
} from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/series/util/radialUtil.ts
|
|
import { _ModuleSupport as _ModuleSupport177 } from "ag-charts-community";
|
|
import { mergeDefaults as mergeDefaults17 } from "ag-charts-core";
|
|
var { createDatumId: createDatumId16, toHighlightString: toHighlightString4 } = _ModuleSupport177;
|
|
function makeStylerParams(series, highlightStateEnum) {
|
|
const { id: seriesId } = series;
|
|
const {
|
|
angleKey,
|
|
cornerRadius,
|
|
fill,
|
|
fillOpacity,
|
|
lineDash,
|
|
lineDashOffset,
|
|
radiusKey,
|
|
stackGroup,
|
|
stroke: stroke3,
|
|
strokeOpacity,
|
|
strokeWidth
|
|
} = series.properties;
|
|
const highlightState = toHighlightString4(highlightStateEnum ?? _ModuleSupport177.HighlightState.None);
|
|
return {
|
|
angleKey,
|
|
cornerRadius,
|
|
fill,
|
|
fillOpacity,
|
|
highlightState,
|
|
lineDash,
|
|
lineDashOffset,
|
|
radiusKey,
|
|
seriesId,
|
|
stackGroup,
|
|
stroke: stroke3,
|
|
strokeOpacity,
|
|
strokeWidth
|
|
};
|
|
}
|
|
function getStyle(series, ignoreStylerCallback, highlightState) {
|
|
const { styler } = series.properties;
|
|
let stylerResult = {};
|
|
if (!ignoreStylerCallback && styler) {
|
|
const stylerParams = makeStylerParams(series, highlightState);
|
|
stylerResult = series.ctx.optionsGraphService.resolvePartial(
|
|
["series", `${series.declarationOrder}`],
|
|
series.cachedCallWithContext(styler, stylerParams) ?? {},
|
|
{ pick: false }
|
|
) ?? {};
|
|
}
|
|
return {
|
|
cornerRadius: stylerResult.cornerRadius ?? series.properties.cornerRadius,
|
|
fill: stylerResult.fill ?? series.properties.fill,
|
|
fillOpacity: stylerResult.fillOpacity ?? series.properties.fillOpacity,
|
|
lineDash: stylerResult.lineDash ?? series.properties.lineDash,
|
|
lineDashOffset: stylerResult.lineDashOffset ?? series.properties.lineDashOffset,
|
|
stroke: stylerResult.stroke ?? series.properties.stroke,
|
|
strokeOpacity: stylerResult.strokeOpacity ?? series.properties.strokeOpacity,
|
|
strokeWidth: stylerResult.strokeWidth ?? series.properties.strokeWidth,
|
|
opacity: 1
|
|
};
|
|
}
|
|
function makeItemStylerParams(series, nodeDatum, isHighlight, style) {
|
|
const { id: seriesId, properties } = series;
|
|
const { angleKey, radiusKey } = properties;
|
|
const activeHighlight = series.ctx.highlightManager?.getActiveHighlight();
|
|
const highlightStateString = series.getHighlightStateString(activeHighlight, isHighlight, nodeDatum.datumIndex);
|
|
const fill = series.filterItemStylerFillParams(style.fill) ?? style.fill;
|
|
return {
|
|
seriesId,
|
|
datum: nodeDatum.datum,
|
|
highlightState: highlightStateString,
|
|
angleKey,
|
|
radiusKey,
|
|
...style,
|
|
fill
|
|
};
|
|
}
|
|
function getItemStyle(series, nodeDatum, isHighlight, highlightState) {
|
|
const { properties } = series;
|
|
const { itemStyler } = properties;
|
|
const highlightStyle = series.getHighlightStyle(isHighlight, nodeDatum?.datumIndex, highlightState);
|
|
const baseStyle = mergeDefaults17(highlightStyle, getStyle(series, nodeDatum === void 0, highlightState));
|
|
let style = baseStyle;
|
|
if (itemStyler != null && nodeDatum != null) {
|
|
const overrides = series.cachedDatumCallback(
|
|
createDatumId16(series.getDatumId(nodeDatum), isHighlight ? "highlight" : "node"),
|
|
() => {
|
|
const params = makeItemStylerParams(series, nodeDatum, isHighlight, style);
|
|
return series.callWithContext(itemStyler, params);
|
|
}
|
|
);
|
|
if (overrides) {
|
|
style = mergeDefaults17(overrides, style);
|
|
}
|
|
}
|
|
return style;
|
|
}
|
|
|
|
// packages/ag-charts-enterprise/src/series/radial-column/radialColumnSeriesBase.ts
|
|
var {
|
|
DEFAULT_POLAR_DIRECTION_KEYS,
|
|
DEFAULT_POLAR_DIRECTION_NAMES,
|
|
PolarAxis,
|
|
diff: diff6,
|
|
fixNumericExtent: fixNumericExtent8,
|
|
groupAccumulativeValueProperty: groupAccumulativeValueProperty2,
|
|
keyProperty: keyProperty9,
|
|
normaliseGroupTo,
|
|
resetLabelFn: resetLabelFn5,
|
|
seriesLabelFadeInAnimation: seriesLabelFadeInAnimation5,
|
|
seriesLabelFadeOutAnimation,
|
|
valueProperty: valueProperty14,
|
|
animationValidation: animationValidation7,
|
|
createDatumId: createDatumId17,
|
|
SeriesNodePickMode: SeriesNodePickMode12,
|
|
CategoryScale: CategoryScale3,
|
|
motion: motion6,
|
|
updateLabelNode: updateLabelNode6,
|
|
getItemStyles: getItemStyles3
|
|
} = _ModuleSupport178;
|
|
var RadialColumnSeriesNodeEvent = class extends _ModuleSupport178.SeriesNodeEvent {
|
|
constructor(type, nativeEvent, datum, series) {
|
|
super(type, nativeEvent, datum, series);
|
|
this.angleKey = series.properties.angleKey;
|
|
this.radiusKey = series.properties.radiusKey;
|
|
}
|
|
};
|
|
var RadialColumnSeriesBase = class extends _ModuleSupport178.PolarSeries {
|
|
constructor(moduleCtx, {
|
|
animationResetFns
|
|
}) {
|
|
super({
|
|
moduleCtx,
|
|
categoryKey: "angleValue",
|
|
propertyKeys: DEFAULT_POLAR_DIRECTION_KEYS,
|
|
propertyNames: DEFAULT_POLAR_DIRECTION_NAMES,
|
|
canHaveAxes: true,
|
|
pickModes: [SeriesNodePickMode12.NEAREST_NODE, SeriesNodePickMode12.EXACT_SHAPE_MATCH],
|
|
animationResetFns: {
|
|
...animationResetFns,
|
|
label: resetLabelFn5
|
|
}
|
|
});
|
|
this.NodeEvent = RadialColumnSeriesNodeEvent;
|
|
this.groupScale = new CategoryScale3();
|
|
this.circleCache = { r: 0, cx: 0, cy: 0 };
|
|
}
|
|
getSeriesDomain(direction) {
|
|
const { dataModel, processedData } = this;
|
|
if (!processedData || !dataModel)
|
|
return { domain: [] };
|
|
if (direction === ChartAxisDirection45.Angle) {
|
|
return dataModel.getDomain(this, "angleValue", "key", processedData);
|
|
} else {
|
|
const yExtent = dataModel.getDomain(this, "radiusValue-end", "value", processedData).domain;
|
|
const fixedYExtent = Number.isFinite(yExtent[1] - yExtent[0]) ? [Math.min(yExtent[0], 0), Math.max(yExtent[1], 0)] : [];
|
|
return { domain: fixNumericExtent8(fixedYExtent) };
|
|
}
|
|
}
|
|
async processData(dataController) {
|
|
const { angleKey, radiusKey, normalizedTo } = this.properties;
|
|
const animationEnabled = !this.ctx.animationManager.isSkipped();
|
|
const stackGroupId = this.getStackId();
|
|
const stackGroupTrailingId = `${stackGroupId}-trailing`;
|
|
const extraProps = [];
|
|
if (isDefined3(normalizedTo)) {
|
|
extraProps.push(normaliseGroupTo([stackGroupId, stackGroupTrailingId], Math.abs(normalizedTo)));
|
|
}
|
|
if (this.needsDataModelDiff() && this.processedData) {
|
|
extraProps.push(diff6(this.id, this.processedData));
|
|
}
|
|
if (animationEnabled) {
|
|
extraProps.push(animationValidation7());
|
|
}
|
|
const visibleProps = this.visible ? {} : { forceValue: 0 };
|
|
const radiusScaleType = this.axes[ChartAxisDirection45.Radius]?.scale.type;
|
|
const angleScaleType = this.axes[ChartAxisDirection45.Angle]?.scale.type;
|
|
const allowNullKey = this.properties.allowNullKeys ?? false;
|
|
await this.requestDataModel(dataController, this.data, {
|
|
props: [
|
|
keyProperty9(angleKey, angleScaleType, { id: "angleValue", allowNullKey }),
|
|
valueProperty14(radiusKey, radiusScaleType, {
|
|
id: "radiusValue-raw",
|
|
invalidValue: null,
|
|
...visibleProps
|
|
}),
|
|
...groupAccumulativeValueProperty2(
|
|
radiusKey,
|
|
"normal",
|
|
{
|
|
id: `radiusValue-end`,
|
|
rangeId: `radiusValue-range`,
|
|
invalidValue: null,
|
|
groupId: stackGroupId,
|
|
separateNegative: true,
|
|
...visibleProps
|
|
},
|
|
radiusScaleType
|
|
),
|
|
...groupAccumulativeValueProperty2(
|
|
radiusKey,
|
|
"trailing",
|
|
{
|
|
id: `radiusValue-start`,
|
|
invalidValue: null,
|
|
groupId: stackGroupTrailingId,
|
|
separateNegative: true,
|
|
...visibleProps
|
|
},
|
|
radiusScaleType
|
|
),
|
|
...extraProps
|
|
],
|
|
groupByKeys: true,
|
|
groupByData: false
|
|
});
|
|
this.animationState.transition("updateData");
|
|
}
|
|
didCircleChange() {
|
|
const r = this.radius;
|
|
const cx = this.centerX;
|
|
const cy = this.centerY;
|
|
const cache = this.circleCache;
|
|
if (r !== cache.r || cx !== cache.cx || cy !== cache.cy) {
|
|
this.circleCache = { r, cx, cy };
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
isRadiusAxisReversed() {
|
|
return this.axes[ChartAxisDirection45.Radius]?.isReversed();
|
|
}
|
|
maybeRefreshNodeData() {
|
|
const circleChanged = this.didCircleChange();
|
|
if (!circleChanged && !this.nodeDataRefresh)
|
|
return;
|
|
this.contextNodeData = this.createNodeData();
|
|
this.nodeData = this.contextNodeData?.nodeData ?? [];
|
|
this.nodeDataRefresh = false;
|
|
}
|
|
getAxisInnerRadius() {
|
|
const radiusAxis = this.axes[ChartAxisDirection45.Radius];
|
|
return radiusAxis instanceof PolarAxis ? this.radius * radiusAxis.innerRadiusRatio : 0;
|
|
}
|
|
createNodeData() {
|
|
const { processedData, dataModel, groupScale } = this;
|
|
if (!dataModel || processedData?.type !== "grouped")
|
|
return;
|
|
const angleAxis = this.axes[ChartAxisDirection45.Angle];
|
|
const radiusAxis = this.axes[ChartAxisDirection45.Radius];
|
|
const angleScale = angleAxis?.scale;
|
|
const radiusScale = radiusAxis?.scale;
|
|
if (!angleScale || !radiusScale) {
|
|
return;
|
|
}
|
|
const angleValues = dataModel.resolveKeysById(this, `angleValue`, processedData);
|
|
const radiusStartValues = dataModel.resolveColumnById(this, `radiusValue-start`, processedData);
|
|
const radiusEndValues = dataModel.resolveColumnById(this, `radiusValue-end`, processedData);
|
|
const radiusRawValues = dataModel.resolveColumnById(this, `radiusValue-raw`, processedData);
|
|
let groupPaddingInner = 0;
|
|
let groupPaddingOuter = 0;
|
|
if (angleAxis instanceof AngleCategoryAxis) {
|
|
groupPaddingInner = angleAxis.groupPaddingInner;
|
|
groupPaddingOuter = angleAxis.paddingInner;
|
|
}
|
|
const groupAngleStep = angleScale.bandwidth ?? 0;
|
|
const paddedGroupAngleStep = groupAngleStep * (1 - groupPaddingOuter);
|
|
const { index: groupIndex, visibleGroupCount } = this.ctx.seriesStateManager.getVisiblePeerGroupIndex(this);
|
|
groupScale.domain = Array.from({ length: visibleGroupCount }).map((_, i) => String(i));
|
|
groupScale.range = [-paddedGroupAngleStep / 2, paddedGroupAngleStep / 2];
|
|
groupScale.paddingInner = visibleGroupCount > 1 ? groupPaddingInner : 0;
|
|
const radiusAxisReversed = this.isRadiusAxisReversed();
|
|
const axisInnerRadius = this.getAxisInnerRadius();
|
|
const axisOuterRadius = this.radius;
|
|
const axisTotalRadius = axisOuterRadius + axisInnerRadius;
|
|
const { angleKey, radiusKey, angleName, radiusName, legendItemName, label } = this.properties;
|
|
const radiusDomain = this.getSeriesDomain(ChartAxisDirection45.Radius).domain;
|
|
const getLabelNodeDatum = (datum, radiusDatum, x, y) => {
|
|
const labelText = this.getLabelText(
|
|
radiusDatum,
|
|
datum,
|
|
radiusKey,
|
|
"radius",
|
|
radiusDomain,
|
|
label,
|
|
{ value: radiusDatum, datum, angleKey, radiusKey, angleName, radiusName, legendItemName }
|
|
);
|
|
if (labelText) {
|
|
return { x, y, text: labelText, textAlign: "center", textBaseline: "middle" };
|
|
}
|
|
};
|
|
const nodeData = [];
|
|
const styles = getItemStyles3(
|
|
(nodeDatum, isHighlight, highlightState) => getItemStyle(this, nodeDatum, isHighlight, highlightState)
|
|
);
|
|
const context = {
|
|
itemId: radiusKey,
|
|
nodeData,
|
|
labelData: nodeData,
|
|
styles
|
|
};
|
|
if (!this.visible)
|
|
return context;
|
|
const { dataSources } = processedData;
|
|
const rawData = dataSources.get(this.id)?.data ?? [];
|
|
for (const { datumIndex } of dataModel.forEachGroupDatum(this, processedData)) {
|
|
const datum = rawData[datumIndex];
|
|
const angleDatum = angleValues[datumIndex];
|
|
if (angleDatum === void 0 && !this.properties.allowNullKeys)
|
|
return;
|
|
const radiusDatum = radiusRawValues[datumIndex];
|
|
const isPositive = radiusDatum >= 0 && !Object.is(radiusDatum, -0);
|
|
const innerRadiusDatum = radiusStartValues[datumIndex];
|
|
const outerRadiusDatum = radiusEndValues[datumIndex];
|
|
const negative = isPositive === radiusAxisReversed;
|
|
if (innerRadiusDatum === void 0 || outerRadiusDatum === void 0)
|
|
return;
|
|
let startAngle;
|
|
let endAngle;
|
|
let angle;
|
|
if (rawData.length === 1) {
|
|
startAngle = -0.5 * Math.PI;
|
|
endAngle = 1.5 * Math.PI;
|
|
angle = startAngle;
|
|
} else {
|
|
const groupAngle = angleScale.convert(angleDatum);
|
|
startAngle = normalizeAngle3605(groupAngle + groupScale.convert(String(groupIndex)));
|
|
endAngle = normalizeAngle3605(startAngle + groupScale.bandwidth);
|
|
angle = startAngle + groupScale.bandwidth / 2;
|
|
}
|
|
const innerRadius = axisTotalRadius - radiusScale.convert(innerRadiusDatum);
|
|
const outerRadius = axisTotalRadius - radiusScale.convert(outerRadiusDatum);
|
|
const midRadius = (innerRadius + outerRadius) / 2;
|
|
const x = Math.cos(angle) * midRadius;
|
|
const y = Math.sin(angle) * midRadius;
|
|
const labelNodeDatum = this.properties.label.enabled ? getLabelNodeDatum(datum, radiusDatum, x, y) : void 0;
|
|
const columnWidth = this.getColumnWidth(startAngle, endAngle);
|
|
nodeData.push({
|
|
series: this,
|
|
datum,
|
|
datumIndex,
|
|
point: { x, y, size: 0 },
|
|
midPoint: { x, y },
|
|
label: labelNodeDatum,
|
|
angleValue: angleDatum,
|
|
radiusValue: radiusDatum,
|
|
negative,
|
|
innerRadius,
|
|
outerRadius,
|
|
stackInnerRadius: innerRadius,
|
|
stackOuterRadius: outerRadius,
|
|
startAngle,
|
|
endAngle,
|
|
midAngle: angle,
|
|
axisInnerRadius,
|
|
axisOuterRadius,
|
|
columnWidth,
|
|
index: datumIndex
|
|
});
|
|
}
|
|
return {
|
|
itemId: radiusKey,
|
|
nodeData,
|
|
labelData: nodeData,
|
|
styles
|
|
};
|
|
}
|
|
getColumnWidth(_startAngle, _endAngle) {
|
|
return Number.NaN;
|
|
}
|
|
update({ seriesRect }) {
|
|
const resize = this.checkResize(seriesRect);
|
|
this.maybeRefreshNodeData();
|
|
this.contentGroup.translationX = this.centerX;
|
|
this.contentGroup.translationY = this.centerY;
|
|
this.highlightGroup.translationX = this.centerX;
|
|
this.highlightGroup.translationY = this.centerY;
|
|
if (this.labelGroup) {
|
|
this.labelGroup.translationX = this.centerX;
|
|
this.labelGroup.translationY = this.centerY;
|
|
}
|
|
this.updateSectorSelection(this.itemSelection, false);
|
|
this.updateSectorSelection(this.highlightSelection, true);
|
|
this.updateLabels();
|
|
if (resize) {
|
|
this.animationState.transition("resize");
|
|
}
|
|
this.animationState.transition("update");
|
|
}
|
|
updateSectorSelection(selection, isHighlight) {
|
|
const { contextNodeData } = this;
|
|
if (!contextNodeData) {
|
|
return;
|
|
}
|
|
const highlightedDatum = this.ctx.highlightManager.getActiveHighlight();
|
|
let selectionData = [];
|
|
const activeHighlight = this.ctx.highlightManager?.getActiveHighlight();
|
|
if (isHighlight) {
|
|
if (activeHighlight?.datum && activeHighlight.series === this) {
|
|
selectionData.push(activeHighlight);
|
|
}
|
|
} else {
|
|
selectionData = this.nodeData;
|
|
}
|
|
const radiusAxisReversed = this.isRadiusAxisReversed();
|
|
const axisInnerRadius = radiusAxisReversed ? this.radius : this.getAxisInnerRadius();
|
|
const axisOuterRadius = radiusAxisReversed ? this.getAxisInnerRadius() : this.radius;
|
|
const fillBBox = this.getShapeFillBBox();
|
|
const hasItemStylers = this.hasItemStylers();
|
|
selection.update(selectionData, void 0, (datum) => this.getDatumId(datum)).each((node, nodeDatum) => {
|
|
const { midPoint } = nodeDatum;
|
|
if (hasItemStylers) {
|
|
const highlightState = this.getHighlightState(activeHighlight, isHighlight, nodeDatum.datumIndex);
|
|
nodeDatum.style = getItemStyle(this, nodeDatum, isHighlight, highlightState);
|
|
}
|
|
const style = nodeDatum.style ?? contextNodeData.styles[this.getHighlightState(highlightedDatum, isHighlight, nodeDatum.datumIndex)];
|
|
const fill = style.fill;
|
|
const itemBounds = isGradientFill2(fill) && fill.bounds === "item";
|
|
const fillParams = itemBounds ? { centerX: midPoint?.x ?? 0, centerY: midPoint?.y ?? 0 } : { centerX: 0, centerY: 0, innerRadius: axisInnerRadius, outerRadius: axisOuterRadius };
|
|
this.updateItemPath(node, nodeDatum, isHighlight);
|
|
node.setStyleProperties(style, fillBBox, fillParams);
|
|
node.cornerRadius = style.cornerRadius ?? 0;
|
|
node.lineJoin = "round";
|
|
});
|
|
}
|
|
updateLabels() {
|
|
const activeHighlight = this.ctx.highlightManager?.getActiveHighlight();
|
|
const highlightDatum = activeHighlight?.series === this && activeHighlight?.datum ? activeHighlight : void 0;
|
|
const highlightData = highlightDatum ? [highlightDatum] : [];
|
|
this.labelSelection.update(this.nodeData).each((node, datum) => {
|
|
updateLabelNode6(this, node, this.properties, this.properties.label, datum.label, false, activeHighlight);
|
|
node.fillOpacity = this.getHighlightStyle(false, datum.datumIndex).opacity ?? 1;
|
|
});
|
|
this.highlightLabelSelection.update(highlightData, void 0, (datum) => this.getDatumId(datum)).each((node, datum) => {
|
|
updateLabelNode6(this, node, this.properties, this.properties.label, datum.label, true, activeHighlight);
|
|
node.fillOpacity = this.getHighlightStyle(true, datum.datumIndex).opacity ?? 1;
|
|
});
|
|
}
|
|
animateEmptyUpdateReady() {
|
|
const { labelSelection } = this;
|
|
const fns = this.getColumnTransitionFunctions();
|
|
motion6.fromToMotion(this.id, "datums", this.ctx.animationManager, [this.itemSelection], fns);
|
|
seriesLabelFadeInAnimation5(
|
|
this,
|
|
"labels",
|
|
this.ctx.animationManager,
|
|
labelSelection,
|
|
this.highlightLabelSelection
|
|
);
|
|
}
|
|
animateClearingUpdateEmpty() {
|
|
const { itemSelection } = this;
|
|
const { animationManager } = this.ctx;
|
|
const fns = this.getColumnTransitionFunctions();
|
|
motion6.fromToMotion(this.id, "datums", animationManager, [itemSelection], fns);
|
|
seriesLabelFadeOutAnimation(
|
|
this,
|
|
"labels",
|
|
animationManager,
|
|
this.labelSelection,
|
|
this.highlightLabelSelection
|
|
);
|
|
}
|
|
getTooltipContent(datumIndex) {
|
|
const { id: seriesId, dataModel, processedData, axes, properties } = this;
|
|
const { angleKey, angleName, radiusKey, radiusName, legendItemName, tooltip } = properties;
|
|
const angleAxis = axes[ChartAxisDirection45.Angle];
|
|
const radiusAxis = axes[ChartAxisDirection45.Radius];
|
|
const nodeDatum = this.nodeData?.[datumIndex];
|
|
if (!dataModel || !processedData || !angleAxis || !radiusAxis || !nodeDatum)
|
|
return;
|
|
const datum = processedData.dataSources.get(this.id)?.data[datumIndex];
|
|
const angleValue = dataModel.resolveKeysById(this, `angleValue`, processedData)[datumIndex];
|
|
const radiusValue = dataModel.resolveColumnById(this, `radiusValue-raw`, processedData)[datumIndex];
|
|
if (angleValue === void 0 && !this.properties.allowNullKeys)
|
|
return;
|
|
const format = getItemStyle(this, nodeDatum, false);
|
|
return this.formatTooltipWithContext(
|
|
tooltip,
|
|
{
|
|
heading: this.getAxisValueText(angleAxis, "tooltip", angleValue, datum, angleKey, void 0),
|
|
symbol: this.legendItemSymbol(),
|
|
data: [
|
|
{
|
|
label: radiusName,
|
|
fallbackLabel: radiusKey,
|
|
value: this.getAxisValueText(radiusAxis, "tooltip", radiusValue, datum, radiusKey, void 0),
|
|
missing: _ModuleSupport178.isTooltipValueMissing(radiusValue)
|
|
}
|
|
]
|
|
},
|
|
{
|
|
seriesId,
|
|
datum,
|
|
title: angleName,
|
|
angleKey,
|
|
angleName,
|
|
radiusKey,
|
|
radiusName,
|
|
legendItemName,
|
|
...format
|
|
}
|
|
);
|
|
}
|
|
pickNodeClosestDatum(point) {
|
|
return this.pickNodeNearestDistantObject(point, this.itemSelection.nodes());
|
|
}
|
|
legendItemSymbol() {
|
|
const { fill, stroke: stroke3, fillOpacity, strokeOpacity, strokeWidth, lineDash, lineDashOffset } = getStyle(
|
|
this,
|
|
false,
|
|
_ModuleSupport178.HighlightState.None
|
|
);
|
|
const markerStyle = {
|
|
fill: fill ?? "rgba(0, 0, 0, 0)",
|
|
stroke: stroke3 ?? "rgba(0, 0, 0, 0)",
|
|
fillOpacity,
|
|
strokeOpacity,
|
|
strokeWidth,
|
|
lineDash,
|
|
lineDashOffset
|
|
};
|
|
if (isGradientFill2(markerStyle.fill)) {
|
|
markerStyle.fill = { ...markerStyle.fill, gradient: "linear", rotation: 0, reverse: false };
|
|
}
|
|
return {
|
|
marker: markerStyle
|
|
};
|
|
}
|
|
getLegendData(legendType) {
|
|
if (legendType !== "category") {
|
|
return [];
|
|
}
|
|
const { id: seriesId, visible } = this;
|
|
const { radiusKey, radiusName, legendItemName, showInLegend } = this.properties;
|
|
return [
|
|
{
|
|
legendType: "category",
|
|
id: seriesId,
|
|
itemId: radiusKey,
|
|
seriesId,
|
|
enabled: visible,
|
|
label: {
|
|
text: legendItemName ?? radiusName ?? radiusKey
|
|
},
|
|
symbol: this.legendItemSymbol(),
|
|
legendItemName,
|
|
hideInLegend: !showInLegend
|
|
}
|
|
];
|
|
}
|
|
getDatumId(datum) {
|
|
return createDatumId17(datum.angleValue);
|
|
}
|
|
computeLabelsBBox() {
|
|
return null;
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/series/radial-column/radialColumnSeriesBaseProperties.ts
|
|
import { _ModuleSupport as _ModuleSupport179 } from "ag-charts-community";
|
|
import { Property as Property80 } from "ag-charts-core";
|
|
var { SeriesProperties: SeriesProperties8, makeSeriesTooltip: makeSeriesTooltip17, Label: Label12 } = _ModuleSupport179;
|
|
var RadialColumnSeriesBaseProperties = class extends SeriesProperties8 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.angleKeyAxis = "angle";
|
|
this.radiusKeyAxis = "radius";
|
|
this.fill = "black";
|
|
this.fillOpacity = 1;
|
|
this.stroke = "black";
|
|
this.strokeWidth = 1;
|
|
this.strokeOpacity = 1;
|
|
this.lineDash = [0];
|
|
this.lineDashOffset = 0;
|
|
this.cornerRadius = 0;
|
|
this.rotation = 0;
|
|
this.label = new Label12();
|
|
this.tooltip = makeSeriesTooltip17();
|
|
}
|
|
getStyle() {
|
|
const { fill, fillOpacity, stroke: stroke3, strokeWidth, strokeOpacity, lineDash, lineDashOffset, cornerRadius } = this;
|
|
return {
|
|
fill,
|
|
fillOpacity,
|
|
stroke: stroke3,
|
|
strokeWidth,
|
|
strokeOpacity,
|
|
lineDash,
|
|
lineDashOffset,
|
|
cornerRadius,
|
|
opacity: 1
|
|
};
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property80
|
|
], RadialColumnSeriesBaseProperties.prototype, "angleKey", 2);
|
|
__decorateClass([
|
|
Property80
|
|
], RadialColumnSeriesBaseProperties.prototype, "angleName", 2);
|
|
__decorateClass([
|
|
Property80
|
|
], RadialColumnSeriesBaseProperties.prototype, "radiusKey", 2);
|
|
__decorateClass([
|
|
Property80
|
|
], RadialColumnSeriesBaseProperties.prototype, "radiusName", 2);
|
|
__decorateClass([
|
|
Property80
|
|
], RadialColumnSeriesBaseProperties.prototype, "angleKeyAxis", 2);
|
|
__decorateClass([
|
|
Property80
|
|
], RadialColumnSeriesBaseProperties.prototype, "radiusKeyAxis", 2);
|
|
__decorateClass([
|
|
Property80
|
|
], RadialColumnSeriesBaseProperties.prototype, "legendItemName", 2);
|
|
__decorateClass([
|
|
Property80
|
|
], RadialColumnSeriesBaseProperties.prototype, "fill", 2);
|
|
__decorateClass([
|
|
Property80
|
|
], RadialColumnSeriesBaseProperties.prototype, "fillOpacity", 2);
|
|
__decorateClass([
|
|
Property80
|
|
], RadialColumnSeriesBaseProperties.prototype, "stroke", 2);
|
|
__decorateClass([
|
|
Property80
|
|
], RadialColumnSeriesBaseProperties.prototype, "strokeWidth", 2);
|
|
__decorateClass([
|
|
Property80
|
|
], RadialColumnSeriesBaseProperties.prototype, "strokeOpacity", 2);
|
|
__decorateClass([
|
|
Property80
|
|
], RadialColumnSeriesBaseProperties.prototype, "lineDash", 2);
|
|
__decorateClass([
|
|
Property80
|
|
], RadialColumnSeriesBaseProperties.prototype, "lineDashOffset", 2);
|
|
__decorateClass([
|
|
Property80
|
|
], RadialColumnSeriesBaseProperties.prototype, "cornerRadius", 2);
|
|
__decorateClass([
|
|
Property80
|
|
], RadialColumnSeriesBaseProperties.prototype, "styler", 2);
|
|
__decorateClass([
|
|
Property80
|
|
], RadialColumnSeriesBaseProperties.prototype, "itemStyler", 2);
|
|
__decorateClass([
|
|
Property80
|
|
], RadialColumnSeriesBaseProperties.prototype, "rotation", 2);
|
|
__decorateClass([
|
|
Property80
|
|
], RadialColumnSeriesBaseProperties.prototype, "stackGroup", 2);
|
|
__decorateClass([
|
|
Property80
|
|
], RadialColumnSeriesBaseProperties.prototype, "normalizedTo", 2);
|
|
__decorateClass([
|
|
Property80
|
|
], RadialColumnSeriesBaseProperties.prototype, "label", 2);
|
|
__decorateClass([
|
|
Property80
|
|
], RadialColumnSeriesBaseProperties.prototype, "tooltip", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/series/nightingale/nightingaleUtil.ts
|
|
import { _ModuleSupport as _ModuleSupport181 } from "ag-charts-community";
|
|
|
|
// packages/ag-charts-enterprise/src/series/radial-column/radialColumnUtil.ts
|
|
import { _ModuleSupport as _ModuleSupport180 } from "ag-charts-community";
|
|
var { motion: motion7 } = _ModuleSupport180;
|
|
function createAngleMotionCalculator() {
|
|
const angles = {
|
|
startAngle: /* @__PURE__ */ new Map(),
|
|
endAngle: /* @__PURE__ */ new Map()
|
|
};
|
|
const angleKeys = ["startAngle", "endAngle"];
|
|
const calculate = (node, datum, status) => {
|
|
for (const key of angleKeys) {
|
|
const map = angles[key];
|
|
let from2 = (status === "removed" || status === "updated" ? node : datum)[key];
|
|
let to2 = (status === "removed" ? node : datum)[key];
|
|
if (Number.isNaN(to2)) {
|
|
to2 = node.previousDatum?.[key] ?? Number.NaN;
|
|
}
|
|
const diff8 = from2 - to2;
|
|
if (Math.abs(diff8) > Math.PI) {
|
|
from2 -= Math.sign(diff8) * 2 * Math.PI;
|
|
}
|
|
map.set(datum, { from: from2, to: to2 });
|
|
}
|
|
};
|
|
const getAngles = (datum, fromToKey) => {
|
|
return {
|
|
startAngle: angles.startAngle.get(datum)[fromToKey],
|
|
endAngle: angles.endAngle.get(datum)[fromToKey]
|
|
};
|
|
};
|
|
const from = (datum) => getAngles(datum, "from");
|
|
const to = (datum) => getAngles(datum, "to");
|
|
return { calculate, from, to };
|
|
}
|
|
function fixRadialColumnAnimationStatus(node, datum, status) {
|
|
if (status === "updated") {
|
|
if (node.previousDatum == null || Number.isNaN(node.previousDatum.startAngle) || Number.isNaN(node.previousDatum.endAngle)) {
|
|
return "added";
|
|
}
|
|
if (Number.isNaN(datum.startAngle) || Number.isNaN(datum.endAngle)) {
|
|
return "removed";
|
|
}
|
|
}
|
|
if (status === "added" && node.previousDatum != null) {
|
|
return "updated";
|
|
}
|
|
return status;
|
|
}
|
|
function prepareRadialColumnAnimationFunctions(axisZeroRadius) {
|
|
const angles = createAngleMotionCalculator();
|
|
const fromFn = (node, datum, status) => {
|
|
status = fixRadialColumnAnimationStatus(node, datum, status);
|
|
angles.calculate(node, datum, status);
|
|
const { startAngle, endAngle } = angles.from(datum);
|
|
let innerRadius;
|
|
let outerRadius;
|
|
let columnWidth;
|
|
let axisInnerRadius;
|
|
let axisOuterRadius;
|
|
if (status === "removed" || status === "updated") {
|
|
innerRadius = node.innerRadius;
|
|
outerRadius = node.outerRadius;
|
|
columnWidth = node.columnWidth;
|
|
axisInnerRadius = node.axisInnerRadius;
|
|
axisOuterRadius = node.axisOuterRadius;
|
|
} else {
|
|
innerRadius = axisZeroRadius;
|
|
outerRadius = axisZeroRadius;
|
|
columnWidth = datum.columnWidth;
|
|
axisInnerRadius = datum.axisInnerRadius;
|
|
axisOuterRadius = datum.axisOuterRadius;
|
|
}
|
|
const phase = motion7.NODE_UPDATE_STATE_TO_PHASE_MAPPING[status];
|
|
return {
|
|
innerRadius,
|
|
outerRadius,
|
|
columnWidth,
|
|
axisInnerRadius,
|
|
axisOuterRadius,
|
|
startAngle,
|
|
endAngle,
|
|
phase
|
|
};
|
|
};
|
|
const toFn = (node, datum, status) => {
|
|
const { startAngle, endAngle } = angles.to(datum);
|
|
let innerRadius;
|
|
let outerRadius;
|
|
let columnWidth;
|
|
let axisInnerRadius;
|
|
let axisOuterRadius;
|
|
if (status === "removed") {
|
|
innerRadius = node.innerRadius;
|
|
outerRadius = node.innerRadius;
|
|
columnWidth = node.columnWidth;
|
|
axisInnerRadius = node.axisInnerRadius;
|
|
axisOuterRadius = node.axisOuterRadius;
|
|
} else {
|
|
innerRadius = Number.isNaN(datum.innerRadius) ? axisZeroRadius : datum.innerRadius;
|
|
outerRadius = Number.isNaN(datum.outerRadius) ? axisZeroRadius : datum.outerRadius;
|
|
columnWidth = Number.isNaN(datum.columnWidth) ? node.columnWidth : datum.columnWidth;
|
|
axisInnerRadius = datum.axisInnerRadius;
|
|
axisOuterRadius = datum.axisOuterRadius;
|
|
}
|
|
return { innerRadius, outerRadius, columnWidth, axisInnerRadius, axisOuterRadius, startAngle, endAngle };
|
|
};
|
|
return { toFn, fromFn };
|
|
}
|
|
function resetRadialColumnSelectionFn(_node, {
|
|
innerRadius,
|
|
outerRadius,
|
|
columnWidth,
|
|
axisInnerRadius,
|
|
axisOuterRadius,
|
|
startAngle,
|
|
endAngle
|
|
}) {
|
|
return { innerRadius, outerRadius, columnWidth, axisInnerRadius, axisOuterRadius, startAngle, endAngle };
|
|
}
|
|
|
|
// packages/ag-charts-enterprise/src/series/nightingale/nightingaleUtil.ts
|
|
var { SectorBox, motion: motion8 } = _ModuleSupport181;
|
|
function getRadii(datum) {
|
|
const { negative, innerRadius, outerRadius, stackInnerRadius, stackOuterRadius } = datum;
|
|
return {
|
|
innerRadius: negative ? stackOuterRadius : stackInnerRadius,
|
|
outerRadius: negative ? stackInnerRadius : stackOuterRadius,
|
|
clipInnerRadius: negative ? outerRadius : innerRadius,
|
|
clipOuterRadius: negative ? innerRadius : outerRadius
|
|
};
|
|
}
|
|
function prepareNightingaleAnimationFunctions(axisZeroRadius) {
|
|
const angles = createAngleMotionCalculator();
|
|
const fromFn = (sect, datum, status) => {
|
|
status = fixRadialColumnAnimationStatus(sect, datum, status);
|
|
angles.calculate(sect, datum, status);
|
|
const { startAngle, endAngle } = angles.from(datum);
|
|
let innerRadius;
|
|
let outerRadius;
|
|
let clipSector;
|
|
if (status === "removed" || status === "updated") {
|
|
innerRadius = sect.innerRadius;
|
|
outerRadius = sect.outerRadius;
|
|
clipSector = sect.clipSector;
|
|
} else {
|
|
innerRadius = axisZeroRadius;
|
|
outerRadius = axisZeroRadius;
|
|
}
|
|
clipSector ?? (clipSector = new SectorBox(startAngle, endAngle, innerRadius, outerRadius));
|
|
const phase = motion8.NODE_UPDATE_STATE_TO_PHASE_MAPPING[status];
|
|
return { innerRadius, outerRadius, startAngle, endAngle, clipSector, phase };
|
|
};
|
|
const toFn = (_sect, datum, status) => {
|
|
const { startAngle, endAngle } = angles.to(datum);
|
|
let innerRadius;
|
|
let outerRadius;
|
|
let clipSector;
|
|
if (status === "removed") {
|
|
innerRadius = axisZeroRadius;
|
|
outerRadius = axisZeroRadius;
|
|
clipSector = new SectorBox(startAngle, endAngle, innerRadius, outerRadius);
|
|
} else {
|
|
let clipInnerRadius, clipOuterRadius;
|
|
({ innerRadius, outerRadius, clipInnerRadius, clipOuterRadius } = getRadii(datum));
|
|
if (Number.isNaN(innerRadius))
|
|
innerRadius = axisZeroRadius;
|
|
if (Number.isNaN(outerRadius))
|
|
outerRadius = axisZeroRadius;
|
|
if (Number.isNaN(clipInnerRadius))
|
|
clipInnerRadius = axisZeroRadius;
|
|
if (Number.isNaN(clipOuterRadius))
|
|
clipOuterRadius = axisZeroRadius;
|
|
clipSector = new SectorBox(startAngle, endAngle, clipInnerRadius, clipOuterRadius);
|
|
}
|
|
return { innerRadius, outerRadius, startAngle, endAngle, clipSector };
|
|
};
|
|
return { toFn, fromFn };
|
|
}
|
|
function resetNightingaleSelectionFn(_sect, datum) {
|
|
const { startAngle, endAngle } = datum;
|
|
const { innerRadius, outerRadius, clipInnerRadius, clipOuterRadius } = getRadii(datum);
|
|
const clipSector = new SectorBox(startAngle, endAngle, clipInnerRadius, clipOuterRadius);
|
|
return { innerRadius, outerRadius, startAngle, endAngle, clipSector };
|
|
}
|
|
|
|
// packages/ag-charts-enterprise/src/series/nightingale/nightingaleSeries.ts
|
|
var { Sector: Sector4, SectorBox: SectorBox2 } = _ModuleSupport182;
|
|
var NightingaleSeries = class extends RadialColumnSeriesBase {
|
|
// TODO: Enable once the options contract has been revisited
|
|
// @TempValidate
|
|
// sectorSpacing = 1;
|
|
constructor(moduleCtx) {
|
|
super(moduleCtx, { animationResetFns: { item: resetNightingaleSelectionFn } });
|
|
this.properties = new RadialColumnSeriesBaseProperties();
|
|
}
|
|
setZIndex(zIndex) {
|
|
super.setZIndex(zIndex);
|
|
this.contentGroup.zIndex = [0, PolarZIndexMap.FOREGROUND, zIndex];
|
|
this.highlightGroup.zIndex = [0, PolarZIndexMap.HIGHLIGHT, zIndex];
|
|
this.labelGroup.zIndex = [0, PolarZIndexMap.LABEL, zIndex];
|
|
return true;
|
|
}
|
|
getStackId() {
|
|
const groupIndex = this.seriesGrouping?.groupIndex ?? this.id;
|
|
return `nightingale-stack-${groupIndex}-yValues`;
|
|
}
|
|
nodeFactory() {
|
|
return new Sector4();
|
|
}
|
|
updateItemPath(node, datum, highlight) {
|
|
const { negative } = datum;
|
|
node.centerX = 0;
|
|
node.centerY = 0;
|
|
node.startOuterCornerRadius = negative ? 0 : this.properties.cornerRadius;
|
|
node.endOuterCornerRadius = negative ? 0 : this.properties.cornerRadius;
|
|
node.startInnerCornerRadius = negative ? this.properties.cornerRadius : 0;
|
|
node.endInnerCornerRadius = negative ? this.properties.cornerRadius : 0;
|
|
if (highlight) {
|
|
const { startAngle, endAngle } = datum;
|
|
const { innerRadius, outerRadius, clipInnerRadius, clipOuterRadius } = getRadii(datum);
|
|
node.innerRadius = innerRadius;
|
|
node.outerRadius = outerRadius;
|
|
node.startAngle = startAngle;
|
|
node.endAngle = endAngle;
|
|
node.clipSector = new SectorBox2(startAngle, endAngle, clipInnerRadius, clipOuterRadius);
|
|
}
|
|
}
|
|
getColumnTransitionFunctions() {
|
|
const axisZeroRadius = this.isRadiusAxisReversed() ? this.radius : this.getAxisInnerRadius();
|
|
return prepareNightingaleAnimationFunctions(axisZeroRadius);
|
|
}
|
|
hasItemStylers() {
|
|
return this.properties.itemStyler != null || this.properties.styler != null || this.properties.label.itemStyler != null;
|
|
}
|
|
};
|
|
NightingaleSeries.className = "NightingaleSeries";
|
|
NightingaleSeries.type = "nightingale";
|
|
|
|
// packages/ag-charts-enterprise/src/series/nightingale/nightingaleSeriesOptionsDef.ts
|
|
import { _ModuleSupport as _ModuleSupport183 } from "ag-charts-community";
|
|
import {
|
|
boolean as boolean17,
|
|
commonSeriesOptionsDefs as commonSeriesOptionsDefs15,
|
|
constant as constant16,
|
|
number as number8,
|
|
required as required16,
|
|
string as string16,
|
|
undocumented as undocumented12
|
|
} from "ag-charts-core";
|
|
var { nightingaleSeriesThemeableOptionsDef } = _ModuleSupport183;
|
|
var nightingaleSeriesOptionsDef = {
|
|
...commonSeriesOptionsDefs15,
|
|
...nightingaleSeriesThemeableOptionsDef,
|
|
type: required16(constant16("nightingale")),
|
|
angleKey: required16(string16),
|
|
radiusKey: required16(string16),
|
|
angleName: string16,
|
|
radiusName: string16,
|
|
legendItemName: string16,
|
|
grouped: boolean17,
|
|
stacked: boolean17,
|
|
stackGroup: string16,
|
|
normalizedTo: number8
|
|
};
|
|
nightingaleSeriesOptionsDef.angleKeyAxis = undocumented12(string16);
|
|
nightingaleSeriesOptionsDef.radiusKeyAxis = undocumented12(string16);
|
|
|
|
// packages/ag-charts-enterprise/src/series/nightingale/nightingaleThemes.ts
|
|
import {
|
|
FILL_GRADIENT_RADIAL_SERIES_DEFAULTS,
|
|
FILL_IMAGE_DEFAULTS as FILL_IMAGE_DEFAULTS12,
|
|
FILL_PATTERN_DEFAULTS as FILL_PATTERN_DEFAULTS7,
|
|
LABEL_BOXING_DEFAULTS as LABEL_BOXING_DEFAULTS12,
|
|
MULTI_SERIES_HIGHLIGHT_STYLE as MULTI_SERIES_HIGHLIGHT_STYLE7,
|
|
POLAR_AXIS_SHAPE,
|
|
POLAR_AXIS_TYPE
|
|
} from "ag-charts-core";
|
|
var NIGHTINGALE_SERIES_THEME = {
|
|
series: {
|
|
fill: {
|
|
$applySwitch: [
|
|
{ $path: "type" },
|
|
{ $palette: "fill" },
|
|
["gradient", FILL_GRADIENT_RADIAL_SERIES_DEFAULTS],
|
|
["image", FILL_IMAGE_DEFAULTS12],
|
|
["pattern", FILL_PATTERN_DEFAULTS7]
|
|
]
|
|
},
|
|
stroke: {
|
|
$if: [{ $eq: [{ $palette: "type" }, "inbuilt"] }, { $ref: "chartBackgroundColor" }, { $palette: "stroke" }]
|
|
},
|
|
strokeWidth: 1,
|
|
label: {
|
|
...LABEL_BOXING_DEFAULTS12,
|
|
enabled: false,
|
|
fontSize: { $ref: "fontSize" },
|
|
fontFamily: { $ref: "fontFamily" },
|
|
fontWeight: { $ref: "fontWeight" },
|
|
color: { $ref: "textColor" }
|
|
},
|
|
highlight: { ...MULTI_SERIES_HIGHLIGHT_STYLE7, bringToFront: false }
|
|
},
|
|
axes: {
|
|
[POLAR_AXIS_TYPE.ANGLE_CATEGORY]: {
|
|
shape: { $findFirstSiblingNotOperation: POLAR_AXIS_SHAPE.CIRCLE },
|
|
groupPaddingInner: 0,
|
|
paddingInner: 0,
|
|
label: {
|
|
spacing: 10
|
|
}
|
|
},
|
|
[POLAR_AXIS_TYPE.RADIUS_NUMBER]: {
|
|
shape: { $findFirstSiblingNotOperation: POLAR_AXIS_SHAPE.CIRCLE }
|
|
}
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/series/nightingale/nightingaleModule.ts
|
|
var NightingaleSeriesModule = {
|
|
type: "series",
|
|
name: "nightingale",
|
|
chartType: "polar",
|
|
enterprise: true,
|
|
stackable: true,
|
|
groupable: true,
|
|
stackedByDefault: true,
|
|
version: VERSION41,
|
|
dependencies: [PolarChartModule],
|
|
options: nightingaleSeriesOptionsDef,
|
|
defaultAxes: { angle: { type: POLAR_AXIS_TYPE2.ANGLE_CATEGORY }, radius: { type: POLAR_AXIS_TYPE2.RADIUS_NUMBER } },
|
|
axisKeys: { [ChartAxisDirection46.X]: "xKeyAxis", [ChartAxisDirection46.Y]: "yKeyAxis" },
|
|
themeTemplate: NIGHTINGALE_SERIES_THEME,
|
|
create: (ctx) => new NightingaleSeries(ctx)
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/series/pyramid/pyramidModule.ts
|
|
import { VERSION as VERSION42 } from "ag-charts-community";
|
|
|
|
// packages/ag-charts-enterprise/src/series/pyramid/pyramidSeries.ts
|
|
import {
|
|
_ModuleSupport as _ModuleSupport185
|
|
} from "ag-charts-community";
|
|
import {
|
|
StateMachine as StateMachine14,
|
|
cachedTextMeasurer as cachedTextMeasurer11,
|
|
isArray as isArray6,
|
|
measureTextSegments as measureTextSegments5,
|
|
mergeDefaults as mergeDefaults18,
|
|
toPlainText as toPlainText8,
|
|
toTextString as toTextString4
|
|
} from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/series/pyramid/pyramidProperties.ts
|
|
import { _ModuleSupport as _ModuleSupport184 } from "ag-charts-community";
|
|
import { Property as Property81 } from "ag-charts-core";
|
|
var { SeriesProperties: SeriesProperties9, makeSeriesTooltip: makeSeriesTooltip18, Label: Label13, DropShadow: DropShadow5 } = _ModuleSupport184;
|
|
var PyramidSeriesLabel = class extends Label13 {
|
|
};
|
|
var PyramidSeriesStageLabel = class extends Label13 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.spacing = 0;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property81
|
|
], PyramidSeriesStageLabel.prototype, "spacing", 2);
|
|
__decorateClass([
|
|
Property81
|
|
], PyramidSeriesStageLabel.prototype, "placement", 2);
|
|
var PyramidProperties = class extends SeriesProperties9 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.fills = [];
|
|
this.fillOpacity = 1;
|
|
this.strokes = [];
|
|
this.strokeWidth = 1;
|
|
this.strokeOpacity = 1;
|
|
this.lineDash = [0];
|
|
this.lineDashOffset = 0;
|
|
this.direction = "vertical";
|
|
this.reverse = void 0;
|
|
this.spacing = 0;
|
|
this.aspectRatio = void 0;
|
|
this.shadow = new DropShadow5().set({ enabled: false });
|
|
this.label = new PyramidSeriesLabel();
|
|
this.stageLabel = new PyramidSeriesStageLabel();
|
|
this.tooltip = makeSeriesTooltip18();
|
|
}
|
|
getStyle(index = 0) {
|
|
const { fills, strokes, fillOpacity, strokeWidth, strokeOpacity, lineDash, lineDashOffset } = this;
|
|
return {
|
|
fill: fills[index % fills.length],
|
|
fillOpacity,
|
|
stroke: strokes[index % strokes.length],
|
|
strokeWidth,
|
|
strokeOpacity,
|
|
lineDash,
|
|
lineDashOffset,
|
|
opacity: 1
|
|
};
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property81
|
|
], PyramidProperties.prototype, "stageKey", 2);
|
|
__decorateClass([
|
|
Property81
|
|
], PyramidProperties.prototype, "valueKey", 2);
|
|
__decorateClass([
|
|
Property81
|
|
], PyramidProperties.prototype, "fills", 2);
|
|
__decorateClass([
|
|
Property81
|
|
], PyramidProperties.prototype, "fillOpacity", 2);
|
|
__decorateClass([
|
|
Property81
|
|
], PyramidProperties.prototype, "strokes", 2);
|
|
__decorateClass([
|
|
Property81
|
|
], PyramidProperties.prototype, "strokeWidth", 2);
|
|
__decorateClass([
|
|
Property81
|
|
], PyramidProperties.prototype, "strokeOpacity", 2);
|
|
__decorateClass([
|
|
Property81
|
|
], PyramidProperties.prototype, "lineDash", 2);
|
|
__decorateClass([
|
|
Property81
|
|
], PyramidProperties.prototype, "lineDashOffset", 2);
|
|
__decorateClass([
|
|
Property81
|
|
], PyramidProperties.prototype, "direction", 2);
|
|
__decorateClass([
|
|
Property81
|
|
], PyramidProperties.prototype, "reverse", 2);
|
|
__decorateClass([
|
|
Property81
|
|
], PyramidProperties.prototype, "spacing", 2);
|
|
__decorateClass([
|
|
Property81
|
|
], PyramidProperties.prototype, "aspectRatio", 2);
|
|
__decorateClass([
|
|
Property81
|
|
], PyramidProperties.prototype, "itemStyler", 2);
|
|
__decorateClass([
|
|
Property81
|
|
], PyramidProperties.prototype, "shadow", 2);
|
|
__decorateClass([
|
|
Property81
|
|
], PyramidProperties.prototype, "label", 2);
|
|
__decorateClass([
|
|
Property81
|
|
], PyramidProperties.prototype, "stageLabel", 2);
|
|
__decorateClass([
|
|
Property81
|
|
], PyramidProperties.prototype, "tooltip", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/series/pyramid/pyramidUtil.ts
|
|
function applyPyramidDatum(connector, { x, y, top, right, bottom, left }) {
|
|
connector.x0 = x - top / 2;
|
|
connector.x1 = x + top / 2;
|
|
connector.x2 = x + bottom / 2;
|
|
connector.x3 = x - bottom / 2;
|
|
connector.y0 = y - left / 2;
|
|
connector.y1 = y - right / 2;
|
|
connector.y2 = y + right / 2;
|
|
connector.y3 = y + left / 2;
|
|
}
|
|
function preparePyramidAnimationFunctions(direction) {
|
|
const fromFn = (_connector, datum) => {
|
|
const { x, y } = datum;
|
|
let { top, right, bottom, left } = datum;
|
|
if (direction === "vertical") {
|
|
top = 0;
|
|
bottom = 0;
|
|
} else {
|
|
left = 0;
|
|
right = 0;
|
|
}
|
|
return { x, y, top, right, bottom, left };
|
|
};
|
|
const toFn = (_connector, datum) => {
|
|
const { x, y, top, right, bottom, left } = datum;
|
|
return { x, y, top, right, bottom, left };
|
|
};
|
|
const applyFn = applyPyramidDatum;
|
|
return { fromFn, toFn, applyFn };
|
|
}
|
|
|
|
// packages/ag-charts-enterprise/src/series/pyramid/pyramidSeries.ts
|
|
var {
|
|
valueProperty: valueProperty15,
|
|
SeriesNodePickMode: SeriesNodePickMode13,
|
|
createDatumId: createDatumId18,
|
|
BBox: BBox23,
|
|
Group: Group17,
|
|
Selection: Selection13,
|
|
Text: Text7,
|
|
PointerEvents: PointerEvents9,
|
|
fromToMotion: fromToMotion4,
|
|
seriesLabelFadeInAnimation: seriesLabelFadeInAnimation6,
|
|
getLabelStyles: getLabelStyles5
|
|
} = _ModuleSupport185;
|
|
var PyramidSeries = class extends _ModuleSupport185.DataModelSeries {
|
|
constructor(moduleCtx) {
|
|
super({
|
|
moduleCtx,
|
|
categoryKey: void 0,
|
|
pickModes: [SeriesNodePickMode13.EXACT_SHAPE_MATCH, SeriesNodePickMode13.NEAREST_NODE]
|
|
});
|
|
this.properties = new PyramidProperties();
|
|
this.itemGroup = this.contentGroup.appendChild(new Group17({ name: "itemGroup" }));
|
|
this.itemLabelGroup = this.contentGroup.appendChild(new Group17({ name: "itemLabelGroup" }));
|
|
this.stageLabelGroup = this.contentGroup.appendChild(new Group17({ name: "stageLabelGroup" }));
|
|
this.datumSelection = Selection13.select(
|
|
this.itemGroup,
|
|
() => this.nodeFactory()
|
|
);
|
|
this.labelSelection = Selection13.select(
|
|
this.itemLabelGroup,
|
|
Text7
|
|
);
|
|
this.stageLabelSelection = Selection13.select(this.stageLabelGroup, Text7);
|
|
this.highlightLabelSelection = Selection13.select(this.highlightLabelGroup, Text7);
|
|
this.highlightDatumSelection = Selection13.select(
|
|
this.highlightNodeGroup,
|
|
() => this.nodeFactory()
|
|
);
|
|
this.animationState = new StateMachine14(
|
|
"empty",
|
|
{
|
|
empty: {
|
|
update: {
|
|
target: "ready",
|
|
action: () => this.animateEmptyUpdateReady()
|
|
},
|
|
reset: "empty",
|
|
skip: "ready"
|
|
},
|
|
ready: {
|
|
clear: "empty",
|
|
reset: "empty",
|
|
skip: "ready"
|
|
}
|
|
},
|
|
() => this.checkProcessedDataAnimatable()
|
|
);
|
|
this.itemLabelGroup.pointerEvents = PointerEvents9.None;
|
|
this.stageLabelGroup.pointerEvents = PointerEvents9.None;
|
|
this.cleanup.register(this.ctx.eventsHub.on("legend:item-click", (event) => this.onLegendItemClick(event)));
|
|
}
|
|
nodeFactory() {
|
|
return new FunnelConnector();
|
|
}
|
|
getNodeData() {
|
|
return this.contextNodeData?.nodeData;
|
|
}
|
|
resetAnimation(phase) {
|
|
if (phase === "initial") {
|
|
this.animationState.transition("reset");
|
|
} else if (phase === "ready") {
|
|
this.animationState.transition("skip");
|
|
}
|
|
}
|
|
async processData(dataController) {
|
|
if (this.data == null)
|
|
return;
|
|
const {
|
|
id: seriesId,
|
|
visible,
|
|
ctx: { legendManager }
|
|
} = this;
|
|
const { stageKey, valueKey } = this.properties;
|
|
const xScaleType = "category";
|
|
const yScaleType = "number";
|
|
const validation = (_value, _datum, index) => visible && legendManager.getItemEnabled({ seriesId, itemId: index });
|
|
const visibleProps = this.visible ? {} : { forceValue: 0 };
|
|
const allowNullKey = this.properties.allowNullKeys ?? false;
|
|
await this.requestDataModel(dataController, this.data, {
|
|
props: [
|
|
valueProperty15(stageKey, xScaleType, { id: "xValue", allowNullKey }),
|
|
valueProperty15(valueKey, yScaleType, { id: `yValue`, ...visibleProps, validation, invalidValue: 0 })
|
|
]
|
|
});
|
|
}
|
|
createNodeData() {
|
|
const {
|
|
id: seriesId,
|
|
dataModel,
|
|
processedData,
|
|
properties,
|
|
visible,
|
|
ctx: { legendManager }
|
|
} = this;
|
|
const {
|
|
stageKey,
|
|
valueKey,
|
|
direction,
|
|
reverse = direction === "horizontal",
|
|
spacing,
|
|
aspectRatio,
|
|
label,
|
|
stageLabel
|
|
} = properties;
|
|
if (dataModel == null || processedData == null)
|
|
return;
|
|
const horizontal = direction === "horizontal";
|
|
const xValues = dataModel.resolveColumnById(this, `xValue`, processedData);
|
|
const yValues = dataModel.resolveColumnById(this, `yValue`, processedData);
|
|
const xDomain = dataModel.getDomain(this, "xValue", "value", processedData).domain;
|
|
const yDomain = dataModel.getDomain(this, "yValue", "value", processedData).domain;
|
|
const textMeasurer = cachedTextMeasurer11(stageLabel);
|
|
let textAlign;
|
|
let textBaseline;
|
|
if (horizontal) {
|
|
textAlign = "center";
|
|
textBaseline = stageLabel.placement === "before" ? "bottom" : "top";
|
|
} else {
|
|
textAlign = stageLabel.placement === "after" ? "left" : "right";
|
|
textBaseline = "middle";
|
|
}
|
|
const stageLabelData = stageLabel.enabled ? [] : void 0;
|
|
let maxLabelWidth = 0;
|
|
let maxLabelHeight = 0;
|
|
let yTotal = 0;
|
|
const rawData = processedData.dataSources.get(this.id)?.data ?? [];
|
|
for (const [datumIndex, datum] of rawData.entries()) {
|
|
const xValue = xValues[datumIndex];
|
|
if (xValue === void 0 && !this.properties.allowNullKeys)
|
|
continue;
|
|
const yValue = yValues[datumIndex];
|
|
const enabled = visible && legendManager.getItemEnabled({ seriesId, itemId: datumIndex });
|
|
yTotal += yValue;
|
|
if (stageLabelData == null)
|
|
continue;
|
|
const text2 = this.getLabelText(
|
|
xValue,
|
|
datum,
|
|
stageKey,
|
|
"x",
|
|
xDomain,
|
|
this.properties.stageLabel,
|
|
{ datum, value: yValue, stageKey, valueKey },
|
|
this.properties.allowNullKeys ?? false
|
|
);
|
|
const { width, height } = isArray6(text2) ? measureTextSegments5(text2, label) : textMeasurer.measureLines(toTextString4(text2));
|
|
maxLabelWidth = Math.max(maxLabelWidth, width);
|
|
maxLabelHeight = Math.max(maxLabelHeight, height);
|
|
stageLabelData.push({
|
|
x: Number.NaN,
|
|
y: Number.NaN,
|
|
text: text2,
|
|
textAlign,
|
|
textBaseline,
|
|
visible: enabled
|
|
});
|
|
}
|
|
const seriesRectWidth = this._nodeDataDependencies?.seriesRectWidth ?? 0;
|
|
const seriesRectHeight = this._nodeDataDependencies?.seriesRectHeight ?? 0;
|
|
const totalSpacing = spacing * (processedData.input.count - 1);
|
|
let bounds;
|
|
if (horizontal) {
|
|
const verticalInset = maxLabelHeight + stageLabel.spacing;
|
|
bounds = new BBox23(
|
|
0,
|
|
stageLabel.placement === "before" ? verticalInset : 0,
|
|
seriesRectWidth,
|
|
seriesRectHeight - verticalInset
|
|
);
|
|
} else {
|
|
const horizontalInset = maxLabelWidth + stageLabel.spacing;
|
|
bounds = new BBox23(
|
|
stageLabel.placement === "after" ? 0 : horizontalInset,
|
|
0,
|
|
seriesRectWidth - horizontalInset,
|
|
seriesRectHeight
|
|
);
|
|
}
|
|
if (aspectRatio != null && aspectRatio !== 0) {
|
|
const directionalAspectRatio = direction === "horizontal" ? 1 / aspectRatio : aspectRatio;
|
|
const constrainedWidth = Math.min(bounds.width, bounds.height * directionalAspectRatio);
|
|
const constrainedHeight = constrainedWidth / directionalAspectRatio;
|
|
bounds = new BBox23(
|
|
bounds.x + (bounds.width - constrainedWidth) / 2,
|
|
bounds.y + (bounds.height - constrainedHeight) / 2,
|
|
constrainedWidth,
|
|
constrainedHeight
|
|
);
|
|
}
|
|
let labelX;
|
|
let labelY;
|
|
if (horizontal) {
|
|
labelY = stageLabel.placement === "before" ? bounds.y - stageLabel.spacing : bounds.y + bounds.height + stageLabel.spacing;
|
|
} else {
|
|
labelX = stageLabel.placement === "after" ? bounds.x + bounds.width + stageLabel.spacing : bounds.x - stageLabel.spacing;
|
|
}
|
|
const availableWidth = bounds.width - (horizontal ? totalSpacing : 0);
|
|
const availableHeight = bounds.height - (horizontal ? 0 : totalSpacing);
|
|
if (availableWidth < 0 || availableHeight < 0)
|
|
return;
|
|
const nodeData = [];
|
|
const labelData = [];
|
|
let yStart = 0;
|
|
let stageLabelIndex = 0;
|
|
for (const [datumIndex, datum] of rawData.entries()) {
|
|
const xValue = xValues[datumIndex];
|
|
if (xValue === void 0 && !this.properties.allowNullKeys)
|
|
continue;
|
|
const yValue = yValues[datumIndex];
|
|
const enabled = visible && legendManager.getItemEnabled({ seriesId, itemId: datumIndex });
|
|
const yEnd = yStart + yValue;
|
|
const yMidRatio = (yStart + yEnd) / (2 * yTotal);
|
|
const yRangeRatio = (yEnd - yStart) / yTotal;
|
|
const xOffset = horizontal ? availableWidth * yMidRatio + spacing * datumIndex : availableWidth * 0.5;
|
|
const yOffset = horizontal ? availableHeight * 0.5 : availableHeight * yMidRatio + spacing * datumIndex;
|
|
const x = bounds.x + xOffset;
|
|
const y = bounds.y + yOffset;
|
|
if (stageLabelData != null) {
|
|
const stageLabelDatum = stageLabelData[stageLabelIndex++];
|
|
stageLabelDatum.x = labelX ?? x;
|
|
stageLabelDatum.y = labelY ?? y;
|
|
}
|
|
let top;
|
|
let right;
|
|
let bottom;
|
|
let left;
|
|
if (horizontal) {
|
|
const barWidth = availableWidth * yRangeRatio;
|
|
top = barWidth;
|
|
bottom = barWidth;
|
|
const y0 = (xOffset + barWidth / 2) * (availableHeight / bounds.width);
|
|
const y1 = (xOffset - barWidth / 2) * (availableHeight / bounds.width);
|
|
right = reverse ? bounds.height - y0 : y0;
|
|
left = reverse ? bounds.height - y1 : y1;
|
|
} else {
|
|
const barHeight = availableHeight * yRangeRatio;
|
|
right = barHeight;
|
|
left = barHeight;
|
|
const x0 = (yOffset - barHeight / 2) * (availableWidth / bounds.height);
|
|
const x1 = (yOffset + barHeight / 2) * (availableWidth / bounds.height);
|
|
top = reverse ? bounds.width - x0 : x0;
|
|
bottom = reverse ? bounds.width - x1 : x1;
|
|
}
|
|
const text2 = this.getLabelText(
|
|
yValue,
|
|
datum,
|
|
valueKey,
|
|
"y",
|
|
yDomain,
|
|
label,
|
|
{
|
|
datum,
|
|
value: yValue,
|
|
stageKey,
|
|
valueKey
|
|
}
|
|
);
|
|
const labelDatum = {
|
|
x,
|
|
y,
|
|
text: text2,
|
|
textAlign: "center",
|
|
textBaseline: "middle",
|
|
visible: enabled
|
|
};
|
|
labelData.push(labelDatum);
|
|
nodeData.push({
|
|
series: this,
|
|
datum,
|
|
datumIndex,
|
|
index: datumIndex,
|
|
xValue,
|
|
yValue,
|
|
x,
|
|
y,
|
|
top,
|
|
right,
|
|
bottom,
|
|
left,
|
|
label: labelDatum,
|
|
enabled,
|
|
midPoint: {
|
|
x,
|
|
y
|
|
},
|
|
style: this.getItemStyle({ datumIndex, datum }, false)
|
|
});
|
|
yStart = yEnd;
|
|
}
|
|
return {
|
|
itemId: seriesId,
|
|
nodeData,
|
|
labelData,
|
|
stageLabelData,
|
|
bounds
|
|
};
|
|
}
|
|
updateSelections() {
|
|
if (this.nodeDataRefresh) {
|
|
this.contextNodeData = this.createNodeData();
|
|
this.nodeDataRefresh = false;
|
|
}
|
|
}
|
|
update({ seriesRect }) {
|
|
this.checkResize(seriesRect);
|
|
const {
|
|
datumSelection,
|
|
labelSelection,
|
|
stageLabelSelection,
|
|
highlightDatumSelection,
|
|
highlightLabelSelection
|
|
} = this;
|
|
this.updateSelections();
|
|
this.contentGroup.visible = this.visible;
|
|
this.contentGroup.opacity = this.getOpacity();
|
|
let highlightedDatum = this.ctx.highlightManager?.getActiveHighlight();
|
|
if (highlightedDatum != null && (highlightedDatum.series !== this || highlightedDatum.datum == null)) {
|
|
highlightedDatum = void 0;
|
|
}
|
|
const nodeData = this.contextNodeData?.nodeData ?? [];
|
|
const labelData = this.contextNodeData?.labelData ?? [];
|
|
const stageLabelData = this.contextNodeData?.stageLabelData ?? [];
|
|
this.datumSelection = this.updateDatumSelection({ nodeData, datumSelection });
|
|
this.updateDatumStyles({ datumSelection, isHighlight: false });
|
|
this.updateDatumNodes({ datumSelection, isHighlight: false });
|
|
this.labelSelection = this.updateLabelSelection({ labelData, labelSelection });
|
|
this.updateLabelNodes({ labelSelection, labelProperties: this.properties.label });
|
|
this.stageLabelSelection = this.updateStageLabelSelection({ stageLabelData, stageLabelSelection });
|
|
this.updateLabelNodes({
|
|
labelSelection: stageLabelSelection,
|
|
labelProperties: this.properties.stageLabel,
|
|
checkActiveHighlight: true
|
|
});
|
|
const highlightLabelData = this.getHighlightLabelData(labelData, highlightedDatum) ?? [];
|
|
this.highlightLabelSelection = highlightLabelSelection.update(highlightLabelData);
|
|
this.updateLabelNodes({
|
|
labelSelection: this.highlightLabelSelection,
|
|
labelProperties: this.properties.label,
|
|
isHighlight: true
|
|
});
|
|
this.highlightDatumSelection = this.updateDatumSelection({
|
|
nodeData: highlightedDatum == null ? [] : [highlightedDatum],
|
|
datumSelection: highlightDatumSelection
|
|
});
|
|
this.updateDatumStyles({ datumSelection: highlightDatumSelection, isHighlight: true });
|
|
this.updateDatumNodes({ datumSelection: highlightDatumSelection, isHighlight: true });
|
|
this.animationState.transition("update");
|
|
}
|
|
updateDatumSelection(opts) {
|
|
return opts.datumSelection.update(opts.nodeData);
|
|
}
|
|
getItemStyle({ datumIndex, datum }, isHighlight) {
|
|
const { properties } = this;
|
|
const { itemStyler } = properties;
|
|
const highlightStyle = this.getHighlightStyle(isHighlight, datumIndex);
|
|
const baseStyle = mergeDefaults18(highlightStyle, properties.getStyle(datumIndex));
|
|
let style = baseStyle;
|
|
if (itemStyler != null && datumIndex != null) {
|
|
const overrides = this.cachedDatumCallback(
|
|
createDatumId18(datumIndex, isHighlight ? "highlight" : "node"),
|
|
() => {
|
|
const params = this.makeItemStylerParams(datum, datumIndex, isHighlight, style);
|
|
return this.callWithContext(itemStyler, params);
|
|
}
|
|
);
|
|
if (overrides) {
|
|
style = mergeDefaults18(overrides, style);
|
|
}
|
|
}
|
|
return style;
|
|
}
|
|
makeItemStylerParams(datum, datumIndex, isHighlight, style) {
|
|
const { id: seriesId, properties } = this;
|
|
const { stageKey, valueKey } = properties;
|
|
const activeHighlight = this.ctx.highlightManager?.getActiveHighlight();
|
|
const highlightState = this.getHighlightStateString(activeHighlight, isHighlight, datumIndex);
|
|
const fill = this.filterItemStylerFillParams(style.fill) ?? style.fill;
|
|
return {
|
|
seriesId,
|
|
datum,
|
|
stageKey,
|
|
valueKey,
|
|
highlightState,
|
|
...style,
|
|
fill
|
|
};
|
|
}
|
|
updateDatumStyles({
|
|
datumSelection,
|
|
isHighlight
|
|
}) {
|
|
datumSelection.each((_, nodeDatum) => {
|
|
nodeDatum.style = this.getItemStyle(nodeDatum, isHighlight);
|
|
});
|
|
}
|
|
updateDatumNodes({
|
|
datumSelection
|
|
}) {
|
|
const { properties } = this;
|
|
const { shadow } = properties;
|
|
const bounds = this.contextNodeData?.bounds;
|
|
const fillBBox = bounds ? { series: bounds, axis: bounds } : void 0;
|
|
datumSelection.each((connector, nodeDatum) => {
|
|
connector.setStyleProperties(nodeDatum.style, fillBBox);
|
|
applyPyramidDatum(connector, nodeDatum);
|
|
connector.fillShadow = shadow;
|
|
});
|
|
}
|
|
updateLabelSelection(opts) {
|
|
return opts.labelSelection.update(this.properties.label.enabled ? opts.labelData : []);
|
|
}
|
|
updateStageLabelSelection(opts) {
|
|
return opts.stageLabelSelection.update(opts.stageLabelData);
|
|
}
|
|
updateLabelNodes(opts) {
|
|
const activeHighlight = this.ctx.highlightManager?.getActiveHighlight();
|
|
const { labelSelection, labelProperties, isHighlight = false, checkActiveHighlight = false } = opts;
|
|
labelSelection.each((label, nodeDatum, datumIndex) => {
|
|
const { visible, x, y, text: text2, textAlign, textBaseline } = nodeDatum;
|
|
const datumIsHighlighted = isHighlight || checkActiveHighlight && activeHighlight?.datumIndex === datumIndex;
|
|
const highlightStyle = this.getHighlightStyle(datumIsHighlighted, datumIndex);
|
|
const style = getLabelStyles5(
|
|
this,
|
|
void 0,
|
|
this.properties,
|
|
labelProperties,
|
|
datumIsHighlighted,
|
|
activeHighlight
|
|
);
|
|
const { color: fill, fontSize, fontStyle, fontWeight, fontFamily } = style;
|
|
label.visible = visible;
|
|
label.x = x;
|
|
label.y = y;
|
|
label.text = text2;
|
|
label.fill = fill;
|
|
label.opacity = (highlightStyle.opacity ?? 1) * (style.fillOpacity ?? 1);
|
|
label.fillOpacity = (highlightStyle.opacity ?? 1) * (style.fillOpacity ?? 1);
|
|
label.fontStyle = fontStyle;
|
|
label.fontWeight = fontWeight;
|
|
label.fontSize = fontSize;
|
|
label.fontFamily = fontFamily;
|
|
label.textAlign = textAlign;
|
|
label.textBaseline = textBaseline;
|
|
label.setBoxing(style);
|
|
});
|
|
}
|
|
getHighlightLabelData(_labelData, highlightedItem) {
|
|
if (highlightedItem?.label) {
|
|
return [{ ...highlightedItem.label }];
|
|
}
|
|
return void 0;
|
|
}
|
|
computeFocusBounds(opts) {
|
|
const datum = this.getNodeData()?.[opts.datumIndex];
|
|
if (datum === void 0)
|
|
return;
|
|
for (const node of this.datumSelection) {
|
|
if (node.datum === datum) {
|
|
return node.node;
|
|
}
|
|
}
|
|
}
|
|
getTooltipContent(datumIndex) {
|
|
const { id: seriesId, dataModel, processedData, properties } = this;
|
|
const { stageKey, valueKey, tooltip } = properties;
|
|
if (!dataModel || !processedData)
|
|
return;
|
|
const datum = processedData.dataSources.get(this.id)?.data[datumIndex];
|
|
const xValue = dataModel.resolveColumnById(this, "xValue", processedData)[datumIndex];
|
|
const yValue = dataModel.resolveColumnById(this, `yValue`, processedData)[datumIndex];
|
|
const allowNullKeys = this.properties.allowNullKeys ?? false;
|
|
if (xValue === void 0 && !allowNullKeys)
|
|
return;
|
|
const label = this.getLabelText(
|
|
xValue,
|
|
datum,
|
|
stageKey,
|
|
"x",
|
|
dataModel.getDomain(this, "xValue", "value", processedData).domain,
|
|
this.properties.stageLabel,
|
|
{ datum, value: xValue, stageKey, valueKey }
|
|
);
|
|
const format = this.getItemStyle({ datumIndex, datum }, false);
|
|
return this.formatTooltipWithContext(
|
|
tooltip,
|
|
{
|
|
symbol: this.legendItemSymbol(datumIndex),
|
|
data: [{ label: toPlainText8(label), value: toPlainText8(yValue) }]
|
|
},
|
|
{
|
|
seriesId,
|
|
datum,
|
|
title: void 0,
|
|
stageKey,
|
|
valueKey,
|
|
...format
|
|
}
|
|
);
|
|
}
|
|
getSeriesDomain() {
|
|
return { domain: [Number.NaN, Number.NaN] };
|
|
}
|
|
getSeriesRange() {
|
|
return [Number.NaN, Number.NaN];
|
|
}
|
|
pickNodeClosestDatum({ x, y }) {
|
|
let minDistanceSquared = Infinity;
|
|
let minDatum;
|
|
this.datumSelection.each((node, datum) => {
|
|
const distanceSquared = node.distanceSquared(x, y);
|
|
if (distanceSquared < minDistanceSquared) {
|
|
minDistanceSquared = distanceSquared;
|
|
minDatum = datum;
|
|
}
|
|
});
|
|
return minDatum == null ? void 0 : { datum: minDatum, distance: Math.sqrt(minDistanceSquared) };
|
|
}
|
|
legendItemSymbol(datumIndex) {
|
|
const { fills, strokes, strokeWidth, fillOpacity, strokeOpacity, lineDash, lineDashOffset } = this.properties;
|
|
const fill = fills[datumIndex] ?? "black";
|
|
const stroke3 = strokes[datumIndex] ?? "black";
|
|
return {
|
|
marker: {
|
|
fill,
|
|
fillOpacity,
|
|
stroke: stroke3,
|
|
strokeWidth,
|
|
strokeOpacity,
|
|
lineDash,
|
|
lineDashOffset
|
|
}
|
|
};
|
|
}
|
|
getLegendData(legendType) {
|
|
const {
|
|
processedData,
|
|
dataModel,
|
|
id: seriesId,
|
|
ctx: { legendManager },
|
|
visible
|
|
} = this;
|
|
if (!dataModel || !processedData || legendType !== "category") {
|
|
return [];
|
|
}
|
|
const { showInLegend } = this.properties;
|
|
const stageValues = dataModel.resolveColumnById(this, `xValue`, processedData);
|
|
return (processedData.dataSources.get(this.id)?.data ?? []).map((datum, datumIndex) => {
|
|
const stageValue = stageValues[datumIndex];
|
|
const allowNullKeys = this.properties.allowNullKeys ?? false;
|
|
if (stageValue == null && !allowNullKeys)
|
|
return;
|
|
return {
|
|
legendType: "category",
|
|
id: seriesId,
|
|
datum,
|
|
itemId: datumIndex,
|
|
seriesId,
|
|
enabled: visible && legendManager.getItemEnabled({ seriesId, itemId: datumIndex }),
|
|
label: { text: String(stageValue) },
|
|
symbol: this.legendItemSymbol(datumIndex),
|
|
hideInLegend: !showInLegend
|
|
};
|
|
}).filter((datum) => datum != null);
|
|
}
|
|
animateReset() {
|
|
this.ctx.animationManager.skipCurrentBatch();
|
|
this.ctx.animationManager.stopByAnimationGroupId(this.id);
|
|
}
|
|
animateEmptyUpdateReady() {
|
|
const { datumSelection, labelSelection, properties } = this;
|
|
const fns = preparePyramidAnimationFunctions(properties.direction);
|
|
fromToMotion4(this.id, "nodes", this.ctx.animationManager, [datumSelection], fns);
|
|
seriesLabelFadeInAnimation6(this, "labels", this.ctx.animationManager, labelSelection);
|
|
}
|
|
hasItemStylers() {
|
|
return this.properties.itemStyler != null || this.properties.label.itemStyler != null;
|
|
}
|
|
};
|
|
PyramidSeries.className = "PyramidSeries";
|
|
PyramidSeries.type = "pyramid";
|
|
|
|
// packages/ag-charts-enterprise/src/series/pyramid/pyramidSeriesOptionsDef.ts
|
|
import { _ModuleSupport as _ModuleSupport186 } from "ag-charts-community";
|
|
import { commonSeriesOptionsDefs as commonSeriesOptionsDefs16, constant as constant17, required as required17, string as string17 } from "ag-charts-core";
|
|
var { pyramidSeriesThemeableOptionsDef } = _ModuleSupport186;
|
|
var pyramidSeriesOptionsDef = {
|
|
...pyramidSeriesThemeableOptionsDef,
|
|
...commonSeriesOptionsDefs16,
|
|
type: required17(constant17("pyramid")),
|
|
stageKey: required17(string17),
|
|
valueKey: required17(string17)
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/series/pyramid/pyramidThemes.ts
|
|
import {
|
|
DEFAULT_SHADOW_COLOUR as DEFAULT_SHADOW_COLOUR2,
|
|
FILL_GRADIENT_LINEAR_DEFAULTS as FILL_GRADIENT_LINEAR_DEFAULTS6,
|
|
FILL_IMAGE_DEFAULTS as FILL_IMAGE_DEFAULTS13,
|
|
FILL_PATTERN_DEFAULTS as FILL_PATTERN_DEFAULTS8,
|
|
LABEL_BOXING_DEFAULTS as LABEL_BOXING_DEFAULTS13
|
|
} from "ag-charts-core";
|
|
var PYRAMID_SERIES_THEME = {
|
|
series: {
|
|
direction: "vertical",
|
|
strokeWidth: { $isUserOption: ["./strokes/0", 2, 0] },
|
|
spacing: 2,
|
|
fills: {
|
|
$applyCycle: [
|
|
{ $size: { $path: ["./data", { $path: "/data" }] } },
|
|
{ $palette: "fills" },
|
|
{
|
|
$applySwitch: [
|
|
{ $path: ["/type", void 0, { $value: "$1" }] },
|
|
{ $value: "$1" },
|
|
["gradient", FILL_GRADIENT_LINEAR_DEFAULTS6],
|
|
["pattern", FILL_PATTERN_DEFAULTS8],
|
|
["image", FILL_IMAGE_DEFAULTS13]
|
|
]
|
|
}
|
|
]
|
|
},
|
|
strokes: {
|
|
$applyCycle: [{ $size: { $path: ["./data", { $path: "/data" }] } }, { $palette: "strokes" }]
|
|
},
|
|
label: {
|
|
...LABEL_BOXING_DEFAULTS13,
|
|
enabled: true,
|
|
fontSize: { $ref: "fontSize" },
|
|
fontFamily: { $ref: "fontFamily" },
|
|
fontWeight: { $ref: "fontWeight" },
|
|
color: { $ref: "chartBackgroundColor" }
|
|
},
|
|
stageLabel: {
|
|
...LABEL_BOXING_DEFAULTS13,
|
|
enabled: true,
|
|
fontSize: { $ref: "fontSize" },
|
|
fontFamily: { $ref: "fontFamily" },
|
|
fontWeight: { $ref: "fontWeight" },
|
|
color: { $ref: "textColor" },
|
|
spacing: 12
|
|
},
|
|
shadow: {
|
|
enabled: false,
|
|
color: DEFAULT_SHADOW_COLOUR2,
|
|
xOffset: 3,
|
|
yOffset: 3,
|
|
blur: 5
|
|
},
|
|
highlight: {
|
|
unhighlightedItem: {
|
|
opacity: 0.4
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/series/pyramid/pyramidModule.ts
|
|
var PyramidSeriesModule = {
|
|
type: "series",
|
|
name: "pyramid",
|
|
chartType: "standalone",
|
|
enterprise: true,
|
|
solo: true,
|
|
version: VERSION42,
|
|
dependencies: [StandaloneChartModule],
|
|
options: pyramidSeriesOptionsDef,
|
|
themeTemplate: PYRAMID_SERIES_THEME,
|
|
create: (ctx) => new PyramidSeries(ctx)
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/series/radar-area/radarAreaModule.ts
|
|
import { PolarChartModule as PolarChartModule2, VERSION as VERSION43 } from "ag-charts-community";
|
|
import { ChartAxisDirection as ChartAxisDirection49, POLAR_AXIS_TYPE as POLAR_AXIS_TYPE4 } from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/series/radar/radarThemes.ts
|
|
import {
|
|
FILL_GRADIENT_LINEAR_DEFAULTS as FILL_GRADIENT_LINEAR_DEFAULTS7,
|
|
FILL_GRADIENT_RADIAL_REVERSED_DEFAULTS as FILL_GRADIENT_RADIAL_REVERSED_DEFAULTS3,
|
|
FILL_IMAGE_DEFAULTS as FILL_IMAGE_DEFAULTS14,
|
|
FILL_PATTERN_DEFAULTS as FILL_PATTERN_DEFAULTS9,
|
|
LABEL_BOXING_DEFAULTS as LABEL_BOXING_DEFAULTS14,
|
|
MARKER_SERIES_HIGHLIGHT_STYLE as MARKER_SERIES_HIGHLIGHT_STYLE2,
|
|
POLAR_AXIS_TYPE as POLAR_AXIS_TYPE3,
|
|
SAFE_STROKE_FILL_OPERATION as SAFE_STROKE_FILL_OPERATION3,
|
|
mergeDefaults as mergeDefaults19
|
|
} from "ag-charts-core";
|
|
var BASE_RADAR_SERIES_THEME = {
|
|
series: {
|
|
stroke: { $palette: "stroke" },
|
|
label: {
|
|
...LABEL_BOXING_DEFAULTS14,
|
|
enabled: false,
|
|
fontSize: { $ref: "fontSize" },
|
|
fontFamily: { $ref: "fontFamily" },
|
|
fontWeight: { $ref: "fontWeight" },
|
|
color: { $ref: "textColor" }
|
|
},
|
|
marker: {
|
|
enabled: true,
|
|
fill: {
|
|
$applySwitch: [
|
|
{ $path: "type" },
|
|
{ $palette: "fill" },
|
|
["gradient", FILL_GRADIENT_RADIAL_REVERSED_DEFAULTS3],
|
|
["image", FILL_IMAGE_DEFAULTS14],
|
|
["pattern", FILL_PATTERN_DEFAULTS9]
|
|
]
|
|
},
|
|
stroke: { $palette: "stroke" },
|
|
fillOpacity: 1,
|
|
shape: "circle",
|
|
size: 6,
|
|
strokeOpacity: 1,
|
|
strokeWidth: { $isUserOption: ["./stroke", 1, 0] }
|
|
},
|
|
highlight: MARKER_SERIES_HIGHLIGHT_STYLE2,
|
|
tooltip: {
|
|
range: { $path: ["/tooltip/range", "nearest"] }
|
|
}
|
|
},
|
|
axes: {
|
|
[POLAR_AXIS_TYPE3.ANGLE_CATEGORY]: {
|
|
label: {
|
|
spacing: 10
|
|
}
|
|
}
|
|
}
|
|
};
|
|
var RADAR_LINE_SERIES_THEME = mergeDefaults19(
|
|
{
|
|
series: {
|
|
stroke: SAFE_STROKE_FILL_OPERATION3,
|
|
strokeWidth: 2
|
|
}
|
|
},
|
|
BASE_RADAR_SERIES_THEME
|
|
);
|
|
var RADAR_AREA_SERIES_THEME = mergeDefaults19(
|
|
{
|
|
series: {
|
|
fill: {
|
|
$applySwitch: [
|
|
{ $path: "type" },
|
|
{ $palette: "fill" },
|
|
["gradient", FILL_GRADIENT_LINEAR_DEFAULTS7],
|
|
["image", FILL_IMAGE_DEFAULTS14],
|
|
["pattern", FILL_PATTERN_DEFAULTS9]
|
|
]
|
|
},
|
|
fillOpacity: 0.8,
|
|
strokeWidth: 2,
|
|
marker: {
|
|
enabled: false
|
|
}
|
|
}
|
|
},
|
|
BASE_RADAR_SERIES_THEME
|
|
);
|
|
|
|
// packages/ag-charts-enterprise/src/series/radar-area/radarAreaSeries.ts
|
|
import {
|
|
_ModuleSupport as _ModuleSupport189
|
|
} from "ag-charts-community";
|
|
import { ChartAxisDirection as ChartAxisDirection48 } from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/series/radar/radarSeries.ts
|
|
import {
|
|
_ModuleSupport as _ModuleSupport188
|
|
} from "ag-charts-community";
|
|
import {
|
|
ChartAxisDirection as ChartAxisDirection47,
|
|
extent as extent3,
|
|
isFiniteNumber as isFiniteNumber3,
|
|
isNumberEqual as isNumberEqual9,
|
|
mergeDefaults as mergeDefaults20
|
|
} from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/series/radar/radarSeriesProperties.ts
|
|
import { _ModuleSupport as _ModuleSupport187 } from "ag-charts-community";
|
|
import { Property as Property82 } from "ag-charts-core";
|
|
var { Label: Label14, SeriesMarker: SeriesMarker2, SeriesProperties: SeriesProperties10, makeSeriesTooltip: makeSeriesTooltip19 } = _ModuleSupport187;
|
|
var RadarSeriesProperties = class extends SeriesProperties10 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.angleKeyAxis = "angle";
|
|
this.radiusKeyAxis = "radius";
|
|
this.stroke = "black";
|
|
this.strokeWidth = 1;
|
|
this.strokeOpacity = 1;
|
|
this.lineDash = [0];
|
|
this.lineDashOffset = 0;
|
|
this.rotation = 0;
|
|
this.marker = new SeriesMarker2();
|
|
this.label = new Label14();
|
|
this.tooltip = makeSeriesTooltip19();
|
|
this.connectMissingData = false;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property82
|
|
], RadarSeriesProperties.prototype, "angleKey", 2);
|
|
__decorateClass([
|
|
Property82
|
|
], RadarSeriesProperties.prototype, "radiusKey", 2);
|
|
__decorateClass([
|
|
Property82
|
|
], RadarSeriesProperties.prototype, "angleName", 2);
|
|
__decorateClass([
|
|
Property82
|
|
], RadarSeriesProperties.prototype, "radiusName", 2);
|
|
__decorateClass([
|
|
Property82
|
|
], RadarSeriesProperties.prototype, "angleKeyAxis", 2);
|
|
__decorateClass([
|
|
Property82
|
|
], RadarSeriesProperties.prototype, "radiusKeyAxis", 2);
|
|
__decorateClass([
|
|
Property82
|
|
], RadarSeriesProperties.prototype, "legendItemName", 2);
|
|
__decorateClass([
|
|
Property82
|
|
], RadarSeriesProperties.prototype, "stroke", 2);
|
|
__decorateClass([
|
|
Property82
|
|
], RadarSeriesProperties.prototype, "strokeWidth", 2);
|
|
__decorateClass([
|
|
Property82
|
|
], RadarSeriesProperties.prototype, "strokeOpacity", 2);
|
|
__decorateClass([
|
|
Property82
|
|
], RadarSeriesProperties.prototype, "lineDash", 2);
|
|
__decorateClass([
|
|
Property82
|
|
], RadarSeriesProperties.prototype, "lineDashOffset", 2);
|
|
__decorateClass([
|
|
Property82
|
|
], RadarSeriesProperties.prototype, "rotation", 2);
|
|
__decorateClass([
|
|
Property82
|
|
], RadarSeriesProperties.prototype, "styler", 2);
|
|
__decorateClass([
|
|
Property82
|
|
], RadarSeriesProperties.prototype, "marker", 2);
|
|
__decorateClass([
|
|
Property82
|
|
], RadarSeriesProperties.prototype, "label", 2);
|
|
__decorateClass([
|
|
Property82
|
|
], RadarSeriesProperties.prototype, "tooltip", 2);
|
|
__decorateClass([
|
|
Property82
|
|
], RadarSeriesProperties.prototype, "connectMissingData", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/series/radar/radarSeries.ts
|
|
var {
|
|
DEFAULT_POLAR_DIRECTION_KEYS: DEFAULT_POLAR_DIRECTION_KEYS2,
|
|
DEFAULT_POLAR_DIRECTION_NAMES: DEFAULT_POLAR_DIRECTION_NAMES2,
|
|
PolarAxis: PolarAxis2,
|
|
SeriesNodePickMode: SeriesNodePickMode14,
|
|
keyProperty: keyProperty10,
|
|
valueProperty: valueProperty16,
|
|
fixNumericExtent: fixNumericExtent9,
|
|
seriesLabelFadeInAnimation: seriesLabelFadeInAnimation7,
|
|
markerFadeInAnimation: markerFadeInAnimation2,
|
|
resetMarkerFn: resetMarkerFn2,
|
|
resetLabelFn: resetLabelFn6,
|
|
animationValidation: animationValidation8,
|
|
computeMarkerFocusBounds: computeMarkerFocusBounds3,
|
|
BBox: BBox24,
|
|
Group: Group18,
|
|
Path: Path12,
|
|
Selection: Selection14,
|
|
Text: Text8,
|
|
Marker: Marker5,
|
|
updateLabelNode: updateLabelNode7,
|
|
getMarkerStyles: getMarkerStyles2
|
|
} = _ModuleSupport188;
|
|
var RadarSeriesNodeEvent = class extends _ModuleSupport188.SeriesNodeEvent {
|
|
constructor(type, nativeEvent, datum, series) {
|
|
super(type, nativeEvent, datum, series);
|
|
this.angleKey = series.properties.angleKey;
|
|
this.radiusKey = series.properties.radiusKey;
|
|
}
|
|
};
|
|
var RadarSeries = class extends _ModuleSupport188.PolarSeries {
|
|
constructor(moduleCtx) {
|
|
super({
|
|
moduleCtx,
|
|
categoryKey: "angleValue",
|
|
propertyKeys: DEFAULT_POLAR_DIRECTION_KEYS2,
|
|
propertyNames: DEFAULT_POLAR_DIRECTION_NAMES2,
|
|
pickModes: [SeriesNodePickMode14.NEAREST_NODE, SeriesNodePickMode14.EXACT_SHAPE_MATCH],
|
|
canHaveAxes: true,
|
|
animationResetFns: {
|
|
item: resetMarkerFn2,
|
|
label: resetLabelFn6
|
|
},
|
|
clipFocusBox: false
|
|
});
|
|
this.NodeEvent = RadarSeriesNodeEvent;
|
|
this.lineGroup = this.contentGroup.appendChild(new Group18({ name: "radar-line" }));
|
|
this.lineSelection = Selection14.select(
|
|
this.lineGroup,
|
|
Path12
|
|
);
|
|
this.resetInvalidToZero = false;
|
|
this.circleCache = { r: 0, cx: 0, cy: 0 };
|
|
this.lineGroup.zIndex = 0;
|
|
this.itemGroup.zIndex = 1;
|
|
}
|
|
renderToOffscreenCanvas() {
|
|
const hasMarkers = (this.nodeData?.length ?? 0) > 0;
|
|
return hasMarkers && this.getDrawingMode(false) === "cutout" || super.renderToOffscreenCanvas();
|
|
}
|
|
nodeFactory() {
|
|
return new Marker5();
|
|
}
|
|
getSeriesDomain(direction) {
|
|
const { dataModel, processedData } = this;
|
|
if (!processedData || !dataModel)
|
|
return { domain: [] };
|
|
if (direction === ChartAxisDirection47.Angle) {
|
|
const domain = dataModel.getDomain(this, `angleValue`, "key", processedData).domain;
|
|
const sortMetadata = dataModel.getKeySortMetadata(this, "angleValue", processedData);
|
|
return { domain, sortMetadata };
|
|
} else {
|
|
const domain = dataModel.getDomain(this, `radiusValue`, "value", processedData).domain;
|
|
const ext = extent3(domain.length === 0 ? domain : [0].concat(domain));
|
|
return { domain: fixNumericExtent9(ext) };
|
|
}
|
|
}
|
|
async processData(dataController) {
|
|
const { angleKey, radiusKey } = this.properties;
|
|
const extraProps = [];
|
|
if (!this.ctx.animationManager.isSkipped()) {
|
|
extraProps.push(animationValidation8());
|
|
}
|
|
const radiusScaleType = this.axes[ChartAxisDirection47.Radius]?.scale.type;
|
|
const angleScaleType = this.axes[ChartAxisDirection47.Angle]?.scale.type;
|
|
const allowNullKey = this.properties.allowNullKeys ?? false;
|
|
await this.requestDataModel(dataController, this.data, {
|
|
props: [
|
|
keyProperty10(angleKey, angleScaleType, { id: "angleValue", allowNullKey }),
|
|
valueProperty16(radiusKey, radiusScaleType, { id: "radiusValue", invalidValue: void 0 }),
|
|
...extraProps
|
|
]
|
|
});
|
|
this.animationState.transition("updateData");
|
|
}
|
|
didCircleChange() {
|
|
const r = this.radius;
|
|
const cx = this.centerX;
|
|
const cy = this.centerY;
|
|
const cache = this.circleCache;
|
|
if (!(r === cache.r && cx === cache.cx && cy === cache.cy)) {
|
|
this.circleCache = { r, cx, cy };
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
getAxisInnerRadius() {
|
|
const radiusAxis = this.axes[ChartAxisDirection47.Radius];
|
|
return radiusAxis instanceof PolarAxis2 ? this.radius * radiusAxis.innerRadiusRatio : 0;
|
|
}
|
|
maybeRefreshNodeData() {
|
|
const didCircleChange = this.didCircleChange();
|
|
if (!didCircleChange && !this.nodeDataRefresh)
|
|
return;
|
|
this.contextNodeData = this.createNodeData();
|
|
this.nodeData = this.contextNodeData?.nodeData ?? [];
|
|
this.nodeDataRefresh = false;
|
|
}
|
|
createNodeData() {
|
|
const { processedData, dataModel } = this;
|
|
if (!processedData || !dataModel)
|
|
return;
|
|
const { angleKey, radiusKey, angleName, radiusName, legendItemName, marker, label } = this.properties;
|
|
const angleScale = this.axes[ChartAxisDirection47.Angle]?.scale;
|
|
const radiusScale = this.axes[ChartAxisDirection47.Radius]?.scale;
|
|
if (!angleScale || !radiusScale) {
|
|
return;
|
|
}
|
|
const angleValues = dataModel.resolveKeysById(this, `angleValue`, processedData);
|
|
const radiusValues = dataModel.resolveColumnById(this, `radiusValue`, processedData);
|
|
const axisInnerRadius = this.getAxisInnerRadius();
|
|
const radiusDomain = this.getSeriesDomain(ChartAxisDirection47.Radius).domain;
|
|
const rawData = processedData.dataSources.get(this.id)?.data ?? [];
|
|
const allowNullKeys = this.properties.allowNullKeys ?? false;
|
|
const nodeData = [];
|
|
for (let datumIndex = 0; datumIndex < rawData.length; datumIndex++) {
|
|
const datum = rawData[datumIndex];
|
|
const angleDatum = angleValues[datumIndex];
|
|
if (angleDatum === void 0 && !allowNullKeys) {
|
|
continue;
|
|
}
|
|
const radiusDatum = radiusValues[datumIndex];
|
|
const angle = angleScale.convert(angleDatum);
|
|
const radius = this.radius + axisInnerRadius - radiusScale.convert(radiusDatum);
|
|
const cos = Math.cos(angle);
|
|
const sin = Math.sin(angle);
|
|
const x = cos * radius;
|
|
const y = sin * radius;
|
|
let labelNodeDatum;
|
|
if (label.enabled) {
|
|
const labelText = this.getLabelText(
|
|
radiusDatum,
|
|
datum,
|
|
radiusKey,
|
|
"radius",
|
|
radiusDomain,
|
|
label,
|
|
{ value: radiusDatum, datum, angleKey, radiusKey, angleName, radiusName, legendItemName }
|
|
);
|
|
if (labelText) {
|
|
let textAlign = "right";
|
|
if (isNumberEqual9(cos, 0)) {
|
|
textAlign = "center";
|
|
} else if (cos > 0) {
|
|
textAlign = "left";
|
|
}
|
|
let textBaseline = "bottom";
|
|
if (isNumberEqual9(sin, 0)) {
|
|
textBaseline = "middle";
|
|
} else if (sin > 0) {
|
|
textBaseline = "top";
|
|
}
|
|
labelNodeDatum = {
|
|
x: x + cos * marker.size,
|
|
y: y + sin * marker.size,
|
|
text: labelText,
|
|
textAlign,
|
|
textBaseline
|
|
};
|
|
}
|
|
}
|
|
nodeData.push({
|
|
series: this,
|
|
datum,
|
|
datumIndex,
|
|
index: datumIndex,
|
|
point: { x, y, size: marker.size },
|
|
midPoint: { x, y },
|
|
label: labelNodeDatum,
|
|
angleValue: angleDatum,
|
|
radiusValue: radiusDatum,
|
|
missing: !isFiniteNumber3(angle) || !isFiniteNumber3(radius)
|
|
});
|
|
}
|
|
return {
|
|
itemId: radiusKey,
|
|
nodeData,
|
|
labelData: nodeData,
|
|
styles: getMarkerStyles2(this, this.properties, marker)
|
|
};
|
|
}
|
|
update({ seriesRect }) {
|
|
const resize = this.checkResize(seriesRect);
|
|
const animationEnabled = !this.ctx.animationManager.isSkipped();
|
|
const { series } = this.ctx.highlightManager?.getActiveHighlight() ?? {};
|
|
this.highlightGroup.visible = (animationEnabled || this.visible) && series === this;
|
|
this.maybeRefreshNodeData();
|
|
this.contentGroup.translationX = this.centerX;
|
|
this.contentGroup.translationY = this.centerY;
|
|
this.highlightGroup.translationX = this.centerX;
|
|
this.highlightGroup.translationY = this.centerY;
|
|
if (this.labelGroup) {
|
|
this.labelGroup.translationX = this.centerX;
|
|
this.labelGroup.translationY = this.centerY;
|
|
}
|
|
this.updatePathSelections();
|
|
this.updateMarkerSelection();
|
|
this.updateHighlightSelection();
|
|
this.updatePathNodes();
|
|
if (this.hasItemStylers()) {
|
|
this.updateDatumStyles(this.itemSelection, false);
|
|
this.updateDatumStyles(this.highlightSelection, true);
|
|
}
|
|
const drawingMode = this.ctx.chartService.highlight?.drawingMode ?? "overlay";
|
|
this.updateMarkers(this.itemSelection, false, "overlay");
|
|
this.updateMarkers(this.highlightSelection, true, drawingMode);
|
|
this.updateLabels();
|
|
if (resize) {
|
|
this.animationState.transition("resize");
|
|
}
|
|
this.animationState.transition("update");
|
|
}
|
|
updatePathSelections() {
|
|
const pathData = this.visible ? [true] : [];
|
|
this.lineSelection.update(pathData);
|
|
}
|
|
updateMarkerSelection() {
|
|
const { marker, styler } = this.properties;
|
|
if (marker.isDirty()) {
|
|
this.itemSelection.clear();
|
|
this.itemSelection.cleanup();
|
|
this.itemSelection = Selection14.select(this.itemGroup, () => this.nodeFactory(), false);
|
|
}
|
|
const markersEnabled = styler == null ? marker.enabled : this.getStyle().marker.enabled;
|
|
const data = this.visible && marker.shape && markersEnabled ? this.nodeData : [];
|
|
this.itemSelection.update(data);
|
|
}
|
|
updateHighlightSelection() {
|
|
const { marker, styler } = this.properties;
|
|
if (marker.isDirty()) {
|
|
this.highlightSelection.clear();
|
|
this.highlightSelection.cleanup();
|
|
this.highlightSelection = Selection14.select(this.highlightGroup, () => this.nodeFactory(), false);
|
|
}
|
|
const markersEnabled = styler == null ? marker.enabled : this.getStyle().marker.enabled;
|
|
const highlighted = this.ctx.highlightManager?.getActiveHighlight();
|
|
const data = this.visible && marker.shape && markersEnabled && highlighted?.datum ? [{ ...highlighted }] : [];
|
|
this.highlightSelection.update(data);
|
|
}
|
|
getMarkerFill(highlightedStyle) {
|
|
return highlightedStyle?.fill ?? this.getStyle().marker.fill;
|
|
}
|
|
getDatumStylerProperties(datum) {
|
|
const { id: seriesId, properties } = this;
|
|
const { angleKey, radiusKey } = properties;
|
|
return {
|
|
seriesId,
|
|
datum,
|
|
angleKey,
|
|
radiusKey
|
|
};
|
|
}
|
|
updateDatumStyles(selection, isHighlight) {
|
|
const highlightedDatum = this.ctx.highlightManager.getActiveHighlight();
|
|
selection.each((_, datum) => {
|
|
const highlightState = this.getHighlightState(highlightedDatum, isHighlight, datum.datumIndex);
|
|
const stylerStyle = this.getStyle(highlightState);
|
|
const { stroke: stroke3, strokeWidth, strokeOpacity } = stylerStyle;
|
|
datum.style = this.getMarkerStyle(
|
|
this.properties.marker,
|
|
datum,
|
|
this.getDatumStylerProperties(datum.datum),
|
|
{ isHighlight, highlightState },
|
|
stylerStyle.marker,
|
|
{
|
|
stroke: stroke3,
|
|
strokeWidth,
|
|
strokeOpacity
|
|
}
|
|
);
|
|
});
|
|
}
|
|
updateMarkers(selection, isHighlight, drawingMode) {
|
|
const fillBBox = this.getShapeFillBBox();
|
|
const { contextNodeData } = this;
|
|
if (!contextNodeData) {
|
|
return;
|
|
}
|
|
const highlightedDatum = this.ctx.highlightManager.getActiveHighlight();
|
|
drawingMode = this.getDrawingMode(isHighlight, drawingMode);
|
|
selection.each((node, datum) => {
|
|
const style = datum.style ?? contextNodeData.styles[this.getHighlightState(highlightedDatum, isHighlight, datum.datumIndex)];
|
|
this.applyMarkerStyle(style, node, datum.point, fillBBox);
|
|
node.drawingMode = drawingMode;
|
|
});
|
|
}
|
|
updateLabels() {
|
|
const { properties } = this;
|
|
const activeHighlight = this.ctx.highlightManager?.getActiveHighlight();
|
|
const highlightData = activeHighlight?.series === this && activeHighlight?.datum ? [{ ...activeHighlight }] : [];
|
|
this.labelSelection.update(this.nodeData).each((node, datum) => {
|
|
if (datum.label) {
|
|
const isHighlight = false;
|
|
node.fillOpacity = this.getHighlightStyle(isHighlight, datum.datumIndex).opacity ?? 1;
|
|
updateLabelNode7(this, node, properties, properties.label, datum.label, isHighlight, activeHighlight);
|
|
}
|
|
});
|
|
this.highlightLabelSelection.update(highlightData).each((node, datum) => {
|
|
if (datum.label) {
|
|
const isHighlight = true;
|
|
node.fillOpacity = this.getHighlightStyle(isHighlight, datum.datumIndex).opacity ?? 1;
|
|
updateLabelNode7(this, node, properties, properties.label, datum.label, isHighlight, activeHighlight);
|
|
}
|
|
});
|
|
}
|
|
getTooltipContent(datumIndex) {
|
|
const { id: seriesId, dataModel, processedData, axes, properties } = this;
|
|
const { angleKey, angleName, radiusKey, radiusName, legendItemName, tooltip, marker } = properties;
|
|
const angleAxis = axes[ChartAxisDirection47.Angle];
|
|
const radiusAxis = axes[ChartAxisDirection47.Radius];
|
|
if (!dataModel || !processedData || !angleAxis || !radiusAxis)
|
|
return;
|
|
const datum = processedData.dataSources.get(this.id)?.data[datumIndex];
|
|
const angleValue = dataModel.resolveKeysById(this, `angleValue`, processedData)[datumIndex];
|
|
const radiusValue = dataModel.resolveColumnById(this, `radiusValue`, processedData)[datumIndex];
|
|
const allowNullKeys = this.properties.allowNullKeys ?? false;
|
|
if (angleValue === void 0 && !allowNullKeys)
|
|
return;
|
|
const activeStyle = this.getMarkerStyle(marker, { datum, datumIndex }, this.getDatumStylerProperties(datum), {
|
|
isHighlight: false
|
|
});
|
|
return this.formatTooltipWithContext(
|
|
tooltip,
|
|
{
|
|
heading: this.getAxisValueText(
|
|
angleAxis,
|
|
"tooltip",
|
|
angleValue,
|
|
datum,
|
|
angleKey,
|
|
void 0,
|
|
allowNullKeys
|
|
),
|
|
symbol: this.legendItemSymbol(),
|
|
data: [
|
|
{
|
|
label: radiusName,
|
|
fallbackLabel: radiusKey,
|
|
value: this.getAxisValueText(radiusAxis, "tooltip", radiusValue, datum, radiusKey, void 0),
|
|
missing: _ModuleSupport188.isTooltipValueMissing(radiusValue)
|
|
}
|
|
]
|
|
},
|
|
{
|
|
seriesId,
|
|
datum,
|
|
title: angleName,
|
|
angleKey,
|
|
radiusKey,
|
|
angleName,
|
|
radiusName,
|
|
legendItemName,
|
|
...activeStyle
|
|
}
|
|
);
|
|
}
|
|
legendItemSymbol() {
|
|
const { stroke: stroke3, strokeWidth, strokeOpacity, lineDash, marker } = this.getStyle();
|
|
const markerStyle = {
|
|
shape: marker.shape,
|
|
enabled: marker.enabled || strokeWidth <= 0,
|
|
fill: this.getMarkerFill() ?? marker.stroke ?? stroke3 ?? "rgba(0, 0, 0, 0)",
|
|
stroke: marker.stroke ?? stroke3 ?? "rgba(0, 0, 0, 0)",
|
|
fillOpacity: marker.fillOpacity,
|
|
strokeOpacity: marker.strokeOpacity,
|
|
strokeWidth: marker.strokeWidth,
|
|
lineDash: marker.lineDash,
|
|
lineDashOffset: marker.lineDashOffset
|
|
};
|
|
return {
|
|
marker: markerStyle,
|
|
line: {
|
|
enabled: true,
|
|
stroke: stroke3,
|
|
strokeOpacity,
|
|
strokeWidth,
|
|
lineDash
|
|
}
|
|
};
|
|
}
|
|
getLegendData(legendType) {
|
|
if (legendType !== "category") {
|
|
return [];
|
|
}
|
|
const {
|
|
id: seriesId,
|
|
ctx: { legendManager },
|
|
visible
|
|
} = this;
|
|
const { radiusKey, radiusName, legendItemName, showInLegend } = this.properties;
|
|
return [
|
|
{
|
|
legendType: "category",
|
|
id: seriesId,
|
|
itemId: radiusKey,
|
|
seriesId,
|
|
enabled: visible && legendManager.getItemEnabled({ seriesId, itemId: radiusKey }),
|
|
label: {
|
|
text: legendItemName ?? radiusName ?? radiusKey
|
|
},
|
|
symbol: this.legendItemSymbol(),
|
|
legendItemName,
|
|
hideInLegend: !showInLegend
|
|
}
|
|
];
|
|
}
|
|
pickNodeClosestDatum(hitPoint) {
|
|
const { nodeData, centerX: cx, centerY: cy } = this;
|
|
const { x, y } = hitPoint;
|
|
const radius = this.radius;
|
|
const distanceFromCenter = Math.hypot(x - cx, y - cy);
|
|
if (distanceFromCenter > radius + this.maxChartMarkerSize) {
|
|
return;
|
|
}
|
|
let minDistance = Infinity;
|
|
let closestDatum;
|
|
for (const datum of nodeData) {
|
|
const { point: { x: datumX = Number.NaN, y: datumY = Number.NaN } = {} } = datum;
|
|
if (Number.isNaN(datumX) || Number.isNaN(datumY)) {
|
|
continue;
|
|
}
|
|
const distance = Math.hypot(hitPoint.x - datumX - cx, hitPoint.y - datumY - cy);
|
|
if (distance < minDistance) {
|
|
minDistance = distance;
|
|
closestDatum = datum;
|
|
}
|
|
}
|
|
if (closestDatum) {
|
|
const distance = Math.max(minDistance - (closestDatum.point?.size ?? 0) / 2, 0);
|
|
return { datum: closestDatum, distance };
|
|
}
|
|
}
|
|
computeLabelsBBox() {
|
|
const { label } = this.properties;
|
|
this.maybeRefreshNodeData();
|
|
const textBoxes = [];
|
|
const tempText = new Text8();
|
|
for (const nodeDatum of this.nodeData) {
|
|
if (!label.enabled || !nodeDatum.label) {
|
|
continue;
|
|
}
|
|
tempText.text = nodeDatum.label.text;
|
|
tempText.x = nodeDatum.label.x;
|
|
tempText.y = nodeDatum.label.y;
|
|
tempText.setFont(label);
|
|
tempText.setAlign(nodeDatum.label);
|
|
const box = tempText.getBBox();
|
|
textBoxes.push(box);
|
|
}
|
|
if (textBoxes.length === 0) {
|
|
return null;
|
|
}
|
|
return BBox24.merge(textBoxes);
|
|
}
|
|
getLineNode() {
|
|
return this.lineSelection?.at(0);
|
|
}
|
|
beforePathAnimation() {
|
|
this.updatePathNodes();
|
|
}
|
|
getPathNodesStyle() {
|
|
const highlightDatum = this.ctx.highlightManager?.getActiveHighlight();
|
|
const highlightState = this.getHighlightState(highlightDatum);
|
|
const highlightStyle = this.getHighlightStyle(void 0, void 0, highlightState);
|
|
const stylerStyle = this.getStyle(highlightState);
|
|
return mergeDefaults20(highlightStyle, stylerStyle);
|
|
}
|
|
getLinePoints() {
|
|
const { nodeData, resetInvalidToZero } = this;
|
|
const { connectMissingData } = this.properties;
|
|
if (nodeData.length === 0) {
|
|
return [];
|
|
}
|
|
const radiusAxis = this.axes[ChartAxisDirection47.Radius];
|
|
const angleAxis = this.axes[ChartAxisDirection47.Angle];
|
|
const reversedAngleAxis = angleAxis?.isReversed();
|
|
const reversedRadiusAxis = radiusAxis?.isReversed();
|
|
const data = reversedRadiusAxis && !reversedAngleAxis ? [...nodeData].reverse() : nodeData;
|
|
const points = [];
|
|
let prevPointInvalid = false;
|
|
let firstValid;
|
|
for (const [index, datum] of data.entries()) {
|
|
let { x, y } = datum.point;
|
|
const isPointInvalid = Number.isNaN(x) || Number.isNaN(y);
|
|
if (!isPointInvalid) {
|
|
firstValid ?? (firstValid = datum);
|
|
}
|
|
if (isPointInvalid && !connectMissingData) {
|
|
x = 0;
|
|
y = 0;
|
|
}
|
|
const moveTo2 = index === 0 || !resetInvalidToZero && !connectMissingData && (isPointInvalid || prevPointInvalid);
|
|
points.push({ x, y, moveTo: moveTo2 });
|
|
prevPointInvalid = isPointInvalid;
|
|
}
|
|
if (firstValid !== void 0) {
|
|
points.push({ x: firstValid.point.x, y: firstValid.point.y, moveTo: false });
|
|
}
|
|
return points;
|
|
}
|
|
animateSinglePath(pathNode, points, ratio8) {
|
|
const { path } = pathNode;
|
|
path.clear(true);
|
|
const axisInnerRadius = this.getAxisInnerRadius();
|
|
const radiusAxis = this.axes[ChartAxisDirection47.Radius];
|
|
const reversedRadiusAxis = radiusAxis?.isReversed();
|
|
const radiusZero = reversedRadiusAxis ? this.radius + axisInnerRadius - radiusAxis?.scale.convert(0) : axisInnerRadius;
|
|
for (const point of points) {
|
|
const { x: x1, y: y1, arc, radius = 0, startAngle = 0, endAngle = 0, moveTo: moveTo2 } = point;
|
|
const angle = Math.atan2(y1, x1);
|
|
const x0 = radiusZero * Math.cos(angle);
|
|
const y0 = radiusZero * Math.sin(angle);
|
|
const t = ratio8;
|
|
const x = x0 * (1 - t) + x1 * t;
|
|
const y = y0 * (1 - t) + y1 * t;
|
|
if (arc) {
|
|
path.arc(x1, y1, radius, startAngle, endAngle);
|
|
} else if (moveTo2) {
|
|
path.moveTo(x, y);
|
|
} else {
|
|
path.lineTo(x, y);
|
|
}
|
|
}
|
|
pathNode.checkPathDirty();
|
|
}
|
|
animatePaths(ratio8) {
|
|
const linePoints = this.getLinePoints();
|
|
const lineNode = this.getLineNode();
|
|
if (!lineNode)
|
|
return;
|
|
this.animateSinglePath(lineNode, linePoints, ratio8);
|
|
}
|
|
animateEmptyUpdateReady() {
|
|
const { itemSelection, labelSelection } = this;
|
|
const { animationManager } = this.ctx;
|
|
this.beforePathAnimation();
|
|
animationManager.animate({
|
|
id: `${this.id}_'path`,
|
|
groupId: this.id,
|
|
from: 0,
|
|
to: 1,
|
|
phase: "initial",
|
|
collapsable: false,
|
|
onUpdate: (ratio8) => this.animatePaths(ratio8),
|
|
onStop: () => this.animatePaths(1)
|
|
});
|
|
markerFadeInAnimation2(this, animationManager, "added", this.getAnimationDrawingModes(), itemSelection);
|
|
seriesLabelFadeInAnimation7(this, "labels", animationManager, labelSelection, this.highlightLabelSelection);
|
|
}
|
|
animateWaitingUpdateReady(data) {
|
|
super.animateWaitingUpdateReady(data);
|
|
this.resetPaths();
|
|
}
|
|
animateReadyResize(data) {
|
|
super.animateReadyResize(data);
|
|
this.resetPaths();
|
|
}
|
|
resetPaths() {
|
|
const lineNode = this.getLineNode();
|
|
if (lineNode) {
|
|
const { path: linePath } = lineNode;
|
|
const linePoints = this.getLinePoints();
|
|
const stylerStyle = this.getStyle();
|
|
lineNode.fill = void 0;
|
|
lineNode.stroke = stylerStyle.stroke;
|
|
lineNode.strokeWidth = stylerStyle.strokeWidth;
|
|
lineNode.strokeOpacity = stylerStyle.strokeOpacity;
|
|
lineNode.lineDash = stylerStyle.lineDash;
|
|
lineNode.lineDashOffset = stylerStyle.lineDashOffset;
|
|
linePath.clear(true);
|
|
for (const { x, y, moveTo: moveTo2 } of linePoints) {
|
|
if (moveTo2) {
|
|
linePath.moveTo(x, y);
|
|
} else {
|
|
linePath.lineTo(x, y);
|
|
}
|
|
}
|
|
lineNode.checkPathDirty();
|
|
return stylerStyle;
|
|
}
|
|
}
|
|
getStylerResult(stylerResult, highlightState) {
|
|
const { styler } = this.properties;
|
|
if (styler) {
|
|
const stylerParams = this.makeStylerParams(highlightState);
|
|
const cbResult = this.cachedCallWithContext(styler, stylerParams) ?? {};
|
|
const resolved = this.ctx.optionsGraphService.resolvePartial(
|
|
["series", `${this.declarationOrder}`],
|
|
cbResult,
|
|
{ pick: false }
|
|
);
|
|
if (resolved) {
|
|
stylerResult = resolved;
|
|
}
|
|
}
|
|
return stylerResult;
|
|
}
|
|
getFormattedMarkerStyle(datum) {
|
|
const { angleKey, radiusKey } = this.properties;
|
|
return this.getMarkerStyle(this.properties.marker, datum, { angleKey, radiusKey }, { isHighlight: true });
|
|
}
|
|
computeFocusBounds(opts) {
|
|
return computeMarkerFocusBounds3(this, opts);
|
|
}
|
|
hasItemStylers() {
|
|
return this.properties.styler != null || this.properties.marker.itemStyler != null || this.properties.label.itemStyler != null;
|
|
}
|
|
};
|
|
RadarSeries.className = "RadarSeries";
|
|
|
|
// packages/ag-charts-enterprise/src/series/radar-area/radarAreaSeriesProperties.ts
|
|
import "ag-charts-community";
|
|
import { Property as Property83 } from "ag-charts-core";
|
|
var RadarAreaSeriesProperties = class extends RadarSeriesProperties {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.fill = "black";
|
|
this.fillOpacity = 1;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property83
|
|
], RadarAreaSeriesProperties.prototype, "fill", 2);
|
|
__decorateClass([
|
|
Property83
|
|
], RadarAreaSeriesProperties.prototype, "fillOpacity", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/series/radar-area/radarAreaSeries.ts
|
|
var { Group: Group19, HighlightState: HighlightState5, Path: Path13, PointerEvents: PointerEvents10, Selection: Selection15, toHighlightString: toHighlightString5 } = _ModuleSupport189;
|
|
var RadarAreaSeries = class extends RadarSeries {
|
|
constructor(moduleCtx) {
|
|
super(moduleCtx);
|
|
this.properties = new RadarAreaSeriesProperties();
|
|
this.areaGroup = this.contentGroup.appendChild(new Group19({ name: "radar-area" }));
|
|
this.areaSelection = Selection15.select(
|
|
this.areaGroup,
|
|
Path13
|
|
);
|
|
this.resetInvalidToZero = true;
|
|
this.areaGroup.zIndex = -1;
|
|
}
|
|
updatePathSelections() {
|
|
const pathData = this.visible ? [true] : [];
|
|
this.areaSelection.update(pathData);
|
|
super.updatePathSelections();
|
|
}
|
|
getAreaNode() {
|
|
return this.areaSelection.at(0);
|
|
}
|
|
getMarkerFill(highlightedStyle) {
|
|
if (highlightedStyle?.fill != null)
|
|
return highlightedStyle.fill;
|
|
const stylerStyle = this.getStyle();
|
|
return stylerStyle.marker.fill ?? stylerStyle.fill;
|
|
}
|
|
updatePathNodes() {
|
|
const styles = this.getPathNodesStyle();
|
|
const { fill, fillOpacity, strokeWidth, stroke: stroke3, strokeOpacity, lineDash, lineDashOffset, opacity } = styles;
|
|
const lineNode = this.getLineNode();
|
|
if (lineNode) {
|
|
lineNode.setProperties({
|
|
fill: void 0,
|
|
lineJoin: "round",
|
|
lineCap: "round",
|
|
pointerEvents: PointerEvents10.None,
|
|
opacity,
|
|
stroke: stroke3,
|
|
strokeWidth,
|
|
strokeOpacity,
|
|
lineDash,
|
|
lineDashOffset
|
|
});
|
|
}
|
|
const areaNode = this.getAreaNode();
|
|
if (areaNode) {
|
|
areaNode.setStyleProperties({ fill, fillOpacity, stroke: void 0 }, this.getShapeFillBBox());
|
|
areaNode.setProperties({
|
|
lineJoin: "round",
|
|
pointerEvents: PointerEvents10.None,
|
|
opacity
|
|
});
|
|
}
|
|
}
|
|
animatePaths(ratio8) {
|
|
super.animatePaths(ratio8);
|
|
const areaNode = this.getAreaNode();
|
|
if (areaNode) {
|
|
this.animateSinglePath(areaNode, this.getAreaPoints(), ratio8);
|
|
}
|
|
}
|
|
getAreaPoints() {
|
|
const points = this.getLinePoints();
|
|
const getPolarAxis = (direction) => {
|
|
const axis = this.axes[direction];
|
|
return axis instanceof _ModuleSupport189.PolarAxis ? axis : void 0;
|
|
};
|
|
const radiusAxis = getPolarAxis(ChartAxisDirection48.Radius);
|
|
const angleAxis = getPolarAxis(ChartAxisDirection48.Angle);
|
|
const reversedRadiusAxis = radiusAxis?.isReversed();
|
|
if (!reversedRadiusAxis) {
|
|
return points;
|
|
}
|
|
const zeroLinePoints = angleAxis?.getAxisLinePoints()?.points ?? [];
|
|
return points.concat(...zeroLinePoints);
|
|
}
|
|
resetPaths() {
|
|
const superStyle = super.resetPaths();
|
|
const areaNode = this.getAreaNode();
|
|
if (areaNode) {
|
|
const { path: areaPath } = areaNode;
|
|
const areaPoints = this.getAreaPoints();
|
|
const stylerStyle = superStyle ?? this.getStyle();
|
|
const fillBBox = this.getShapeFillBBox();
|
|
areaNode.setStyleProperties(
|
|
{
|
|
fill: stylerStyle.fill,
|
|
stroke: void 0,
|
|
fillOpacity: stylerStyle.fillOpacity,
|
|
lineDash: stylerStyle.lineDash,
|
|
lineDashOffset: stylerStyle.lineDashOffset
|
|
},
|
|
fillBBox
|
|
);
|
|
areaNode.lineJoin = areaNode.lineCap = "round";
|
|
areaPath.clear(true);
|
|
for (const { x, y, moveTo: moveTo2, arc, radius = 0, startAngle = 0, endAngle = 0 } of areaPoints) {
|
|
if (arc) {
|
|
areaPath.arc(x, y, radius, startAngle, endAngle);
|
|
} else if (moveTo2) {
|
|
areaPath.moveTo(x, y);
|
|
} else {
|
|
areaPath.lineTo(x, y);
|
|
}
|
|
}
|
|
areaPath.closePath();
|
|
areaNode.checkPathDirty();
|
|
return stylerStyle;
|
|
}
|
|
}
|
|
makeStylerParams(highlightStateEnum) {
|
|
const { properties } = this;
|
|
const highlightState = toHighlightString5(highlightStateEnum ?? HighlightState5.None);
|
|
return {
|
|
marker: {
|
|
fill: properties.marker.fill,
|
|
fillOpacity: properties.marker.fillOpacity,
|
|
size: properties.marker.size,
|
|
shape: properties.marker.shape,
|
|
stroke: properties.marker.stroke,
|
|
strokeOpacity: properties.marker.strokeOpacity,
|
|
strokeWidth: properties.marker.strokeWidth,
|
|
lineDash: properties.marker.lineDash,
|
|
lineDashOffset: properties.marker.lineDashOffset
|
|
},
|
|
highlightState,
|
|
fill: properties.fill,
|
|
fillOpacity: properties.fillOpacity,
|
|
lineDash: properties.lineDash,
|
|
lineDashOffset: properties.lineDashOffset,
|
|
seriesId: this.id,
|
|
stroke: properties.stroke,
|
|
strokeOpacity: properties.strokeOpacity,
|
|
strokeWidth: properties.strokeWidth,
|
|
angleKey: properties.angleKey,
|
|
radiusKey: properties.radiusKey
|
|
};
|
|
}
|
|
getStyle(highlightState) {
|
|
const { marker, fill, fillOpacity, lineDash, lineDashOffset, stroke: stroke3, strokeOpacity, strokeWidth } = this.properties;
|
|
const { size, shape, fill: markerFill = "transparent", fillOpacity: markerFillOpacity } = marker;
|
|
const stylerResult = this.getStylerResult({}, highlightState);
|
|
stylerResult.marker ?? (stylerResult.marker = {});
|
|
return {
|
|
fill: stylerResult.fill ?? fill,
|
|
fillOpacity: stylerResult.fillOpacity ?? fillOpacity,
|
|
lineDash: stylerResult.lineDash ?? lineDash,
|
|
lineDashOffset: stylerResult.lineDashOffset ?? lineDashOffset,
|
|
stroke: stylerResult.stroke ?? stroke3,
|
|
strokeOpacity: stylerResult.strokeOpacity ?? strokeOpacity,
|
|
strokeWidth: stylerResult.strokeWidth ?? strokeWidth,
|
|
marker: {
|
|
enabled: stylerResult.marker.enabled ?? marker.enabled,
|
|
fill: stylerResult.marker.fill ?? markerFill,
|
|
fillOpacity: stylerResult.marker.fillOpacity ?? markerFillOpacity,
|
|
shape: stylerResult.marker.shape ?? shape,
|
|
size: stylerResult.marker.size ?? size,
|
|
lineDash: stylerResult.marker.lineDash ?? marker.lineDash ?? lineDash,
|
|
lineDashOffset: stylerResult.marker.lineDashOffset ?? marker.lineDashOffset ?? lineDashOffset,
|
|
stroke: stylerResult.marker.stroke ?? marker.stroke ?? stroke3,
|
|
strokeOpacity: stylerResult.marker.strokeOpacity ?? marker.strokeOpacity ?? strokeOpacity,
|
|
strokeWidth: stylerResult.marker.strokeWidth ?? marker.strokeWidth ?? strokeWidth
|
|
}
|
|
};
|
|
}
|
|
};
|
|
RadarAreaSeries.className = "RadarAreaSeries";
|
|
RadarAreaSeries.type = "radar-area";
|
|
|
|
// packages/ag-charts-enterprise/src/series/radar-area/radarAreaSeriesOptionsDef.ts
|
|
import { _ModuleSupport as _ModuleSupport190 } from "ag-charts-community";
|
|
import { commonSeriesOptionsDefs as commonSeriesOptionsDefs17, constant as constant18, required as required18, string as string18, undocumented as undocumented13 } from "ag-charts-core";
|
|
var { radarAreaSeriesThemeableOptionsDef } = _ModuleSupport190;
|
|
var radarAreaSeriesOptionsDef = {
|
|
...commonSeriesOptionsDefs17,
|
|
...radarAreaSeriesThemeableOptionsDef,
|
|
type: required18(constant18("radar-area")),
|
|
angleKey: required18(string18),
|
|
radiusKey: required18(string18),
|
|
angleName: string18,
|
|
radiusName: string18,
|
|
legendItemName: string18
|
|
};
|
|
radarAreaSeriesOptionsDef.angleKeyAxis = undocumented13(string18);
|
|
radarAreaSeriesOptionsDef.radiusKeyAxis = undocumented13(string18);
|
|
|
|
// packages/ag-charts-enterprise/src/series/radar-area/radarAreaModule.ts
|
|
var RadarAreaSeriesModule = {
|
|
type: "series",
|
|
name: "radar-area",
|
|
chartType: "polar",
|
|
enterprise: true,
|
|
version: VERSION43,
|
|
dependencies: [PolarChartModule2],
|
|
options: radarAreaSeriesOptionsDef,
|
|
defaultAxes: { angle: { type: POLAR_AXIS_TYPE4.ANGLE_CATEGORY }, radius: { type: POLAR_AXIS_TYPE4.RADIUS_NUMBER } },
|
|
axisKeys: { [ChartAxisDirection49.Angle]: "angleKeyAxis", [ChartAxisDirection49.Radius]: "radiusKeyAxis" },
|
|
themeTemplate: RADAR_AREA_SERIES_THEME,
|
|
create: (ctx) => new RadarAreaSeries(ctx)
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/series/radar-line/radarLineModule.ts
|
|
import { PolarChartModule as PolarChartModule3, VERSION as VERSION44 } from "ag-charts-community";
|
|
import { ChartAxisDirection as ChartAxisDirection50, POLAR_AXIS_TYPE as POLAR_AXIS_TYPE5 } from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/series/radar-line/radarLineSeries.ts
|
|
import {
|
|
_ModuleSupport as _ModuleSupport191
|
|
} from "ag-charts-community";
|
|
var { HighlightState: HighlightState6, PointerEvents: PointerEvents11, toHighlightString: toHighlightString6 } = _ModuleSupport191;
|
|
var RadarLineSeries = class extends RadarSeries {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.properties = new RadarSeriesProperties();
|
|
}
|
|
updatePathSelections() {
|
|
this.lineSelection.update(this.visible ? [true] : []);
|
|
}
|
|
updatePathNodes() {
|
|
const lineNode = this.getLineNode();
|
|
if (!lineNode)
|
|
return;
|
|
const style = this.getPathNodesStyle();
|
|
const { strokeWidth, stroke: stroke3, strokeOpacity, lineDash, lineDashOffset, opacity } = style;
|
|
lineNode.setProperties({
|
|
fill: void 0,
|
|
lineJoin: "round",
|
|
lineCap: "round",
|
|
pointerEvents: PointerEvents11.None,
|
|
opacity,
|
|
stroke: stroke3,
|
|
strokeWidth,
|
|
strokeOpacity,
|
|
lineDash,
|
|
lineDashOffset
|
|
});
|
|
}
|
|
makeStylerParams(highlightStateEnum) {
|
|
const { properties } = this;
|
|
const highlightState = toHighlightString6(highlightStateEnum ?? HighlightState6.None);
|
|
return {
|
|
marker: {
|
|
fill: properties.marker.fill,
|
|
fillOpacity: properties.marker.fillOpacity,
|
|
size: properties.marker.size,
|
|
shape: properties.marker.shape,
|
|
stroke: properties.marker.stroke,
|
|
strokeOpacity: properties.marker.strokeOpacity,
|
|
strokeWidth: properties.marker.strokeWidth,
|
|
lineDash: properties.marker.lineDash,
|
|
lineDashOffset: properties.marker.lineDashOffset
|
|
},
|
|
highlightState,
|
|
lineDash: properties.lineDash,
|
|
lineDashOffset: properties.lineDashOffset,
|
|
seriesId: this.id,
|
|
stroke: properties.stroke,
|
|
strokeOpacity: properties.strokeOpacity,
|
|
strokeWidth: properties.strokeWidth,
|
|
angleKey: properties.angleKey,
|
|
radiusKey: properties.radiusKey
|
|
};
|
|
}
|
|
getStyle(highlightState) {
|
|
const { marker, lineDash, lineDashOffset, stroke: stroke3, strokeOpacity, strokeWidth } = this.properties;
|
|
const { size, shape, fill = "transparent", fillOpacity } = marker;
|
|
const stylerResult = this.getStylerResult({}, highlightState);
|
|
stylerResult.marker ?? (stylerResult.marker = {});
|
|
return {
|
|
lineDash: stylerResult.lineDash ?? lineDash,
|
|
lineDashOffset: stylerResult.lineDashOffset ?? lineDashOffset,
|
|
stroke: stylerResult.stroke ?? stroke3,
|
|
strokeOpacity: stylerResult.strokeOpacity ?? strokeOpacity,
|
|
strokeWidth: stylerResult.strokeWidth ?? strokeWidth,
|
|
marker: {
|
|
enabled: stylerResult.marker.enabled ?? marker.enabled,
|
|
fill: stylerResult.marker.fill ?? fill,
|
|
fillOpacity: stylerResult.marker.fillOpacity ?? fillOpacity,
|
|
shape: stylerResult.marker.shape ?? shape,
|
|
size: stylerResult.marker.size ?? size,
|
|
lineDash: stylerResult.marker.lineDash ?? marker.lineDash ?? lineDash,
|
|
lineDashOffset: stylerResult.marker.lineDashOffset ?? marker.lineDashOffset ?? lineDashOffset,
|
|
stroke: stylerResult.marker.stroke ?? marker.stroke ?? stroke3,
|
|
strokeOpacity: stylerResult.marker.strokeOpacity ?? marker.strokeOpacity ?? strokeOpacity,
|
|
strokeWidth: stylerResult.marker.strokeWidth ?? marker.strokeWidth ?? strokeWidth
|
|
}
|
|
};
|
|
}
|
|
};
|
|
RadarLineSeries.className = "RadarLineSeries";
|
|
RadarLineSeries.type = "radar-line";
|
|
|
|
// packages/ag-charts-enterprise/src/series/radar-line/radarLineSeriesOptionsDef.ts
|
|
import { _ModuleSupport as _ModuleSupport192 } from "ag-charts-community";
|
|
import { commonSeriesOptionsDefs as commonSeriesOptionsDefs18, constant as constant19, required as required19, string as string19, undocumented as undocumented14 } from "ag-charts-core";
|
|
var { radarLineSeriesThemeableOptionsDef } = _ModuleSupport192;
|
|
var radarLineSeriesOptionsDef = {
|
|
...commonSeriesOptionsDefs18,
|
|
...radarLineSeriesThemeableOptionsDef,
|
|
type: required19(constant19("radar-line")),
|
|
angleKey: required19(string19),
|
|
radiusKey: required19(string19),
|
|
angleName: string19,
|
|
radiusName: string19,
|
|
legendItemName: string19
|
|
};
|
|
radarLineSeriesOptionsDef.angleKeyAxis = undocumented14(string19);
|
|
radarLineSeriesOptionsDef.radiusKeyAxis = undocumented14(string19);
|
|
|
|
// packages/ag-charts-enterprise/src/series/radar-line/radarLineModule.ts
|
|
var RadarLineSeriesModule = {
|
|
type: "series",
|
|
name: "radar-line",
|
|
chartType: "polar",
|
|
enterprise: true,
|
|
version: VERSION44,
|
|
dependencies: [PolarChartModule3],
|
|
options: radarLineSeriesOptionsDef,
|
|
defaultAxes: { angle: { type: POLAR_AXIS_TYPE5.ANGLE_CATEGORY }, radius: { type: POLAR_AXIS_TYPE5.RADIUS_NUMBER } },
|
|
axisKeys: { [ChartAxisDirection50.Angle]: "angleKeyAxis", [ChartAxisDirection50.Radius]: "radiusKeyAxis" },
|
|
themeTemplate: RADAR_LINE_SERIES_THEME,
|
|
create: (ctx) => new RadarLineSeries(ctx)
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/series/radial-bar/radialBarModule.ts
|
|
import { PolarChartModule as PolarChartModule4, VERSION as VERSION45 } from "ag-charts-community";
|
|
import { ChartAxisDirection as ChartAxisDirection52, POLAR_AXIS_TYPE as POLAR_AXIS_TYPE7 } from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/series/radial-bar/radialBarSeries.ts
|
|
import {
|
|
_ModuleSupport as _ModuleSupport195
|
|
} from "ag-charts-community";
|
|
import {
|
|
ChartAxisDirection as ChartAxisDirection51,
|
|
angleBetween as angleBetween3,
|
|
isDefined as isDefined4,
|
|
isGradientFill as isGradientFill3
|
|
} from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/series/radial-bar/radialBarSeriesProperties.ts
|
|
import { _ModuleSupport as _ModuleSupport193 } from "ag-charts-community";
|
|
import { Property as Property84 } from "ag-charts-core";
|
|
var { SeriesProperties: SeriesProperties11, makeSeriesTooltip: makeSeriesTooltip20, Label: Label15 } = _ModuleSupport193;
|
|
var RadialBarSeriesProperties = class extends SeriesProperties11 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.angleKeyAxis = "angle";
|
|
this.radiusKeyAxis = "radius";
|
|
this.fill = "black";
|
|
this.fillOpacity = 1;
|
|
this.stroke = "black";
|
|
this.strokeWidth = 1;
|
|
this.strokeOpacity = 1;
|
|
this.lineDash = [0];
|
|
this.lineDashOffset = 0;
|
|
this.cornerRadius = 0;
|
|
this.rotation = 0;
|
|
this.label = new Label15();
|
|
this.tooltip = makeSeriesTooltip20();
|
|
}
|
|
getStyle() {
|
|
const { fill, fillOpacity, stroke: stroke3, strokeWidth, strokeOpacity, lineDash, lineDashOffset, cornerRadius } = this;
|
|
return {
|
|
fill,
|
|
fillOpacity,
|
|
stroke: stroke3,
|
|
strokeWidth,
|
|
strokeOpacity,
|
|
lineDash,
|
|
lineDashOffset,
|
|
cornerRadius,
|
|
opacity: 1
|
|
};
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property84
|
|
], RadialBarSeriesProperties.prototype, "angleKey", 2);
|
|
__decorateClass([
|
|
Property84
|
|
], RadialBarSeriesProperties.prototype, "radiusKey", 2);
|
|
__decorateClass([
|
|
Property84
|
|
], RadialBarSeriesProperties.prototype, "angleName", 2);
|
|
__decorateClass([
|
|
Property84
|
|
], RadialBarSeriesProperties.prototype, "radiusName", 2);
|
|
__decorateClass([
|
|
Property84
|
|
], RadialBarSeriesProperties.prototype, "angleKeyAxis", 2);
|
|
__decorateClass([
|
|
Property84
|
|
], RadialBarSeriesProperties.prototype, "radiusKeyAxis", 2);
|
|
__decorateClass([
|
|
Property84
|
|
], RadialBarSeriesProperties.prototype, "legendItemName", 2);
|
|
__decorateClass([
|
|
Property84
|
|
], RadialBarSeriesProperties.prototype, "fill", 2);
|
|
__decorateClass([
|
|
Property84
|
|
], RadialBarSeriesProperties.prototype, "fillOpacity", 2);
|
|
__decorateClass([
|
|
Property84
|
|
], RadialBarSeriesProperties.prototype, "stroke", 2);
|
|
__decorateClass([
|
|
Property84
|
|
], RadialBarSeriesProperties.prototype, "strokeWidth", 2);
|
|
__decorateClass([
|
|
Property84
|
|
], RadialBarSeriesProperties.prototype, "strokeOpacity", 2);
|
|
__decorateClass([
|
|
Property84
|
|
], RadialBarSeriesProperties.prototype, "lineDash", 2);
|
|
__decorateClass([
|
|
Property84
|
|
], RadialBarSeriesProperties.prototype, "lineDashOffset", 2);
|
|
__decorateClass([
|
|
Property84
|
|
], RadialBarSeriesProperties.prototype, "cornerRadius", 2);
|
|
__decorateClass([
|
|
Property84
|
|
], RadialBarSeriesProperties.prototype, "styler", 2);
|
|
__decorateClass([
|
|
Property84
|
|
], RadialBarSeriesProperties.prototype, "itemStyler", 2);
|
|
__decorateClass([
|
|
Property84
|
|
], RadialBarSeriesProperties.prototype, "rotation", 2);
|
|
__decorateClass([
|
|
Property84
|
|
], RadialBarSeriesProperties.prototype, "stackGroup", 2);
|
|
__decorateClass([
|
|
Property84
|
|
], RadialBarSeriesProperties.prototype, "normalizedTo", 2);
|
|
__decorateClass([
|
|
Property84
|
|
], RadialBarSeriesProperties.prototype, "label", 2);
|
|
__decorateClass([
|
|
Property84
|
|
], RadialBarSeriesProperties.prototype, "tooltip", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/series/radial-bar/radialBarUtil.ts
|
|
import { _ModuleSupport as _ModuleSupport194 } from "ag-charts-community";
|
|
var { SectorBox: SectorBox3, motion: motion9 } = _ModuleSupport194;
|
|
function fixRadialBarAnimationStatus(node, datum, status) {
|
|
if (status === "updated") {
|
|
if (node.previousDatum == null || Number.isNaN(node.previousDatum.innerRadius) || Number.isNaN(node.previousDatum.outerRadius)) {
|
|
return "added";
|
|
}
|
|
if (Number.isNaN(datum.innerRadius) || Number.isNaN(datum.outerRadius)) {
|
|
return "removed";
|
|
}
|
|
}
|
|
if (status === "added" && node.previousDatum != null) {
|
|
return "updated";
|
|
}
|
|
return status;
|
|
}
|
|
function prepareRadialBarSeriesAnimationFunctions(axisZeroAngle) {
|
|
const fromFn = (sect, datum, status) => {
|
|
status = fixRadialBarAnimationStatus(sect, datum, status);
|
|
let startAngle;
|
|
let endAngle;
|
|
let innerRadius;
|
|
let outerRadius;
|
|
let clipSector;
|
|
if (status === "removed" || status === "updated") {
|
|
startAngle = sect.startAngle;
|
|
endAngle = sect.endAngle;
|
|
innerRadius = sect.innerRadius;
|
|
outerRadius = sect.outerRadius;
|
|
clipSector = sect.clipSector;
|
|
} else {
|
|
startAngle = axisZeroAngle;
|
|
endAngle = axisZeroAngle;
|
|
innerRadius = datum.innerRadius;
|
|
outerRadius = datum.outerRadius;
|
|
}
|
|
clipSector ?? (clipSector = new SectorBox3(startAngle, endAngle, innerRadius, outerRadius));
|
|
const phase = motion9.NODE_UPDATE_STATE_TO_PHASE_MAPPING[status];
|
|
return { startAngle, endAngle, innerRadius, outerRadius, clipSector, phase };
|
|
};
|
|
const toFn = (sect, datum, status) => {
|
|
let startAngle;
|
|
let endAngle;
|
|
let innerRadius;
|
|
let outerRadius;
|
|
let clipSector;
|
|
if (status === "removed") {
|
|
startAngle = axisZeroAngle;
|
|
endAngle = axisZeroAngle;
|
|
innerRadius = datum.innerRadius;
|
|
outerRadius = datum.outerRadius;
|
|
clipSector = new SectorBox3(startAngle, endAngle, innerRadius, outerRadius);
|
|
} else {
|
|
startAngle = datum.startAngle;
|
|
endAngle = datum.endAngle;
|
|
innerRadius = Number.isNaN(datum.innerRadius) ? sect.innerRadius : datum.innerRadius;
|
|
outerRadius = Number.isNaN(datum.outerRadius) ? sect.outerRadius : datum.outerRadius;
|
|
clipSector = datum.clipSector;
|
|
}
|
|
return { startAngle, endAngle, innerRadius, outerRadius, clipSector };
|
|
};
|
|
return { toFn, fromFn };
|
|
}
|
|
function resetRadialBarSelectionsFn(_node, datum) {
|
|
return {
|
|
centerX: 0,
|
|
centerY: 0,
|
|
innerRadius: datum.innerRadius,
|
|
outerRadius: datum.outerRadius,
|
|
startAngle: datum.startAngle,
|
|
endAngle: datum.endAngle,
|
|
clipSector: datum.clipSector
|
|
};
|
|
}
|
|
|
|
// packages/ag-charts-enterprise/src/series/radial-bar/radialBarSeries.ts
|
|
var {
|
|
DEFAULT_POLAR_DIRECTION_KEYS: DEFAULT_POLAR_DIRECTION_KEYS3,
|
|
DEFAULT_POLAR_DIRECTION_NAMES: DEFAULT_POLAR_DIRECTION_NAMES3,
|
|
PolarAxis: PolarAxis3,
|
|
diff: diff7,
|
|
groupAccumulativeValueProperty: groupAccumulativeValueProperty3,
|
|
keyProperty: keyProperty11,
|
|
normaliseGroupTo: normaliseGroupTo2,
|
|
valueProperty: valueProperty17,
|
|
fixNumericExtent: fixNumericExtent10,
|
|
resetLabelFn: resetLabelFn7,
|
|
seriesLabelFadeInAnimation: seriesLabelFadeInAnimation8,
|
|
seriesLabelFadeOutAnimation: seriesLabelFadeOutAnimation2,
|
|
animationValidation: animationValidation9,
|
|
createDatumId: createDatumId19,
|
|
CategoryScale: CategoryScale4,
|
|
Sector: Sector5,
|
|
SectorBox: SectorBox4,
|
|
motion: motion10,
|
|
updateLabelNode: updateLabelNode8,
|
|
getItemStyles: getItemStyles4
|
|
} = _ModuleSupport195;
|
|
var RadialBarSeriesNodeEvent = class extends _ModuleSupport195.SeriesNodeEvent {
|
|
constructor(type, nativeEvent, datum, series) {
|
|
super(type, nativeEvent, datum, series);
|
|
this.angleKey = series.properties.angleKey;
|
|
this.radiusKey = series.properties.radiusKey;
|
|
}
|
|
};
|
|
var RadialBarSeries = class extends _ModuleSupport195.PolarSeries {
|
|
constructor(moduleCtx) {
|
|
super({
|
|
moduleCtx,
|
|
categoryKey: "radiusValue",
|
|
propertyKeys: DEFAULT_POLAR_DIRECTION_KEYS3,
|
|
propertyNames: DEFAULT_POLAR_DIRECTION_NAMES3,
|
|
canHaveAxes: true,
|
|
animationResetFns: {
|
|
item: resetRadialBarSelectionsFn,
|
|
label: resetLabelFn7
|
|
}
|
|
});
|
|
this.properties = new RadialBarSeriesProperties();
|
|
this.NodeEvent = RadialBarSeriesNodeEvent;
|
|
this.groupScale = new CategoryScale4();
|
|
this.circleCache = { r: 0, cx: 0, cy: 0 };
|
|
}
|
|
nodeFactory() {
|
|
return new Sector5();
|
|
}
|
|
getSeriesDomain(direction) {
|
|
const { dataModel, processedData } = this;
|
|
if (!processedData || !dataModel)
|
|
return { domain: [] };
|
|
if (direction === ChartAxisDirection51.Angle) {
|
|
const xExtent = dataModel.getDomain(this, "angleValue-end", "value", processedData).domain;
|
|
const fixedXExtent = [Math.min(xExtent[0], 0), Math.max(xExtent[1], 0)];
|
|
return { domain: fixNumericExtent10(fixedXExtent) };
|
|
} else {
|
|
return dataModel.getDomain(this, "radiusValue", "key", processedData);
|
|
}
|
|
}
|
|
async processData(dataController) {
|
|
const { angleKey, radiusKey, normalizedTo } = this.properties;
|
|
const animationEnabled = !this.ctx.animationManager.isSkipped();
|
|
const stackGroupId = this.getStackId();
|
|
const stackGroupTrailingId = `${stackGroupId}-trailing`;
|
|
const extraProps = [];
|
|
if (isDefined4(normalizedTo)) {
|
|
extraProps.push(normaliseGroupTo2([stackGroupId, stackGroupTrailingId], Math.abs(normalizedTo)));
|
|
}
|
|
if (this.needsDataModelDiff() && this.processedData) {
|
|
extraProps.push(diff7(this.id, this.processedData));
|
|
}
|
|
if (animationEnabled) {
|
|
extraProps.push(animationValidation9());
|
|
}
|
|
const visibleProps = this.visible ? {} : { forceValue: 0 };
|
|
const radiusScaleType = this.axes[ChartAxisDirection51.Radius]?.scale.type;
|
|
const angleScaleType = this.axes[ChartAxisDirection51.Angle]?.scale.type;
|
|
const allowNullKey = this.properties.allowNullKeys ?? false;
|
|
await this.requestDataModel(dataController, this.data, {
|
|
props: [
|
|
keyProperty11(radiusKey, radiusScaleType, { id: "radiusValue", allowNullKey }),
|
|
valueProperty17(angleKey, angleScaleType, {
|
|
id: "angleValue-raw",
|
|
invalidValue: null,
|
|
...visibleProps
|
|
}),
|
|
...groupAccumulativeValueProperty3(
|
|
angleKey,
|
|
"normal",
|
|
{
|
|
id: `angleValue-end`,
|
|
rangeId: `angleValue-range`,
|
|
invalidValue: null,
|
|
groupId: stackGroupId,
|
|
separateNegative: true,
|
|
...visibleProps
|
|
},
|
|
angleScaleType
|
|
),
|
|
...groupAccumulativeValueProperty3(
|
|
angleKey,
|
|
"trailing",
|
|
{
|
|
id: `angleValue-start`,
|
|
invalidValue: null,
|
|
groupId: stackGroupTrailingId,
|
|
separateNegative: true,
|
|
...visibleProps
|
|
},
|
|
angleScaleType
|
|
),
|
|
...extraProps
|
|
],
|
|
groupByKeys: true,
|
|
groupByData: false
|
|
});
|
|
this.animationState.transition("updateData");
|
|
}
|
|
didCircleChange() {
|
|
const r = this.radius;
|
|
const cx = this.centerX;
|
|
const cy = this.centerY;
|
|
const cache = this.circleCache;
|
|
if (!(r === cache.r && cx === cache.cx && cy === cache.cy)) {
|
|
this.circleCache = { r, cx, cy };
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
maybeRefreshNodeData() {
|
|
const circleChanged = this.didCircleChange();
|
|
if (!circleChanged && !this.nodeDataRefresh)
|
|
return;
|
|
this.contextNodeData = this.createNodeData();
|
|
this.nodeData = this.contextNodeData?.nodeData ?? [];
|
|
this.nodeDataRefresh = false;
|
|
}
|
|
getAxisInnerRadius() {
|
|
const radiusAxis = this.axes[ChartAxisDirection51.Radius];
|
|
return radiusAxis instanceof PolarAxis3 ? this.radius * radiusAxis.innerRadiusRatio : 0;
|
|
}
|
|
createNodeData() {
|
|
const { processedData, dataModel } = this;
|
|
if (!dataModel || processedData?.type !== "grouped")
|
|
return;
|
|
const angleAxis = this.axes[ChartAxisDirection51.Angle];
|
|
const radiusAxis = this.axes[ChartAxisDirection51.Radius];
|
|
const angleScale = angleAxis?.scale;
|
|
const radiusScale = radiusAxis?.scale;
|
|
if (!angleScale || !radiusScale) {
|
|
return;
|
|
}
|
|
const radiusValues = dataModel.resolveKeysById(this, "radiusValue", processedData);
|
|
const angleStartValues = dataModel.resolveColumnById(this, `angleValue-start`, processedData);
|
|
const angleEndValues = dataModel.resolveColumnById(this, `angleValue-end`, processedData);
|
|
const angleRawValues = dataModel.resolveColumnById(this, `angleValue-raw`, processedData);
|
|
const angleRangeIndex = dataModel.resolveProcessedDataIndexById(this, `angleValue-range`);
|
|
let groupPaddingInner = 0;
|
|
if (radiusAxis instanceof RadiusCategoryAxis) {
|
|
groupPaddingInner = radiusAxis.groupPaddingInner;
|
|
}
|
|
const { groupScale } = this;
|
|
const { index: groupIndex, visibleGroupCount } = this.ctx.seriesStateManager.getVisiblePeerGroupIndex(this);
|
|
groupScale.domain = Array.from({ length: visibleGroupCount }).map((_, i) => String(i));
|
|
groupScale.range = [0, Math.abs(radiusScale.bandwidth ?? 0)];
|
|
groupScale.paddingInner = visibleGroupCount > 1 ? groupPaddingInner : 0;
|
|
const barWidth = groupScale.bandwidth >= 1 ? groupScale.bandwidth : groupScale.rawBandwidth;
|
|
const angleAxisReversed = angleAxis.isReversed();
|
|
const radiusAxisReversed = radiusAxis.isReversed();
|
|
const axisInnerRadius = radiusAxisReversed ? this.radius : this.getAxisInnerRadius();
|
|
const axisOuterRadius = radiusAxisReversed ? this.getAxisInnerRadius() : this.radius;
|
|
const axisTotalRadius = axisOuterRadius + axisInnerRadius;
|
|
const angleDomain = this.getSeriesDomain(ChartAxisDirection51.Angle).domain;
|
|
const { angleKey, radiusKey, angleName, radiusName, legendItemName, label } = this.properties;
|
|
const getLabelNodeDatum = (datum, angleDatum, x, y) => {
|
|
const labelText = this.getLabelText(
|
|
angleDatum,
|
|
datum,
|
|
angleKey,
|
|
"angle",
|
|
angleDomain,
|
|
label,
|
|
{ value: angleDatum, datum, angleKey, radiusKey, angleName, radiusName, legendItemName }
|
|
);
|
|
if (labelText) {
|
|
return { x, y, text: labelText, textAlign: "center", textBaseline: "middle" };
|
|
}
|
|
};
|
|
const nodeData = [];
|
|
const styles = getItemStyles4(
|
|
(nodeDatum, isHighlight, highlightState) => getItemStyle(this, nodeDatum, isHighlight, highlightState)
|
|
);
|
|
const context = {
|
|
itemId: radiusKey,
|
|
nodeData,
|
|
labelData: nodeData,
|
|
styles
|
|
};
|
|
if (!this.visible)
|
|
return context;
|
|
const { dataSources } = processedData;
|
|
const rawData = dataSources.get(this.id)?.data ?? [];
|
|
for (const { datumIndex, group } of dataModel.forEachGroupDatum(this, processedData)) {
|
|
const datum = rawData[datumIndex];
|
|
const radiusDatum = radiusValues[datumIndex];
|
|
if (radiusDatum === void 0 && !this.properties.allowNullKeys)
|
|
return;
|
|
const angleDatum = angleRawValues[datumIndex];
|
|
const angleStartDatum = angleStartValues[datumIndex];
|
|
const angleEndDatum = angleEndValues[datumIndex];
|
|
const isPositive = angleDatum >= 0 && !Object.is(angleDatum, -0);
|
|
const angleRange = group.aggregation[angleRangeIndex][isPositive ? 1 : 0];
|
|
const reversed = isPositive === angleAxisReversed;
|
|
let startAngle = angleScale.convert(angleStartDatum, { clamp: true });
|
|
let endAngle = angleScale.convert(angleEndDatum, { clamp: true });
|
|
let rangeStartAngle = angleScale.convert(0, { clamp: true });
|
|
let rangeEndAngle = angleScale.convert(angleRange, { clamp: true });
|
|
if (reversed) {
|
|
[rangeStartAngle, rangeEndAngle] = [rangeEndAngle, rangeStartAngle];
|
|
[startAngle, endAngle] = [endAngle, startAngle];
|
|
}
|
|
const dataRadius = axisTotalRadius - radiusScale.convert(radiusDatum);
|
|
const innerRadius = dataRadius + groupScale.convert(String(groupIndex));
|
|
const outerRadius = innerRadius + barWidth;
|
|
const midRadius = (innerRadius + outerRadius) / 2;
|
|
const midAngle = startAngle + angleBetween3(startAngle, endAngle) / 2;
|
|
const x = Math.cos(midAngle) * midRadius;
|
|
const y = Math.sin(midAngle) * midRadius;
|
|
const labelNodeDatum = this.properties.label.enabled ? getLabelNodeDatum(datum, angleDatum, x, y) : void 0;
|
|
const clipSector = new SectorBox4(startAngle, endAngle, innerRadius, outerRadius);
|
|
nodeData.push({
|
|
series: this,
|
|
datum,
|
|
datumIndex,
|
|
point: { x, y, size: 0 },
|
|
midPoint: { x, y },
|
|
label: labelNodeDatum,
|
|
angleValue: angleDatum,
|
|
radiusValue: radiusDatum,
|
|
innerRadius,
|
|
outerRadius,
|
|
startAngle: rangeStartAngle,
|
|
endAngle: rangeEndAngle,
|
|
clipSector,
|
|
reversed,
|
|
index: datumIndex
|
|
});
|
|
}
|
|
return context;
|
|
}
|
|
update({ seriesRect }) {
|
|
const resize = this.checkResize(seriesRect);
|
|
this.maybeRefreshNodeData();
|
|
this.contentGroup.translationX = this.centerX;
|
|
this.contentGroup.translationY = this.centerY;
|
|
this.highlightGroup.translationX = this.centerX;
|
|
this.highlightGroup.translationY = this.centerY;
|
|
if (this.labelGroup) {
|
|
this.labelGroup.translationX = this.centerX;
|
|
this.labelGroup.translationY = this.centerY;
|
|
}
|
|
this.updateSectorSelection(this.itemSelection, false);
|
|
this.updateSectorSelection(this.highlightSelection, true);
|
|
this.updateLabels();
|
|
if (resize) {
|
|
this.animationState.transition("resize");
|
|
}
|
|
this.animationState.transition("update");
|
|
}
|
|
updateSectorSelection(selection, isHighlight) {
|
|
let selectionData = [];
|
|
const activeHighlight = this.ctx.highlightManager?.getActiveHighlight();
|
|
if (isHighlight) {
|
|
if (activeHighlight?.datum && activeHighlight.series === this) {
|
|
selectionData.push(activeHighlight);
|
|
}
|
|
} else {
|
|
selectionData = this.nodeData;
|
|
}
|
|
const { contextNodeData } = this;
|
|
if (!contextNodeData) {
|
|
return;
|
|
}
|
|
const highlightedDatum = this.ctx.highlightManager.getActiveHighlight();
|
|
const fillBBox = this.getShapeFillBBox();
|
|
const hasItemStylers = this.hasItemStylers();
|
|
selection.update(selectionData, void 0, (datum) => this.getDatumId(datum)).each((node, nodeDatum) => {
|
|
const datum = readDatum(nodeDatum);
|
|
if (datum == null)
|
|
return;
|
|
if (hasItemStylers) {
|
|
const highlightState = this.getHighlightState(activeHighlight, isHighlight, nodeDatum.datumIndex);
|
|
nodeDatum.style = getItemStyle(this, nodeDatum, isHighlight, highlightState);
|
|
}
|
|
const style = nodeDatum.style ?? contextNodeData.styles[this.getHighlightState(highlightedDatum, isHighlight, nodeDatum.datumIndex)];
|
|
const cornerRadius = style.cornerRadius;
|
|
const fill = style.fill;
|
|
const fillParams = isGradientFill3(fill) && fill.bounds !== "item" ? { centerX: 0, centerY: 0 } : void 0;
|
|
node.setStyleProperties(style, fillBBox, fillParams);
|
|
node.lineJoin = "round";
|
|
node.inset = node.stroke == null ? 0 : node.strokeWidth / 2;
|
|
node.startInnerCornerRadius = datum.reversed ? cornerRadius : 0;
|
|
node.startOuterCornerRadius = datum.reversed ? cornerRadius : 0;
|
|
node.endInnerCornerRadius = datum.reversed ? 0 : cornerRadius;
|
|
node.endOuterCornerRadius = datum.reversed ? 0 : cornerRadius;
|
|
if (isHighlight) {
|
|
node.startAngle = nodeDatum.startAngle;
|
|
node.endAngle = nodeDatum.endAngle;
|
|
node.clipSector = nodeDatum.clipSector;
|
|
node.innerRadius = nodeDatum.innerRadius;
|
|
node.outerRadius = nodeDatum.outerRadius;
|
|
}
|
|
});
|
|
}
|
|
updateLabels() {
|
|
const { properties } = this;
|
|
const activeHighlight = this.ctx.highlightManager?.getActiveHighlight();
|
|
const highlightDatum = activeHighlight?.series === this && activeHighlight?.datum ? activeHighlight : void 0;
|
|
const highlightData = highlightDatum ? [highlightDatum] : [];
|
|
this.labelSelection.update(this.nodeData).each((node, datum) => {
|
|
const isHighlight = false;
|
|
updateLabelNode8(this, node, properties, properties.label, datum.label, isHighlight, activeHighlight);
|
|
node.fillOpacity = this.getHighlightStyle(isHighlight, datum.datumIndex).opacity ?? 1;
|
|
});
|
|
this.highlightLabelSelection.update(highlightData, void 0, (datum) => this.getDatumId(datum)).each((node, datum) => {
|
|
const isHighlight = true;
|
|
updateLabelNode8(this, node, properties, properties.label, datum.label, isHighlight, activeHighlight);
|
|
node.fillOpacity = this.getHighlightStyle(isHighlight, datum.datumIndex).opacity ?? 1;
|
|
});
|
|
}
|
|
getBarTransitionFunctions() {
|
|
const angleScale = this.axes[ChartAxisDirection51.Angle]?.scale;
|
|
let axisZeroAngle = 0;
|
|
if (!angleScale) {
|
|
return prepareRadialBarSeriesAnimationFunctions(axisZeroAngle);
|
|
}
|
|
const d0 = Math.min(angleScale.domain[0], angleScale.domain[1]);
|
|
const d1 = Math.max(angleScale.domain[0], angleScale.domain[1]);
|
|
if (d0 <= 0 && d1 >= 0) {
|
|
axisZeroAngle = angleScale.convert(0);
|
|
}
|
|
return prepareRadialBarSeriesAnimationFunctions(axisZeroAngle);
|
|
}
|
|
animateEmptyUpdateReady() {
|
|
const { labelSelection } = this;
|
|
const fns = this.getBarTransitionFunctions();
|
|
motion10.fromToMotion(this.id, "datums", this.ctx.animationManager, [this.itemSelection], fns);
|
|
seriesLabelFadeInAnimation8(
|
|
this,
|
|
"labels",
|
|
this.ctx.animationManager,
|
|
labelSelection,
|
|
this.highlightLabelSelection
|
|
);
|
|
}
|
|
animateClearingUpdateEmpty() {
|
|
const { itemSelection } = this;
|
|
const { animationManager } = this.ctx;
|
|
const fns = this.getBarTransitionFunctions();
|
|
motion10.fromToMotion(this.id, "datums", animationManager, [itemSelection], fns);
|
|
seriesLabelFadeOutAnimation2(
|
|
this,
|
|
"labels",
|
|
animationManager,
|
|
this.labelSelection,
|
|
this.highlightLabelSelection
|
|
);
|
|
}
|
|
getTooltipContent(datumIndex) {
|
|
const { id: seriesId, dataModel, processedData, axes, properties } = this;
|
|
const { angleKey, angleName, radiusKey, radiusName, legendItemName, tooltip } = properties;
|
|
const angleAxis = axes[ChartAxisDirection51.Angle];
|
|
const radiusAxis = axes[ChartAxisDirection51.Radius];
|
|
const nodeDatum = this.nodeData?.[datumIndex];
|
|
if (!dataModel || !processedData || !angleAxis || !radiusAxis || !nodeDatum)
|
|
return;
|
|
const datum = processedData.dataSources.get(this.id)?.data[datumIndex];
|
|
const radiusValue = dataModel.resolveKeysById(this, `radiusValue`, processedData)[datumIndex];
|
|
const angleValue = dataModel.resolveColumnById(this, `angleValue-raw`, processedData)[datumIndex];
|
|
if (radiusValue === void 0 && !this.properties.allowNullKeys)
|
|
return;
|
|
const format = getItemStyle(this, nodeDatum, false);
|
|
return this.formatTooltipWithContext(
|
|
tooltip,
|
|
{
|
|
heading: this.getAxisValueText(radiusAxis, "tooltip", radiusValue, datum, radiusKey, void 0),
|
|
symbol: this.legendItemSymbol(),
|
|
data: [
|
|
{
|
|
label: angleName,
|
|
fallbackLabel: angleKey,
|
|
value: this.getAxisValueText(angleAxis, "tooltip", angleValue, datum, angleKey, void 0),
|
|
missing: _ModuleSupport195.isTooltipValueMissing(angleValue)
|
|
}
|
|
]
|
|
},
|
|
{
|
|
seriesId,
|
|
datum,
|
|
title: angleName,
|
|
angleKey,
|
|
angleName,
|
|
radiusKey,
|
|
radiusName,
|
|
legendItemName,
|
|
...format
|
|
}
|
|
);
|
|
}
|
|
pickNodeClosestDatum(point) {
|
|
return this.pickNodeNearestDistantObject(point, this.itemSelection.nodes());
|
|
}
|
|
legendItemSymbol() {
|
|
const { fill, stroke: stroke3, fillOpacity, strokeOpacity, strokeWidth, lineDash, lineDashOffset } = getStyle(
|
|
this,
|
|
false,
|
|
_ModuleSupport195.HighlightState.None
|
|
);
|
|
const markerStyle = {
|
|
fill: fill ?? "rgba(0, 0, 0, 0)",
|
|
stroke: stroke3 ?? "rgba(0, 0, 0, 0)",
|
|
fillOpacity,
|
|
strokeOpacity,
|
|
strokeWidth,
|
|
lineDash,
|
|
lineDashOffset
|
|
};
|
|
if (isGradientFill3(markerStyle.fill)) {
|
|
markerStyle.fill = { ...markerStyle.fill, gradient: "linear", rotation: 0, reverse: false };
|
|
}
|
|
return {
|
|
marker: markerStyle
|
|
};
|
|
}
|
|
getLegendData(legendType) {
|
|
if (legendType !== "category") {
|
|
return [];
|
|
}
|
|
const { id: seriesId, visible } = this;
|
|
const { angleKey, angleName, legendItemName, showInLegend } = this.properties;
|
|
return [
|
|
{
|
|
legendType: "category",
|
|
id: seriesId,
|
|
itemId: angleKey,
|
|
seriesId,
|
|
enabled: visible,
|
|
label: {
|
|
text: legendItemName ?? angleName ?? angleKey
|
|
},
|
|
symbol: this.legendItemSymbol(),
|
|
legendItemName,
|
|
hideInLegend: !showInLegend
|
|
}
|
|
];
|
|
}
|
|
getDatumId(datum) {
|
|
return createDatumId19(datum.radiusValue);
|
|
}
|
|
computeLabelsBBox() {
|
|
return null;
|
|
}
|
|
getStackId() {
|
|
const groupIndex = this.seriesGrouping?.groupIndex ?? this.id;
|
|
return `radialBar-stack-${groupIndex}-xValues`;
|
|
}
|
|
hasItemStylers() {
|
|
return this.properties.itemStyler != null || this.properties.styler != null || this.properties.label.itemStyler != null;
|
|
}
|
|
};
|
|
RadialBarSeries.className = "RadialBarSeries";
|
|
RadialBarSeries.type = "radial-bar";
|
|
|
|
// packages/ag-charts-enterprise/src/series/radial-bar/radialBarSeriesOptionsDef.ts
|
|
import { _ModuleSupport as _ModuleSupport196 } from "ag-charts-community";
|
|
import {
|
|
boolean as boolean18,
|
|
commonSeriesOptionsDefs as commonSeriesOptionsDefs19,
|
|
constant as constant20,
|
|
number as number9,
|
|
required as required20,
|
|
string as string20,
|
|
undocumented as undocumented15
|
|
} from "ag-charts-core";
|
|
var { radialBarSeriesThemeableOptionsDef } = _ModuleSupport196;
|
|
var radialBarSeriesOptionsDef = {
|
|
...commonSeriesOptionsDefs19,
|
|
...radialBarSeriesThemeableOptionsDef,
|
|
type: required20(constant20("radial-bar")),
|
|
angleKey: required20(string20),
|
|
radiusKey: required20(string20),
|
|
angleName: string20,
|
|
radiusName: string20,
|
|
legendItemName: string20,
|
|
grouped: boolean18,
|
|
stacked: boolean18,
|
|
stackGroup: string20,
|
|
normalizedTo: number9
|
|
};
|
|
radialBarSeriesOptionsDef.angleKeyAxis = undocumented15(string20);
|
|
radialBarSeriesOptionsDef.radiusKeyAxis = undocumented15(string20);
|
|
|
|
// packages/ag-charts-enterprise/src/series/radial-bar/radialBarThemes.ts
|
|
import {
|
|
FILL_GRADIENT_CONIC_SERIES_DEFAULTS,
|
|
FILL_IMAGE_DEFAULTS as FILL_IMAGE_DEFAULTS15,
|
|
FILL_PATTERN_DEFAULTS as FILL_PATTERN_DEFAULTS10,
|
|
LABEL_BOXING_DEFAULTS as LABEL_BOXING_DEFAULTS15,
|
|
MULTI_SERIES_HIGHLIGHT_STYLE as MULTI_SERIES_HIGHLIGHT_STYLE8,
|
|
POLAR_AXIS_TYPE as POLAR_AXIS_TYPE6
|
|
} from "ag-charts-core";
|
|
var RADIAL_BAR_SERIES_THEME = {
|
|
series: {
|
|
fill: {
|
|
$applySwitch: [
|
|
{ $path: "type" },
|
|
{ $palette: "fill" },
|
|
["gradient", FILL_GRADIENT_CONIC_SERIES_DEFAULTS],
|
|
["image", FILL_IMAGE_DEFAULTS15],
|
|
["pattern", FILL_PATTERN_DEFAULTS10]
|
|
]
|
|
},
|
|
stroke: { $palette: "stroke" },
|
|
strokeWidth: { $isUserOption: ["./stroke", 1, 0] },
|
|
label: {
|
|
...LABEL_BOXING_DEFAULTS15,
|
|
enabled: false,
|
|
fontSize: { $ref: "fontSize" },
|
|
fontFamily: { $ref: "fontFamily" },
|
|
fontWeight: { $ref: "fontWeight" },
|
|
color: { $ref: "chartBackgroundColor" }
|
|
},
|
|
highlight: MULTI_SERIES_HIGHLIGHT_STYLE8
|
|
},
|
|
axes: {
|
|
[POLAR_AXIS_TYPE6.RADIUS_CATEGORY]: {
|
|
innerRadiusRatio: 0.2,
|
|
groupPaddingInner: 0.2,
|
|
paddingInner: 0.2,
|
|
paddingOuter: 0.1
|
|
}
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/series/radial-bar/radialBarModule.ts
|
|
var RadialBarSeriesModule = {
|
|
type: "series",
|
|
name: "radial-bar",
|
|
chartType: "polar",
|
|
enterprise: true,
|
|
stackable: true,
|
|
groupable: true,
|
|
version: VERSION45,
|
|
dependencies: [PolarChartModule4],
|
|
options: radialBarSeriesOptionsDef,
|
|
defaultAxes: { angle: { type: POLAR_AXIS_TYPE7.ANGLE_NUMBER }, radius: { type: POLAR_AXIS_TYPE7.RADIUS_CATEGORY } },
|
|
axisKeys: { [ChartAxisDirection52.Angle]: "angleKeyAxis", [ChartAxisDirection52.Radius]: "radiusKeyAxis" },
|
|
themeTemplate: RADIAL_BAR_SERIES_THEME,
|
|
create: (ctx) => new RadialBarSeries(ctx)
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/series/radial-column/radialColumnModule.ts
|
|
import { PolarChartModule as PolarChartModule5, VERSION as VERSION46 } from "ag-charts-community";
|
|
import { ChartAxisDirection as ChartAxisDirection54, POLAR_AXIS_TYPE as POLAR_AXIS_TYPE9 } from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/series/radial-column/radialColumnSeries.ts
|
|
import { _ModuleSupport as _ModuleSupport197 } from "ag-charts-community";
|
|
import { ChartAxisDirection as ChartAxisDirection53 } from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/series/radial-column/radialColumnSeriesProperties.ts
|
|
import { Property as Property85 } from "ag-charts-core";
|
|
var RadialColumnSeriesProperties = class extends RadialColumnSeriesBaseProperties {
|
|
};
|
|
__decorateClass([
|
|
Property85
|
|
], RadialColumnSeriesProperties.prototype, "columnWidthRatio", 2);
|
|
__decorateClass([
|
|
Property85
|
|
], RadialColumnSeriesProperties.prototype, "maxColumnWidthRatio", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/series/radial-column/radialColumnSeries.ts
|
|
var { PolarAxis: PolarAxis4, RadialColumnShape, getRadialColumnWidth } = _ModuleSupport197;
|
|
var RadialColumnSeries = class extends RadialColumnSeriesBase {
|
|
constructor(moduleCtx) {
|
|
super(moduleCtx, {
|
|
animationResetFns: {
|
|
item: resetRadialColumnSelectionFn
|
|
}
|
|
});
|
|
this.properties = new RadialColumnSeriesProperties();
|
|
}
|
|
getStackId() {
|
|
const groupIndex = this.seriesGrouping?.groupIndex ?? this.id;
|
|
return `radarColumn-stack-${groupIndex}-yValues`;
|
|
}
|
|
nodeFactory() {
|
|
return new RadialColumnShape();
|
|
}
|
|
getColumnTransitionFunctions() {
|
|
const axisZeroRadius = this.isRadiusAxisReversed() ? this.radius : this.getAxisInnerRadius();
|
|
return prepareRadialColumnAnimationFunctions(axisZeroRadius);
|
|
}
|
|
isRadiusAxisCircle() {
|
|
const radiusAxis = this.axes[ChartAxisDirection53.Radius];
|
|
return radiusAxis instanceof PolarAxis4 ? radiusAxis.shape === "circle" : false;
|
|
}
|
|
updateItemPath(node, datum, highlight) {
|
|
node.isBeveled = this.isRadiusAxisCircle();
|
|
if (highlight) {
|
|
node.innerRadius = datum.innerRadius;
|
|
node.outerRadius = datum.outerRadius;
|
|
node.startAngle = datum.startAngle;
|
|
node.endAngle = datum.endAngle;
|
|
node.columnWidth = datum.columnWidth;
|
|
node.axisInnerRadius = datum.axisInnerRadius;
|
|
node.axisOuterRadius = datum.axisOuterRadius;
|
|
}
|
|
}
|
|
getColumnWidth(startAngle, endAngle) {
|
|
const { columnWidthRatio = 0.5, maxColumnWidthRatio = 0.5 } = this.properties;
|
|
return getRadialColumnWidth(startAngle, endAngle, this.radius, columnWidthRatio, maxColumnWidthRatio);
|
|
}
|
|
hasItemStylers() {
|
|
return this.properties.itemStyler != null || this.properties.styler != null || this.properties.label.itemStyler != null;
|
|
}
|
|
};
|
|
RadialColumnSeries.className = "RadialColumnSeries";
|
|
RadialColumnSeries.type = "radial-column";
|
|
|
|
// packages/ag-charts-enterprise/src/series/radial-column/radialColumnSeriesOptionsDef.ts
|
|
import { _ModuleSupport as _ModuleSupport198 } from "ag-charts-community";
|
|
import {
|
|
boolean as boolean19,
|
|
commonSeriesOptionsDefs as commonSeriesOptionsDefs20,
|
|
constant as constant21,
|
|
number as number10,
|
|
required as required21,
|
|
string as string21,
|
|
undocumented as undocumented16
|
|
} from "ag-charts-core";
|
|
var { radialColumnSeriesThemeableOptionsDef } = _ModuleSupport198;
|
|
var radialColumnSeriesOptionsDef = {
|
|
...commonSeriesOptionsDefs20,
|
|
...radialColumnSeriesThemeableOptionsDef,
|
|
type: required21(constant21("radial-column")),
|
|
angleKey: required21(string21),
|
|
radiusKey: required21(string21),
|
|
angleName: string21,
|
|
radiusName: string21,
|
|
legendItemName: string21,
|
|
grouped: boolean19,
|
|
stacked: boolean19,
|
|
stackGroup: string21,
|
|
normalizedTo: number10
|
|
};
|
|
radialColumnSeriesOptionsDef.angleKeyAxis = undocumented16(string21);
|
|
radialColumnSeriesOptionsDef.radiusKeyAxis = undocumented16(string21);
|
|
|
|
// packages/ag-charts-enterprise/src/series/radial-column/radialColumnThemes.ts
|
|
import {
|
|
FILL_GRADIENT_RADIAL_SERIES_DEFAULTS as FILL_GRADIENT_RADIAL_SERIES_DEFAULTS2,
|
|
FILL_IMAGE_DEFAULTS as FILL_IMAGE_DEFAULTS16,
|
|
FILL_PATTERN_DEFAULTS as FILL_PATTERN_DEFAULTS11,
|
|
LABEL_BOXING_DEFAULTS as LABEL_BOXING_DEFAULTS16,
|
|
MULTI_SERIES_HIGHLIGHT_STYLE as MULTI_SERIES_HIGHLIGHT_STYLE9,
|
|
POLAR_AXIS_SHAPE as POLAR_AXIS_SHAPE2,
|
|
POLAR_AXIS_TYPE as POLAR_AXIS_TYPE8
|
|
} from "ag-charts-core";
|
|
var RADIAL_COLUMN_SERIES_THEME = {
|
|
series: {
|
|
fill: {
|
|
$applySwitch: [
|
|
{ $path: "type" },
|
|
{ $palette: "fill" },
|
|
["gradient", FILL_GRADIENT_RADIAL_SERIES_DEFAULTS2],
|
|
["image", FILL_IMAGE_DEFAULTS16],
|
|
["pattern", FILL_PATTERN_DEFAULTS11]
|
|
]
|
|
},
|
|
stroke: { $palette: "stroke" },
|
|
columnWidthRatio: 0.5,
|
|
maxColumnWidthRatio: 0.5,
|
|
strokeWidth: { $isUserOption: ["./stroke", 1, 0] },
|
|
label: {
|
|
...LABEL_BOXING_DEFAULTS16,
|
|
enabled: false,
|
|
fontSize: { $ref: "fontSize" },
|
|
fontFamily: { $ref: "fontFamily" },
|
|
fontWeight: { $ref: "fontWeight" },
|
|
color: { $ref: "textColor" }
|
|
},
|
|
highlight: MULTI_SERIES_HIGHLIGHT_STYLE9
|
|
},
|
|
axes: {
|
|
[POLAR_AXIS_TYPE8.ANGLE_CATEGORY]: {
|
|
shape: { $findFirstSiblingNotOperation: POLAR_AXIS_SHAPE2.CIRCLE },
|
|
groupPaddingInner: 0,
|
|
paddingInner: 0,
|
|
label: {
|
|
spacing: 10
|
|
}
|
|
},
|
|
[POLAR_AXIS_TYPE8.RADIUS_NUMBER]: {
|
|
shape: { $findFirstSiblingNotOperation: POLAR_AXIS_SHAPE2.CIRCLE },
|
|
innerRadiusRatio: 0.5
|
|
}
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/series/radial-column/radialColumnModule.ts
|
|
var RadialColumnSeriesModule = {
|
|
type: "series",
|
|
name: "radial-column",
|
|
chartType: "polar",
|
|
enterprise: true,
|
|
stackable: true,
|
|
groupable: true,
|
|
version: VERSION46,
|
|
dependencies: [PolarChartModule5],
|
|
options: radialColumnSeriesOptionsDef,
|
|
defaultAxes: { angle: { type: POLAR_AXIS_TYPE9.ANGLE_CATEGORY }, radius: { type: POLAR_AXIS_TYPE9.RADIUS_NUMBER } },
|
|
axisKeys: { [ChartAxisDirection54.Angle]: "angleKeyAxis", [ChartAxisDirection54.Radius]: "radiusKeyAxis" },
|
|
themeTemplate: RADIAL_COLUMN_SERIES_THEME,
|
|
create: (ctx) => new RadialColumnSeries(ctx)
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/series/radial-gauge/radialGaugeModule.ts
|
|
import { VERSION as VERSION47 } from "ag-charts-community";
|
|
import {
|
|
FONT_SIZE_RATIO as FONT_SIZE_RATIO3,
|
|
LABEL_BOXING_DEFAULTS as LABEL_BOXING_DEFAULTS17,
|
|
SAFE_RANGE2_OPERATION as SAFE_RANGE2_OPERATION7,
|
|
SAFE_STROKE_FILL_OPERATION as SAFE_STROKE_FILL_OPERATION4,
|
|
radialGaugeSeriesOptionsDef as radialGaugeSeriesOptionsDef2
|
|
} from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/series/radial-gauge/radialGaugeSeries.ts
|
|
import {
|
|
_ModuleSupport as _ModuleSupport202
|
|
} from "ag-charts-community";
|
|
import {
|
|
StateMachine as StateMachine15,
|
|
isBetweenAngles as isBetweenAngles2,
|
|
isNumberEqual as isNumberEqual10,
|
|
mergeDefaults as mergeDefaults21,
|
|
normalizeAngle360 as normalizeAngle3607,
|
|
normalizeAngle360Inclusive as normalizeAngle360Inclusive3,
|
|
tickFormat as tickFormat2,
|
|
toPlainText as toPlainText10,
|
|
toRadians as toRadians5
|
|
} from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/series/radial-gauge/radialGaugeNeedle.ts
|
|
import { _ModuleSupport as _ModuleSupport199 } from "ag-charts-community";
|
|
var { SvgPath, Rotatable, Translatable, Scalable: Scalable2 } = _ModuleSupport199;
|
|
var RadialGaugeNeedle = class extends Rotatable(Scalable2(Translatable(SvgPath))) {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.scalingCenterX = 0.5;
|
|
this.scalingCenterY = 0.5;
|
|
this.rotationCenterX = 0.5;
|
|
this.rotationCenterY = 0.5;
|
|
}
|
|
};
|
|
RadialGaugeNeedle.defaultPathData = "M0.50245 0.53745C0.481767 0.53745 0.465 0.520683 0.465 0.5C0.465 0.479317 0.481767 0.46255 0.50245 0.46255L1 0.500012L0.50245 0.53745Z";
|
|
|
|
// packages/ag-charts-enterprise/src/series/radial-gauge/radialGaugeSeriesProperties.ts
|
|
import { _ModuleSupport as _ModuleSupport200 } from "ag-charts-community";
|
|
import {
|
|
BaseProperties as BaseProperties34,
|
|
PropertiesArray as PropertiesArray8,
|
|
Property as Property86,
|
|
normalizeAngle360 as normalizeAngle3606,
|
|
normalizeAngle360Inclusive as normalizeAngle360Inclusive2,
|
|
toDegrees
|
|
} from "ag-charts-core";
|
|
var { getColorStops: getColorStops2 } = _ModuleSupport200;
|
|
var { makeSeriesTooltip: makeSeriesTooltip21, SeriesProperties: SeriesProperties12, AxisLabel: AxisLabel6, Label: Label16 } = _ModuleSupport200;
|
|
var RadialGaugeDefaultTargetLabelProperties = class extends Label16 {
|
|
};
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeDefaultTargetLabelProperties.prototype, "spacing", 2);
|
|
var RadialGaugeTargetProperties = class extends BaseProperties34 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.label = new RadialGaugeDefaultTargetLabelProperties();
|
|
}
|
|
getStyle() {
|
|
const {
|
|
fill = "black",
|
|
fillOpacity = 1,
|
|
stroke: stroke3 = "black",
|
|
strokeWidth = 0,
|
|
strokeOpacity = 1,
|
|
lineDash = [0],
|
|
lineDashOffset = 0
|
|
} = this;
|
|
return {
|
|
fill,
|
|
fillOpacity,
|
|
stroke: stroke3,
|
|
strokeWidth,
|
|
strokeOpacity,
|
|
lineDash,
|
|
lineDashOffset
|
|
};
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeTargetProperties.prototype, "text", 2);
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeTargetProperties.prototype, "value", 2);
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeTargetProperties.prototype, "shape", 2);
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeTargetProperties.prototype, "placement", 2);
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeTargetProperties.prototype, "spacing", 2);
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeTargetProperties.prototype, "size", 2);
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeTargetProperties.prototype, "rotation", 2);
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeTargetProperties.prototype, "fill", 2);
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeTargetProperties.prototype, "fillOpacity", 2);
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeTargetProperties.prototype, "stroke", 2);
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeTargetProperties.prototype, "strokeWidth", 2);
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeTargetProperties.prototype, "strokeOpacity", 2);
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeTargetProperties.prototype, "lineDash", 2);
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeTargetProperties.prototype, "lineDashOffset", 2);
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeTargetProperties.prototype, "label", 2);
|
|
var RadialGaugeBarProperties = class extends BaseProperties34 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.enabled = true;
|
|
this.fills = new PropertiesArray8(_ModuleSupport200.StopProperties);
|
|
this.fillMode = "continuous";
|
|
this.fillOpacity = 1;
|
|
this.stroke = "black";
|
|
this.strokeWidth = 0;
|
|
this.strokeOpacity = 1;
|
|
this.lineDash = [0];
|
|
this.lineDashOffset = 0;
|
|
}
|
|
getStyle(defaultColorRange, scale) {
|
|
const {
|
|
enabled,
|
|
fill,
|
|
fills,
|
|
fillMode,
|
|
fillOpacity,
|
|
stroke: stroke3,
|
|
strokeWidth,
|
|
strokeOpacity,
|
|
lineDash,
|
|
lineDashOffset
|
|
} = this;
|
|
const barFill = enabled ? fill ?? createConicGradient(fills, fillMode, defaultColorRange, scale) : "none";
|
|
return {
|
|
fill: barFill,
|
|
fillOpacity,
|
|
stroke: stroke3,
|
|
strokeWidth,
|
|
strokeOpacity,
|
|
lineDash,
|
|
lineDashOffset
|
|
};
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeBarProperties.prototype, "enabled", 2);
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeBarProperties.prototype, "fills", 2);
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeBarProperties.prototype, "fillMode", 2);
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeBarProperties.prototype, "fill", 2);
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeBarProperties.prototype, "fillOpacity", 2);
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeBarProperties.prototype, "stroke", 2);
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeBarProperties.prototype, "strokeWidth", 2);
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeBarProperties.prototype, "strokeOpacity", 2);
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeBarProperties.prototype, "lineDash", 2);
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeBarProperties.prototype, "lineDashOffset", 2);
|
|
var RadialGaugeScaleIntervalProperties = class extends BaseProperties34 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.values = void 0;
|
|
this.step = void 0;
|
|
this.minSpacing = 0;
|
|
this.maxSpacing = 1e3;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeScaleIntervalProperties.prototype, "values", 2);
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeScaleIntervalProperties.prototype, "step", 2);
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeScaleIntervalProperties.prototype, "minSpacing", 2);
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeScaleIntervalProperties.prototype, "maxSpacing", 2);
|
|
var RadialGaugeScaleLabelProperties = class extends AxisLabel6 {
|
|
};
|
|
var RadialGaugeScaleProperties = class extends BaseProperties34 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.min = 0;
|
|
this.max = 1;
|
|
this.fills = new PropertiesArray8(_ModuleSupport200.StopProperties);
|
|
this.fillMode = "continuous";
|
|
this.fillOpacity = 1;
|
|
this.stroke = "black";
|
|
this.strokeWidth = 0;
|
|
this.strokeOpacity = 1;
|
|
this.lineDash = [0];
|
|
this.lineDashOffset = 0;
|
|
this.defaultFill = "black";
|
|
this.interval = new RadialGaugeScaleIntervalProperties();
|
|
this.label = new RadialGaugeScaleLabelProperties();
|
|
}
|
|
getStyle(barEnabled, defaultColorRange, scale) {
|
|
const {
|
|
fill,
|
|
fills,
|
|
defaultFill,
|
|
fillMode,
|
|
fillOpacity,
|
|
stroke: stroke3,
|
|
strokeWidth,
|
|
strokeOpacity,
|
|
lineDash,
|
|
lineDashOffset
|
|
} = this;
|
|
const scaleFill = fill ?? (barEnabled && fills.length === 0 ? defaultFill : void 0) ?? createConicGradient(fills, fillMode, defaultColorRange, scale);
|
|
return {
|
|
fill: scaleFill,
|
|
fillOpacity,
|
|
stroke: stroke3,
|
|
strokeWidth,
|
|
strokeOpacity,
|
|
lineDash,
|
|
lineDashOffset
|
|
};
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeScaleProperties.prototype, "min", 2);
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeScaleProperties.prototype, "max", 2);
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeScaleProperties.prototype, "fills", 2);
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeScaleProperties.prototype, "fillMode", 2);
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeScaleProperties.prototype, "fill", 2);
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeScaleProperties.prototype, "fillOpacity", 2);
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeScaleProperties.prototype, "stroke", 2);
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeScaleProperties.prototype, "strokeWidth", 2);
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeScaleProperties.prototype, "strokeOpacity", 2);
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeScaleProperties.prototype, "lineDash", 2);
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeScaleProperties.prototype, "lineDashOffset", 2);
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeScaleProperties.prototype, "defaultFill", 2);
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeScaleProperties.prototype, "interval", 2);
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeScaleProperties.prototype, "label", 2);
|
|
var RadialGaugeNeedleProperties = class extends BaseProperties34 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.enabled = true;
|
|
this.spacing = 0;
|
|
this.fill = "black";
|
|
this.fillOpacity = 1;
|
|
this.stroke = "black";
|
|
this.strokeWidth = 0;
|
|
this.strokeOpacity = 1;
|
|
this.lineDash = [0];
|
|
this.lineDashOffset = 0;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeNeedleProperties.prototype, "enabled", 2);
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeNeedleProperties.prototype, "radiusRatio", 2);
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeNeedleProperties.prototype, "spacing", 2);
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeNeedleProperties.prototype, "fill", 2);
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeNeedleProperties.prototype, "fillOpacity", 2);
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeNeedleProperties.prototype, "stroke", 2);
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeNeedleProperties.prototype, "strokeWidth", 2);
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeNeedleProperties.prototype, "strokeOpacity", 2);
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeNeedleProperties.prototype, "lineDash", 2);
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeNeedleProperties.prototype, "lineDashOffset", 2);
|
|
var RadialGaugeLabelProperties = class extends AutoSizedLabel {
|
|
};
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeLabelProperties.prototype, "text", 2);
|
|
var RadialGaugeSecondaryLabelProperties = class extends AutoSizedSecondaryLabel {
|
|
};
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeSecondaryLabelProperties.prototype, "text", 2);
|
|
var RadialGaugeSeriesProperties = class extends SeriesProperties12 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.startAngle = 0;
|
|
this.endAngle = 0;
|
|
this.segmentation = new GaugeSegmentationProperties();
|
|
this.defaultColorRange = [];
|
|
this.targets = new PropertiesArray8(RadialGaugeTargetProperties);
|
|
this.defaultTarget = new RadialGaugeTargetProperties();
|
|
this.outerRadiusRatio = 1;
|
|
this.innerRadiusRatio = 1;
|
|
this.cornerRadius = 0;
|
|
this.cornerMode = "container";
|
|
this.spacing = 0;
|
|
this.scale = new RadialGaugeScaleProperties();
|
|
this.bar = new RadialGaugeBarProperties();
|
|
this.needle = new RadialGaugeNeedleProperties();
|
|
this.label = new RadialGaugeLabelProperties();
|
|
this.secondaryLabel = new RadialGaugeSecondaryLabelProperties();
|
|
this.tooltip = makeSeriesTooltip21();
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeSeriesProperties.prototype, "value", 2);
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeSeriesProperties.prototype, "startAngle", 2);
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeSeriesProperties.prototype, "endAngle", 2);
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeSeriesProperties.prototype, "segmentation", 2);
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeSeriesProperties.prototype, "defaultColorRange", 2);
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeSeriesProperties.prototype, "targets", 2);
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeSeriesProperties.prototype, "defaultTarget", 2);
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeSeriesProperties.prototype, "outerRadiusRatio", 2);
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeSeriesProperties.prototype, "innerRadiusRatio", 2);
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeSeriesProperties.prototype, "outerRadius", 2);
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeSeriesProperties.prototype, "innerRadius", 2);
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeSeriesProperties.prototype, "cornerRadius", 2);
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeSeriesProperties.prototype, "cornerMode", 2);
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeSeriesProperties.prototype, "spacing", 2);
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeSeriesProperties.prototype, "scale", 2);
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeSeriesProperties.prototype, "bar", 2);
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeSeriesProperties.prototype, "needle", 2);
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeSeriesProperties.prototype, "label", 2);
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeSeriesProperties.prototype, "secondaryLabel", 2);
|
|
__decorateClass([
|
|
Property86
|
|
], RadialGaugeSeriesProperties.prototype, "tooltip", 2);
|
|
function createConicGradient(fills, fillMode, defaultColorRange, scale) {
|
|
const { domain, range: range2 } = scale;
|
|
const [startAngle, endAngle] = range2;
|
|
const conicAngle = normalizeAngle3606((startAngle + endAngle) / 2 + Math.PI);
|
|
const sweepAngle = normalizeAngle360Inclusive2(endAngle - startAngle);
|
|
const colorStops = getColorStops2(fills, defaultColorRange, domain, fillMode).map(
|
|
({ color: color7, stop }) => {
|
|
stop = Math.min(Math.max(stop, 0), 1);
|
|
const angle = startAngle + sweepAngle * stop;
|
|
stop = (angle - conicAngle) / (2 * Math.PI);
|
|
stop = (stop % 1 + 1) % 1;
|
|
return { stop, color: color7 };
|
|
}
|
|
);
|
|
return {
|
|
type: "gradient",
|
|
gradient: "conic",
|
|
colorSpace: "oklch",
|
|
colorStops,
|
|
bounds: "series",
|
|
rotation: toDegrees(conicAngle) + 90
|
|
};
|
|
}
|
|
|
|
// packages/ag-charts-enterprise/src/series/radial-gauge/radialGaugeUtil.ts
|
|
import { _ModuleSupport as _ModuleSupport201 } from "ag-charts-community";
|
|
import { toPlainText as toPlainText9 } from "ag-charts-core";
|
|
var { SectorBox: SectorBox5 } = _ModuleSupport201;
|
|
function computeClipSector(datum) {
|
|
const { startAngle, endAngle, clipStartAngle, clipEndAngle, innerRadius, outerRadius } = datum;
|
|
if (clipStartAngle == null || clipEndAngle == null)
|
|
return;
|
|
return new SectorBox5(
|
|
Math.max(clipStartAngle, startAngle),
|
|
Math.min(clipEndAngle, endAngle),
|
|
innerRadius,
|
|
outerRadius
|
|
);
|
|
}
|
|
function clipSectorVisibility(startAngle, endAngle, clipSector) {
|
|
return Math.max(startAngle, clipSector.startAngle) <= Math.min(endAngle, clipSector.endAngle);
|
|
}
|
|
function hasClipSector(datum) {
|
|
return datum.clipStartAngle != null && datum.clipEndAngle != null;
|
|
}
|
|
function datumClipSector(datum, zero) {
|
|
const { clipStartAngle, clipEndAngle, innerRadius, outerRadius } = datum;
|
|
return new SectorBox5(clipStartAngle, zero ? clipStartAngle : clipEndAngle, innerRadius, outerRadius);
|
|
}
|
|
function prepareRadialGaugeSeriesAnimationFunctions(initialLoad, initialStartAngle) {
|
|
const phase = initialLoad ? "initial" : "update";
|
|
const node = {
|
|
fromFn(sect, datum) {
|
|
const previousDatum = sect.previousDatum;
|
|
let { startAngle, endAngle } = previousDatum ?? datum;
|
|
const previousClipSector = previousDatum != null && hasClipSector(previousDatum) ? datumClipSector(previousDatum, initialLoad) : void 0;
|
|
const nextClipSector = hasClipSector(datum) ? datumClipSector(datum, initialLoad) : void 0;
|
|
let clipSector;
|
|
if (previousClipSector != null && nextClipSector != null) {
|
|
clipSector = previousClipSector;
|
|
} else if (previousClipSector == null && nextClipSector != null) {
|
|
clipSector = nextClipSector;
|
|
startAngle = datum.startAngle;
|
|
endAngle = datum.endAngle;
|
|
} else if (previousClipSector != null && nextClipSector == null) {
|
|
clipSector = void 0;
|
|
startAngle = datum.startAngle;
|
|
endAngle = datum.endAngle;
|
|
} else if (initialLoad) {
|
|
endAngle = startAngle;
|
|
}
|
|
return { startAngle, endAngle, clipSector, phase };
|
|
},
|
|
toFn(_sect, datum) {
|
|
const { startAngle, endAngle } = datum;
|
|
let clipSector;
|
|
if (hasClipSector(datum)) {
|
|
clipSector = datumClipSector(datum, false);
|
|
}
|
|
return { startAngle, endAngle, clipSector };
|
|
},
|
|
applyFn(sect, params) {
|
|
const { startAngle, endAngle } = params;
|
|
let { clipSector } = params;
|
|
if (clipSector != null) {
|
|
clipSector = new SectorBox5(
|
|
Math.max(startAngle, clipSector.startAngle),
|
|
Math.min(endAngle, clipSector.endAngle),
|
|
clipSector.innerRadius,
|
|
clipSector.outerRadius
|
|
);
|
|
}
|
|
const visible = clipSector == null || clipSectorVisibility(startAngle, endAngle, clipSector);
|
|
sect.startAngle = startAngle;
|
|
sect.endAngle = endAngle;
|
|
sect.clipSector = clipSector;
|
|
sect.visible = visible;
|
|
}
|
|
};
|
|
const needle = {
|
|
fromFn(needleNode) {
|
|
let { angle: rotation } = needleNode.previousDatum ?? needleNode.datum;
|
|
if (initialLoad) {
|
|
rotation = initialStartAngle;
|
|
}
|
|
return { rotation, phase };
|
|
},
|
|
toFn(_needleNode, datum) {
|
|
const { angle: rotation } = datum;
|
|
return { rotation };
|
|
}
|
|
};
|
|
return { node, needle };
|
|
}
|
|
function resetRadialGaugeSeriesResetSectorFunction(_node, datum) {
|
|
const { startAngle, endAngle } = datum;
|
|
const clipSector = computeClipSector(datum);
|
|
const visible = clipSector == null || clipSectorVisibility(startAngle, endAngle, clipSector);
|
|
return { startAngle, endAngle, clipSector, visible };
|
|
}
|
|
function resetRadialGaugeSeriesResetNeedleFunction(_node, datum) {
|
|
const { angle } = datum;
|
|
return { rotation: angle };
|
|
}
|
|
var verticalAlignFactors3 = {
|
|
top: 0,
|
|
middle: 0.5,
|
|
bottom: 1
|
|
};
|
|
function formatRadialGaugeLabels(series, ctx, selection, opts, innerRadius, datumOverrides) {
|
|
const { padding: padding2, textAlign, verticalAlign } = opts;
|
|
let labelDatum;
|
|
let secondaryLabelDatum;
|
|
selection.each((_node, datum) => {
|
|
if (datum.label === "primary" /* Primary */) {
|
|
labelDatum = datum;
|
|
} else if (datum.label === "secondary" /* Secondary */) {
|
|
secondaryLabelDatum = datum;
|
|
}
|
|
});
|
|
if (labelDatum == null)
|
|
return;
|
|
const labelText = getLabelText(series.id, ctx, labelDatum, datumOverrides?.label);
|
|
if (labelText == null)
|
|
return;
|
|
const secondaryLabelText = secondaryLabelDatum == null ? void 0 : getLabelText(series.id, ctx, secondaryLabelDatum, datumOverrides?.secondaryLabel);
|
|
const params = { padding: padding2 };
|
|
const horizontalFactor = textAlign === "center" ? 2 : 1;
|
|
const verticalFactor = verticalAlign === "middle" ? 2 : 1;
|
|
const sizeFittingHeight = (height2) => ({
|
|
width: Math.sqrt(Math.max(innerRadius ** 2 - (height2 / verticalFactor) ** 2, 0)) * horizontalFactor,
|
|
height: Math.min(height2, verticalFactor * innerRadius),
|
|
meta: null
|
|
});
|
|
let labelLayout;
|
|
let secondaryLabelLayout;
|
|
let height;
|
|
if (secondaryLabelDatum != null && secondaryLabelText != null) {
|
|
const layout = formatStackedLabels(
|
|
toPlainText9(labelText),
|
|
labelDatum,
|
|
toPlainText9(secondaryLabelText),
|
|
secondaryLabelDatum,
|
|
params,
|
|
sizeFittingHeight
|
|
);
|
|
labelLayout = layout?.label;
|
|
secondaryLabelLayout = layout?.secondaryLabel;
|
|
height = layout?.height ?? 0;
|
|
} else {
|
|
const layout = formatSingleLabel(toPlainText9(labelText), labelDatum, params, sizeFittingHeight);
|
|
labelLayout = layout?.[0];
|
|
secondaryLabelLayout = void 0;
|
|
height = layout?.[0].height ?? 0;
|
|
}
|
|
const rectYOffset = height * verticalAlignFactors3[verticalAlign];
|
|
selection.each((label, datum) => {
|
|
let layout;
|
|
if (datum.label === "primary" /* Primary */) {
|
|
layout = labelLayout;
|
|
} else if (datum.label === "secondary" /* Secondary */) {
|
|
layout = secondaryLabelLayout;
|
|
}
|
|
if (layout == null) {
|
|
label.visible = false;
|
|
return;
|
|
}
|
|
label.visible = true;
|
|
label.text = layout.text;
|
|
label.fontSize = layout.fontSize;
|
|
label.lineHeight = layout.lineHeight;
|
|
label.textAlign = textAlign;
|
|
label.textBaseline = "middle";
|
|
const rectOriginInLabelRect = datum.label === "primary" /* Primary */ ? layout.height / 2 : height - layout.height / 2;
|
|
label.y = datum.centerY + rectOriginInLabelRect - rectYOffset;
|
|
label.x = datum.centerX;
|
|
});
|
|
}
|
|
|
|
// packages/ag-charts-enterprise/src/series/radial-gauge/radialGaugeSeries.ts
|
|
var {
|
|
fromToMotion: fromToMotion5,
|
|
resetMotion: resetMotion4,
|
|
SeriesNodePickMode: SeriesNodePickMode15,
|
|
createDatumId: createDatumId20,
|
|
sectorBox,
|
|
BBox: BBox25,
|
|
Group: Group20,
|
|
PointerEvents: PointerEvents12,
|
|
Selection: Selection16,
|
|
Sector: Sector6,
|
|
SectorBox: SectorBox6,
|
|
Transformable: Transformable4,
|
|
TransformableText: TransformableText3,
|
|
Text: Text9,
|
|
Marker: Marker6
|
|
} = _ModuleSupport202;
|
|
var targetPlacementRotation = {
|
|
inside: 90,
|
|
middle: 0,
|
|
outside: -90
|
|
};
|
|
var outsideLabelPlacements = [
|
|
{ textAlign: "left", textBaseline: "top" },
|
|
{ textAlign: "right", textBaseline: "top" },
|
|
{ textAlign: "right", textBaseline: "bottom" },
|
|
{ textAlign: "left", textBaseline: "bottom" }
|
|
];
|
|
var insideLabelPlacements = [
|
|
{ textAlign: "right", textBaseline: "bottom" },
|
|
{ textAlign: "left", textBaseline: "bottom" },
|
|
{ textAlign: "left", textBaseline: "top" },
|
|
{ textAlign: "right", textBaseline: "top" }
|
|
];
|
|
var RadialGaugeSeries = class extends _ModuleSupport202.Series {
|
|
constructor(moduleCtx) {
|
|
super({
|
|
moduleCtx,
|
|
pickModes: [SeriesNodePickMode15.EXACT_SHAPE_MATCH, SeriesNodePickMode15.NEAREST_NODE]
|
|
});
|
|
this.centerX = 0;
|
|
this.centerY = 0;
|
|
this.radius = 0;
|
|
this.textAlign = "center";
|
|
this.verticalAlign = "middle";
|
|
this.properties = new RadialGaugeSeriesProperties();
|
|
this.scale = new LinearAngleScale();
|
|
this.scaleGroup = this.contentGroup.appendChild(new Group20({ name: "scaleGroup" }));
|
|
this.itemGroup = this.contentGroup.appendChild(new Group20({ name: "itemGroup" }));
|
|
this.itemNeedleGroup = this.contentGroup.appendChild(new Group20({ name: "itemNeedleGroup" }));
|
|
this.itemTargetGroup = this.contentGroup.appendChild(new Group20({ name: "itemTargetGroup" }));
|
|
this.itemTargetLabelGroup = this.contentGroup.appendChild(new Group20({ name: "itemTargetLabelGroup" }));
|
|
this.itemLabelGroup = this.contentGroup.appendChild(new Group20({ name: "itemLabelGroup" }));
|
|
this.highlightTargetGroup = this.highlightGroup.appendChild(
|
|
new Group20({ name: "itemTargetLabelGroup" })
|
|
);
|
|
this.tickGroup = this.contentGroup.appendChild(new Group20({ name: "tickGroup" }));
|
|
this.scaleSelection = Selection16.select(
|
|
this.scaleGroup,
|
|
() => this.nodeFactory()
|
|
);
|
|
this.datumSelection = Selection16.select(
|
|
this.itemGroup,
|
|
() => this.nodeFactory()
|
|
);
|
|
this.needleSelection = Selection16.select(
|
|
this.itemNeedleGroup,
|
|
RadialGaugeNeedle
|
|
);
|
|
this.targetSelection = Selection16.select(
|
|
this.itemTargetGroup,
|
|
() => this.markerFactory()
|
|
);
|
|
this.targetLabelSelection = Selection16.select(this.itemTargetLabelGroup, Text9);
|
|
this.labelSelection = Selection16.select(
|
|
this.itemLabelGroup,
|
|
Text9
|
|
);
|
|
this.highlightTargetSelection = Selection16.select(this.highlightTargetGroup, () => this.markerFactory());
|
|
this.tickSelection = Selection16.select(this.tickGroup, _ModuleSupport202.TransformableText);
|
|
this.datumUnion = new DatumUnion();
|
|
this.animationState = new StateMachine15("empty", {
|
|
empty: {
|
|
update: {
|
|
target: "ready",
|
|
action: () => this.animateEmptyUpdateReady()
|
|
},
|
|
reset: "empty",
|
|
skip: "ready"
|
|
},
|
|
ready: {
|
|
updateData: "waiting",
|
|
clear: "clearing",
|
|
resize: () => this.animateReadyResize(),
|
|
reset: "empty",
|
|
skip: "ready"
|
|
},
|
|
waiting: {
|
|
update: {
|
|
target: "ready",
|
|
action: () => this.animateWaitingUpdateReady()
|
|
},
|
|
reset: "empty",
|
|
skip: "ready"
|
|
},
|
|
clearing: {
|
|
update: {
|
|
target: "empty"
|
|
},
|
|
reset: "empty",
|
|
skip: "ready"
|
|
}
|
|
});
|
|
this.scaleGroup.pointerEvents = PointerEvents12.None;
|
|
this.tickGroup.pointerEvents = PointerEvents12.None;
|
|
this.itemNeedleGroup.pointerEvents = PointerEvents12.None;
|
|
this.itemLabelGroup.pointerEvents = PointerEvents12.None;
|
|
}
|
|
get hasData() {
|
|
return this.properties.value != null;
|
|
}
|
|
nodeFactory() {
|
|
return new Sector6();
|
|
}
|
|
markerFactory() {
|
|
const marker = new Marker6();
|
|
marker.size = 1;
|
|
return marker;
|
|
}
|
|
processData() {
|
|
this.nodeDataRefresh = true;
|
|
this.animationState.transition("updateData");
|
|
}
|
|
formatLabel(value) {
|
|
const { min, max } = this.properties.scale;
|
|
return formatLabel(value, { min, max });
|
|
}
|
|
layoutScale() {
|
|
const { scale, properties } = this;
|
|
const { seriesRectWidth, seriesRectHeight } = this.nodeDataDependencies;
|
|
const { scale: scaleProps, outerRadius } = this.properties;
|
|
const { min, max, label, interval } = scaleProps;
|
|
const startAngle = toRadians5(properties.startAngle - 90);
|
|
const endAngle = toRadians5(properties.endAngle - 90);
|
|
const sweepAngle = normalizeAngle360Inclusive3(endAngle - startAngle);
|
|
const largerThanHalf = sweepAngle > Math.PI;
|
|
const containsTop = largerThanHalf || isBetweenAngles2(1.5 * Math.PI, startAngle, endAngle);
|
|
const containsRight = largerThanHalf || isBetweenAngles2(0 * Math.PI, startAngle, endAngle);
|
|
const containsBottom = largerThanHalf || isBetweenAngles2(0.5 * Math.PI, startAngle, endAngle);
|
|
const containsLeft = largerThanHalf || isBetweenAngles2(1 * Math.PI, startAngle, endAngle);
|
|
let textAlign;
|
|
if (containsLeft && !containsRight) {
|
|
textAlign = "right";
|
|
} else if (!containsLeft && containsRight) {
|
|
textAlign = "left";
|
|
} else {
|
|
textAlign = "center";
|
|
}
|
|
let verticalAlign;
|
|
if (containsTop && !containsBottom) {
|
|
verticalAlign = "bottom";
|
|
} else if (!containsTop && containsBottom) {
|
|
verticalAlign = "top";
|
|
} else {
|
|
verticalAlign = "middle";
|
|
}
|
|
const unitBox = sectorBox({
|
|
startAngle,
|
|
endAngle,
|
|
innerRadius: 0,
|
|
outerRadius: 0.5
|
|
});
|
|
const centerXOffset = -(unitBox.x + unitBox.width / 2) * 2;
|
|
const centerYOffset = -(unitBox.y + unitBox.height / 2) * 2;
|
|
const unitBoxSize = Math.min(seriesRectWidth / unitBox.width, seriesRectHeight / unitBox.height);
|
|
scale.domain = [min, max];
|
|
scale.range = [startAngle, endAngle];
|
|
scale.arcLength = unitBoxSize / 2;
|
|
const { maxSpacing, minSpacing } = interval;
|
|
const { arcLength } = scale;
|
|
const minTickCount = maxSpacing ? Math.floor(arcLength / maxSpacing) : 1;
|
|
const maxTickCount = minSpacing ? Math.floor(arcLength / minSpacing) : Infinity;
|
|
const preferredTickCount = Math.floor(4 / Math.PI * Math.abs(scale.range[0] - scale.range[1]));
|
|
const tickCount = Math.max(minTickCount, Math.min(maxTickCount, preferredTickCount));
|
|
const ticks = interval.values ?? scale.ticks({
|
|
nice: [false, false],
|
|
interval: interval.step,
|
|
minTickCount,
|
|
maxTickCount,
|
|
tickCount
|
|
})?.ticks ?? [];
|
|
const tickFormatter = tickFormat2(ticks, typeof label.format === "string" ? label.format : void 0);
|
|
const tickData = [];
|
|
for (const [index, value] of ticks.entries()) {
|
|
let text2;
|
|
if (label.formatter) {
|
|
text2 = formatWithContext(this.ctx, label.formatter, {
|
|
value,
|
|
index,
|
|
domain: scale.domain,
|
|
boundSeries: void 0
|
|
});
|
|
}
|
|
text2 ?? (text2 = tickFormatter?.(value));
|
|
if (text2 == null)
|
|
continue;
|
|
tickData.push({ index, value, text: text2 });
|
|
}
|
|
const baseRadius = 0.5 * unitBoxSize;
|
|
const labelInset = label.enabled && outerRadius == null && tickData.length > 0 ? this.getTickLabelInset({
|
|
tickData,
|
|
radius: baseRadius,
|
|
centerXOffset,
|
|
centerYOffset,
|
|
seriesRectWidth,
|
|
seriesRectHeight,
|
|
spacing: label.spacing,
|
|
rotation: toRadians5(label.rotation ?? 0)
|
|
}) : 0;
|
|
const radiusBounds = Math.max(
|
|
baseRadius - labelInset,
|
|
// seriesRect may have negative size
|
|
0
|
|
);
|
|
const radius = outerRadius ?? radiusBounds;
|
|
this.centerX = seriesRectWidth / 2 + centerXOffset * radius;
|
|
this.centerY = seriesRectHeight / 2 + centerYOffset * radius;
|
|
this.radius = radius;
|
|
this.textAlign = textAlign;
|
|
this.verticalAlign = verticalAlign;
|
|
return tickData;
|
|
}
|
|
getShapeFillBBox() {
|
|
const { centerX, centerY, radius } = this;
|
|
const bbox = new BBox25(centerX - radius, centerY - radius, 2 * radius, 2 * radius);
|
|
return {
|
|
series: bbox,
|
|
axis: bbox
|
|
};
|
|
}
|
|
getTargets() {
|
|
const { properties } = this;
|
|
const defaultTarget = properties.defaultTarget;
|
|
return properties.targets.map((target) => {
|
|
const {
|
|
text: text2 = defaultTarget.text,
|
|
value = defaultTarget.value ?? 0,
|
|
shape = defaultTarget.shape ?? "triangle",
|
|
rotation = defaultTarget.rotation ?? 0,
|
|
placement = defaultTarget.placement ?? "middle",
|
|
spacing = defaultTarget.spacing ?? 0,
|
|
size = defaultTarget.size ?? 0
|
|
} = target;
|
|
const {
|
|
enabled: labelEnabled = defaultTarget.label.enabled,
|
|
color: labelColor = defaultTarget.label.color ?? "black",
|
|
fontStyle: labelFontStyle = defaultTarget.label.fontStyle ?? "normal",
|
|
fontWeight: labelFontWeight = defaultTarget.label.fontWeight ?? "normal",
|
|
fontSize: labelFontSize = defaultTarget.label.fontSize,
|
|
fontFamily: labelFontFamily = defaultTarget.label.fontFamily,
|
|
spacing: labelSpacing = defaultTarget.label.spacing ?? 0
|
|
} = target.label;
|
|
return {
|
|
text: text2,
|
|
value,
|
|
shape,
|
|
placement,
|
|
spacing,
|
|
size,
|
|
rotation,
|
|
label: {
|
|
enabled: labelEnabled,
|
|
color: labelColor,
|
|
fontStyle: labelFontStyle,
|
|
fontWeight: labelFontWeight,
|
|
fontSize: labelFontSize,
|
|
fontFamily: labelFontFamily,
|
|
spacing: labelSpacing
|
|
},
|
|
style: target.getStyle()
|
|
};
|
|
});
|
|
}
|
|
getTargetRadius(target) {
|
|
const { radius, properties } = this;
|
|
const { innerRadiusRatio, outerRadiusRatio } = properties;
|
|
const { placement, spacing, size } = target;
|
|
const outerRadius = radius * outerRadiusRatio;
|
|
const innerRadius = radius * innerRadiusRatio;
|
|
switch (placement) {
|
|
case "inside":
|
|
return Math.max(innerRadius - spacing - size / 2, 0);
|
|
case "outside":
|
|
return outerRadius + spacing + size / 2;
|
|
default:
|
|
return (innerRadius + outerRadius) / 2;
|
|
}
|
|
}
|
|
getTargetLabel(target) {
|
|
const { scale } = this;
|
|
const { value, size, placement, label } = target;
|
|
const { spacing, color: fill, fontStyle, fontWeight, fontSize, fontFamily } = label;
|
|
const angle = scale.convert(value);
|
|
const quadrant = Math.trunc(normalizeAngle3607(angle) / (Math.PI / 2));
|
|
const offset = size / 2 + spacing;
|
|
let textAlign;
|
|
let textBaseline;
|
|
let offsetX;
|
|
let offsetY;
|
|
switch (placement) {
|
|
case "outside":
|
|
({ textAlign, textBaseline } = outsideLabelPlacements[quadrant]);
|
|
offsetX = offset * Math.cos(angle);
|
|
offsetY = offset * Math.sin(angle);
|
|
break;
|
|
case "inside":
|
|
({ textAlign, textBaseline } = insideLabelPlacements[quadrant]);
|
|
offsetX = -offset * Math.cos(angle);
|
|
offsetY = -offset * Math.sin(angle);
|
|
break;
|
|
default:
|
|
textAlign = "center";
|
|
textBaseline = "bottom";
|
|
offsetX = 0;
|
|
offsetY = -offset;
|
|
break;
|
|
}
|
|
return {
|
|
offsetX,
|
|
offsetY,
|
|
fill,
|
|
textAlign,
|
|
textBaseline,
|
|
fontStyle,
|
|
fontWeight,
|
|
fontSize,
|
|
fontFamily,
|
|
lineHeight: void 0
|
|
};
|
|
}
|
|
createNodeData() {
|
|
const tickData = this.layoutScale();
|
|
const { id: seriesId, scale, properties, radius, centerX, centerY } = this;
|
|
const {
|
|
value,
|
|
innerRadiusRatio,
|
|
outerRadiusRatio,
|
|
segmentation,
|
|
cornerRadius,
|
|
cornerMode,
|
|
needle,
|
|
bar,
|
|
scale: scaleProps,
|
|
label,
|
|
secondaryLabel
|
|
} = properties;
|
|
const {
|
|
outerRadius = radius * outerRadiusRatio,
|
|
innerRadius = radius * innerRadiusRatio,
|
|
defaultColorRange
|
|
} = properties;
|
|
const targets = this.getTargets();
|
|
const nodeData = [];
|
|
const targetData = [];
|
|
const needleData = [];
|
|
const labelData = [];
|
|
const scaleData = [];
|
|
const cornersOnAllItems = cornerMode === "item";
|
|
const containerStartAngle = scale.convert(scale.domain[0]);
|
|
const containerEndAngle = scale.convert(value);
|
|
const maxTicks = Math.ceil(normalizeAngle360Inclusive3(containerEndAngle - containerStartAngle) * radius);
|
|
let segments = segmentation.enabled ? segmentation.interval.getSegments(scale, maxTicks) : void 0;
|
|
const barStyle = bar.getStyle(defaultColorRange, scale);
|
|
const scaleStyle = scaleProps.getStyle(bar.enabled, defaultColorRange, scale);
|
|
if (segments == null && cornersOnAllItems) {
|
|
const segmentStart = Math.min(...scale.domain);
|
|
const segmentEnd = Math.max(...scale.domain);
|
|
const datum = { value, segmentStart, segmentEnd };
|
|
const appliedCornerRadius = Math.min(cornerRadius, (outerRadius - innerRadius) / 2);
|
|
const angleInset = appliedCornerRadius / ((innerRadius + outerRadius) / 2);
|
|
nodeData.push({
|
|
series: this,
|
|
itemId: `value`,
|
|
datum,
|
|
datumIndex: { type: 0 /* Node */ },
|
|
type: 0 /* Node */,
|
|
centerX,
|
|
centerY,
|
|
outerRadius,
|
|
innerRadius,
|
|
startAngle: containerStartAngle - angleInset,
|
|
endAngle: containerEndAngle + angleInset,
|
|
clipStartAngle: void 0,
|
|
clipEndAngle: void 0,
|
|
startCornerRadius: cornerRadius,
|
|
endCornerRadius: cornerRadius,
|
|
style: barStyle
|
|
});
|
|
scaleData.push({
|
|
series: this,
|
|
itemId: `scale`,
|
|
datum,
|
|
datumIndex: { type: 0 /* Node */ },
|
|
type: 0 /* Node */,
|
|
centerX,
|
|
centerY,
|
|
outerRadius,
|
|
innerRadius,
|
|
startAngle: scale.range[0] - angleInset,
|
|
endAngle: scale.range[1] + angleInset,
|
|
clipStartAngle: void 0,
|
|
clipEndAngle: void 0,
|
|
startCornerRadius: cornerRadius,
|
|
endCornerRadius: cornerRadius,
|
|
style: scaleStyle
|
|
});
|
|
} else {
|
|
segments ?? (segments = scale.domain);
|
|
for (let i = 0; i < segments.length - 1; i++) {
|
|
const segmentStart = segments[i];
|
|
const segmentEnd = segments[i + 1];
|
|
const datum = { value, segmentStart, segmentEnd };
|
|
const isStart = i === 0;
|
|
const isEnd = i === segments.length - 2;
|
|
const itemStartAngle = scale.convert(segmentStart);
|
|
const itemEndAngle = scale.convert(segmentEnd);
|
|
nodeData.push({
|
|
series: this,
|
|
itemId: `value-${i}`,
|
|
datum,
|
|
datumIndex: { type: 0 /* Node */ },
|
|
type: 0 /* Node */,
|
|
centerX,
|
|
centerY,
|
|
outerRadius,
|
|
innerRadius,
|
|
startAngle: itemStartAngle,
|
|
endAngle: itemEndAngle,
|
|
clipStartAngle: containerStartAngle,
|
|
clipEndAngle: containerEndAngle,
|
|
startCornerRadius: cornersOnAllItems || isStart ? cornerRadius : 0,
|
|
endCornerRadius: cornersOnAllItems || isEnd ? cornerRadius : 0,
|
|
style: barStyle
|
|
});
|
|
scaleData.push({
|
|
series: this,
|
|
itemId: `scale-${i}`,
|
|
datum,
|
|
datumIndex: { type: 0 /* Node */ },
|
|
type: 0 /* Node */,
|
|
centerX,
|
|
centerY,
|
|
outerRadius,
|
|
innerRadius,
|
|
startAngle: itemStartAngle,
|
|
endAngle: itemEndAngle,
|
|
clipStartAngle: void 0,
|
|
clipEndAngle: void 0,
|
|
startCornerRadius: cornersOnAllItems || isStart ? cornerRadius : 0,
|
|
endCornerRadius: cornersOnAllItems || isEnd ? cornerRadius : 0,
|
|
style: scaleStyle
|
|
});
|
|
}
|
|
}
|
|
if (!needle.enabled && label.enabled) {
|
|
const {
|
|
text: text2,
|
|
color: fill,
|
|
fontSize,
|
|
minimumFontSize,
|
|
fontStyle,
|
|
fontWeight,
|
|
fontFamily,
|
|
lineHeight,
|
|
formatter = (params) => this.formatLabel(params.value)
|
|
} = label;
|
|
labelData.push({
|
|
label: "primary" /* Primary */,
|
|
centerX,
|
|
centerY,
|
|
text: text2,
|
|
value,
|
|
fill,
|
|
fontSize,
|
|
minimumFontSize,
|
|
fontStyle,
|
|
fontWeight,
|
|
fontFamily,
|
|
lineHeight,
|
|
formatter
|
|
});
|
|
}
|
|
if (!needle.enabled && secondaryLabel.enabled) {
|
|
const {
|
|
text: text2,
|
|
color: fill,
|
|
fontSize,
|
|
minimumFontSize,
|
|
fontStyle,
|
|
fontWeight,
|
|
fontFamily,
|
|
lineHeight,
|
|
formatter
|
|
} = secondaryLabel;
|
|
labelData.push({
|
|
label: "secondary" /* Secondary */,
|
|
centerX,
|
|
centerY,
|
|
text: text2,
|
|
value,
|
|
fill,
|
|
fontSize,
|
|
minimumFontSize,
|
|
fontStyle,
|
|
fontWeight,
|
|
fontFamily,
|
|
lineHeight,
|
|
formatter
|
|
});
|
|
}
|
|
if (needle.enabled) {
|
|
let needleRadius = needle.radiusRatio == null ? innerRadius : radius * needle.radiusRatio;
|
|
needleRadius = Math.max(needleRadius - needle.spacing, 0);
|
|
const needleAngle = scale.convert(value);
|
|
needleData.push({
|
|
centerX,
|
|
centerY,
|
|
radius: needleRadius,
|
|
angle: needleAngle,
|
|
series: this
|
|
});
|
|
}
|
|
for (let i = 0; i < targets.length; i += 1) {
|
|
const target = targets[i];
|
|
const { value: targetValue, text: text2, size, shape, style } = target;
|
|
if (targetValue < Math.min(...scale.domain) || targetValue > Math.max(...scale.domain)) {
|
|
continue;
|
|
}
|
|
const targetRadius = this.getTargetRadius(target);
|
|
const targetAngle = scale.convert(targetValue);
|
|
const targetRotation = toRadians5(target.rotation + targetPlacementRotation[target.placement]);
|
|
targetData.push({
|
|
series: this,
|
|
itemId: `target-${i}`,
|
|
midPoint: {
|
|
x: targetRadius * Math.cos(targetAngle) + centerX,
|
|
y: targetRadius * Math.sin(targetAngle) + centerY
|
|
},
|
|
datum: { value: targetValue },
|
|
datumIndex: { type: 1 /* Target */, index: i },
|
|
type: 1 /* Target */,
|
|
value: targetValue,
|
|
text: text2,
|
|
centerX,
|
|
centerY,
|
|
shape,
|
|
radius: targetRadius,
|
|
angle: targetAngle,
|
|
rotation: targetRotation,
|
|
size,
|
|
label: this.getTargetLabel(target),
|
|
style
|
|
});
|
|
}
|
|
return {
|
|
itemId: seriesId,
|
|
nodeData,
|
|
needleData,
|
|
targetData,
|
|
labelData,
|
|
scaleData,
|
|
tickData
|
|
};
|
|
}
|
|
findNodeDatum(itemId) {
|
|
return findGaugeNodeDatum(this, itemId);
|
|
}
|
|
updateSelections(resize) {
|
|
if (this.nodeDataRefresh || resize) {
|
|
this.contextNodeData = this.createNodeData();
|
|
this.nodeDataRefresh = false;
|
|
}
|
|
}
|
|
highlightDatum(node) {
|
|
if (node?.series === this && node.type === 1 /* Target */) {
|
|
return node;
|
|
}
|
|
}
|
|
update({ seriesRect }) {
|
|
const {
|
|
datumSelection,
|
|
labelSelection,
|
|
needleSelection,
|
|
targetSelection,
|
|
targetLabelSelection,
|
|
scaleSelection,
|
|
highlightTargetSelection,
|
|
tickSelection
|
|
} = this;
|
|
const resize = this.checkResize(seriesRect);
|
|
this.updateSelections(resize);
|
|
this.contentGroup.visible = this.visible;
|
|
this.contentGroup.opacity = this.getOpacity();
|
|
const nodeData = this.contextNodeData?.nodeData ?? [];
|
|
const labelData = this.contextNodeData?.labelData ?? [];
|
|
const needleData = this.contextNodeData?.needleData ?? [];
|
|
const targetData = this.contextNodeData?.targetData ?? [];
|
|
const scaleData = this.contextNodeData?.scaleData ?? [];
|
|
const tickData = this.contextNodeData?.tickData ?? [];
|
|
const highlightTargetDatum = this.highlightDatum(this.ctx.highlightManager.getActiveHighlight());
|
|
this.scaleSelection = this.updateScaleSelection({ scaleData, scaleSelection });
|
|
this.updateScaleNodes({ scaleSelection });
|
|
this.needleSelection = this.updateNeedleSelection({ needleData, needleSelection });
|
|
this.updateNeedleNodes({ needleSelection });
|
|
this.targetSelection = this.updateTargetSelection({ targetData, targetSelection });
|
|
this.updateTargetStyles({ targetSelection, isHighlight: false });
|
|
this.updateTargetNodes({ targetSelection });
|
|
this.targetLabelSelection = this.updateTargetLabelSelection({ targetData, targetLabelSelection });
|
|
this.updateTargetLabelNodes({ targetLabelSelection });
|
|
this.datumSelection = this.updateDatumSelection({ nodeData, datumSelection });
|
|
this.updateDatumNodes({ datumSelection });
|
|
this.labelSelection = this.updateLabelSelection({ labelData, labelSelection });
|
|
this.updateLabelNodes({ labelSelection });
|
|
this.highlightTargetSelection = this.updateTargetSelection({
|
|
targetData: highlightTargetDatum == null ? [] : [highlightTargetDatum],
|
|
targetSelection: highlightTargetSelection
|
|
});
|
|
this.updateTargetStyles({ targetSelection: highlightTargetSelection, isHighlight: true });
|
|
this.updateTargetNodes({ targetSelection: highlightTargetSelection });
|
|
this.tickSelection = this.updateTickSelection({ tickData, tickSelection });
|
|
this.updateTickNodes({ tickSelection });
|
|
if (resize) {
|
|
this.animationState.transition("resize");
|
|
}
|
|
this.animationState.transition("update");
|
|
}
|
|
updateDatumSelection(opts) {
|
|
return opts.datumSelection.update(opts.nodeData, void 0, (datum) => {
|
|
return createDatumId20(opts.nodeData.length, datum.itemId);
|
|
});
|
|
}
|
|
updateDatumNodes(opts) {
|
|
const { datumSelection } = opts;
|
|
const { ctx, properties } = this;
|
|
const { segmentation } = properties;
|
|
const sectorSpacing = segmentation.spacing ?? 0;
|
|
const animationDisabled = ctx.animationManager.isSkipped();
|
|
const fillBBox = this.getShapeFillBBox();
|
|
datumSelection.each((sector, datum) => {
|
|
const { centerX, centerY, innerRadius, outerRadius, startCornerRadius, endCornerRadius } = datum;
|
|
sector.centerX = centerX;
|
|
sector.centerY = centerY;
|
|
sector.innerRadius = innerRadius;
|
|
sector.outerRadius = outerRadius;
|
|
sector.pointerEvents = this.properties.bar.enabled ? _ModuleSupport202.PointerEvents.All : _ModuleSupport202.PointerEvents.None;
|
|
sector.setStyleProperties(datum.style, fillBBox);
|
|
sector.startOuterCornerRadius = startCornerRadius;
|
|
sector.startInnerCornerRadius = startCornerRadius;
|
|
sector.endOuterCornerRadius = endCornerRadius;
|
|
sector.endInnerCornerRadius = endCornerRadius;
|
|
sector.radialEdgeInset = (sectorSpacing + sector.strokeWidth) / 2;
|
|
sector.concentricEdgeInset = sector.strokeWidth / 2;
|
|
datum.midPoint = sector.getBBox().computeCenter();
|
|
if (animationDisabled || sector.previousDatum == null) {
|
|
sector.setProperties(resetRadialGaugeSeriesResetSectorFunction(sector, datum));
|
|
}
|
|
});
|
|
this.datumUnion.update(datumSelection, this.itemGroup, _ModuleSupport202.Sector, (node, first, last) => {
|
|
node.clipSector ?? (node.clipSector = new SectorBox6(Number.NaN, Number.NaN, Number.NaN, Number.NaN));
|
|
node.centerX = first.centerX;
|
|
node.centerY = first.centerY;
|
|
node.outerRadius = node.clipSector.outerRadius = first.outerRadius;
|
|
node.innerRadius = node.clipSector.innerRadius = first.innerRadius;
|
|
node.startAngle = node.clipSector.startAngle = first.startAngle;
|
|
node.startInnerCornerRadius = first.startInnerCornerRadius;
|
|
node.startOuterCornerRadius = first.startOuterCornerRadius;
|
|
node.endAngle = last.endAngle;
|
|
node.clipSector.endAngle = last.clipSector?.endAngle ?? last.endAngle;
|
|
node.endInnerCornerRadius = last.endInnerCornerRadius;
|
|
node.endOuterCornerRadius = last.endOuterCornerRadius;
|
|
node.pointerEvents = _ModuleSupport202.PointerEvents.None;
|
|
});
|
|
}
|
|
updateScaleSelection(opts) {
|
|
return opts.scaleSelection.update(opts.scaleData, void 0, (datum) => {
|
|
return createDatumId20(opts.scaleData.length, datum.itemId);
|
|
});
|
|
}
|
|
updateScaleNodes(opts) {
|
|
const { scaleSelection } = opts;
|
|
const { segmentation } = this.properties;
|
|
const sectorSpacing = segmentation.spacing ?? 0;
|
|
const fillBBox = this.getShapeFillBBox();
|
|
scaleSelection.each((sector, datum) => {
|
|
const { centerX, centerY, innerRadius, outerRadius, startCornerRadius, endCornerRadius } = datum;
|
|
sector.centerX = centerX;
|
|
sector.centerY = centerY;
|
|
sector.innerRadius = innerRadius;
|
|
sector.outerRadius = outerRadius;
|
|
sector.setStyleProperties(datum.style, fillBBox);
|
|
sector.startOuterCornerRadius = startCornerRadius;
|
|
sector.startInnerCornerRadius = startCornerRadius;
|
|
sector.endOuterCornerRadius = endCornerRadius;
|
|
sector.endInnerCornerRadius = endCornerRadius;
|
|
sector.radialEdgeInset = (sectorSpacing + sector.strokeWidth) / 2;
|
|
sector.concentricEdgeInset = sector.strokeWidth / 2;
|
|
sector.setProperties(resetRadialGaugeSeriesResetSectorFunction(sector, datum));
|
|
});
|
|
}
|
|
updateNeedleSelection(opts) {
|
|
return opts.needleSelection.update(opts.needleData, void 0, () => createDatumId20(0));
|
|
}
|
|
updateNeedleNodes(opts) {
|
|
const { needleSelection } = opts;
|
|
const { fill, fillOpacity, stroke: stroke3, strokeOpacity, strokeWidth, lineDash, lineDashOffset } = this.properties.needle;
|
|
const animationDisabled = this.ctx.animationManager.isSkipped();
|
|
needleSelection.each((needle, datum) => {
|
|
const { centerX, centerY, radius } = datum;
|
|
const scale = radius * 2;
|
|
needle.d = RadialGaugeNeedle.defaultPathData;
|
|
needle.setStyleProperties({
|
|
fill,
|
|
fillOpacity,
|
|
stroke: stroke3,
|
|
strokeOpacity,
|
|
strokeWidth: strokeWidth / scale,
|
|
lineDash: lineDash.map((d) => d / scale),
|
|
lineDashOffset: lineDashOffset / scale
|
|
});
|
|
needle.translationX = centerX;
|
|
needle.translationY = centerY;
|
|
needle.scalingX = scale;
|
|
needle.scalingY = scale;
|
|
if (animationDisabled) {
|
|
needle.setProperties(resetRadialGaugeSeriesResetNeedleFunction(needle, datum));
|
|
}
|
|
});
|
|
}
|
|
updateTargetSelection(opts) {
|
|
return opts.targetSelection.update(opts.targetData, void 0, (target) => target.itemId);
|
|
}
|
|
updateTargetStyles({
|
|
targetSelection,
|
|
isHighlight
|
|
}) {
|
|
targetSelection.each((_, datum) => {
|
|
datum.style = this.getTargetStyle(isHighlight, datum);
|
|
});
|
|
}
|
|
updateTargetNodes({
|
|
targetSelection
|
|
}) {
|
|
targetSelection.each((target, datum) => {
|
|
const { centerX, centerY, angle, radius, shape, size, rotation } = datum;
|
|
target.setStyleProperties(datum.style);
|
|
target.size = size;
|
|
target.shape = shape === "line" ? lineMarker : shape;
|
|
target.translationX = centerX + radius * Math.cos(angle);
|
|
target.translationY = centerY + radius * Math.sin(angle);
|
|
target.rotation = angle + rotation;
|
|
});
|
|
}
|
|
getTargetStyle(isHighlight, { datumIndex, style }) {
|
|
const highlightStyle = this.getHighlightStyle(isHighlight, datumIndex);
|
|
return mergeDefaults21(highlightStyle, {
|
|
...style,
|
|
opacity: 1
|
|
});
|
|
}
|
|
updateTargetLabelSelection(opts) {
|
|
return opts.targetLabelSelection.update(opts.targetData, void 0, (target) => target.itemId);
|
|
}
|
|
updateTargetLabelNodes(opts) {
|
|
const { targetLabelSelection } = opts;
|
|
targetLabelSelection.each((label, target) => {
|
|
const { centerX, centerY, radius, angle, text: text2 } = target;
|
|
const { offsetX, offsetY, fill, fontStyle, fontWeight, fontSize, fontFamily, textAlign, textBaseline } = target.label;
|
|
if (text2 == null) {
|
|
label.visible = false;
|
|
return;
|
|
}
|
|
label.visible = true;
|
|
label.x = centerX + radius * Math.cos(angle) + offsetX;
|
|
label.y = centerY + radius * Math.sin(angle) + offsetY;
|
|
label.text = text2;
|
|
label.fill = fill;
|
|
label.fontStyle = fontStyle;
|
|
label.fontWeight = fontWeight;
|
|
label.fontSize = fontSize;
|
|
label.fontFamily = fontFamily;
|
|
label.textAlign = textAlign;
|
|
label.textBaseline = textBaseline;
|
|
});
|
|
}
|
|
updateLabelSelection(opts) {
|
|
return opts.labelSelection.update(opts.labelData, void 0, (datum) => datum.label);
|
|
}
|
|
updateLabelNodes(opts) {
|
|
const { labelSelection } = opts;
|
|
const animationDisabled = this.ctx.animationManager.isSkipped();
|
|
labelSelection.each((label, datum) => {
|
|
label.fill = datum.fill;
|
|
label.fontStyle = datum.fontStyle;
|
|
label.fontWeight = datum.fontWeight;
|
|
label.fontFamily = datum.fontFamily;
|
|
});
|
|
if (animationDisabled || this.labelsHaveExplicitText()) {
|
|
this.formatLabelText();
|
|
}
|
|
}
|
|
updateTickSelection(opts) {
|
|
return opts.tickSelection.update(opts.tickData, void 0, (datum) => datum.index);
|
|
}
|
|
updateTickNodes(opts) {
|
|
const { scale, radius, centerX, centerY, properties } = this;
|
|
const { enabled, color: color7, fontFamily, fontSize, fontStyle, fontWeight, spacing } = properties.scale.label;
|
|
const rotation = toRadians5(properties.scale.label.rotation ?? 0);
|
|
opts.tickSelection.each((label, datum) => {
|
|
if (!enabled) {
|
|
label.visible = false;
|
|
return;
|
|
}
|
|
label.visible = true;
|
|
label.text = datum.text;
|
|
label.fill = color7;
|
|
label.fontFamily = fontFamily;
|
|
label.fontSize = fontSize;
|
|
label.fontStyle = fontStyle;
|
|
label.fontWeight = fontWeight;
|
|
const angle = scale.convert(datum.value);
|
|
const { textAlign, textBaseline } = this.getTickLabelAlign(angle);
|
|
const x0 = centerX + (radius + spacing) * Math.cos(angle);
|
|
const y0 = centerY + (radius + spacing) * Math.sin(angle);
|
|
label.textAlign = textAlign;
|
|
label.textBaseline = textBaseline;
|
|
label.x = x0;
|
|
label.y = y0;
|
|
label.rotationCenterX = x0;
|
|
label.rotationCenterY = y0;
|
|
label.rotation = rotation;
|
|
});
|
|
}
|
|
getTickLabelAlign(tickAngle) {
|
|
const cos = Math.cos(tickAngle);
|
|
const sin = Math.sin(tickAngle);
|
|
let textAlign;
|
|
let textBaseline;
|
|
const isCos0 = isNumberEqual10(cos, 0);
|
|
const isSin0 = isNumberEqual10(sin, 0);
|
|
const isCosPositive = cos > 0 && !isCos0;
|
|
const isSinPositive = sin > 0 && !isSin0;
|
|
textAlign = "right";
|
|
if (isCos0) {
|
|
textAlign = "center";
|
|
} else if (isCosPositive) {
|
|
textAlign = "left";
|
|
}
|
|
textBaseline = "bottom";
|
|
if (isSin0) {
|
|
textBaseline = "middle";
|
|
} else if (isSinPositive) {
|
|
textBaseline = "top";
|
|
}
|
|
return { textAlign, textBaseline };
|
|
}
|
|
getTickLabelInset(params) {
|
|
const { tickData, radius, centerXOffset, centerYOffset, seriesRectWidth, seriesRectHeight, spacing, rotation } = params;
|
|
const { label } = this.properties.scale;
|
|
const centerX = seriesRectWidth / 2 + centerXOffset * radius;
|
|
const centerY = seriesRectHeight / 2 + centerYOffset * radius;
|
|
const tempText = new TransformableText3();
|
|
tempText.fontFamily = label.fontFamily;
|
|
tempText.fontSize = label.fontSize;
|
|
tempText.fontStyle = label.fontStyle;
|
|
tempText.fontWeight = label.fontWeight;
|
|
tempText.rotation = rotation;
|
|
const minComponent = 1e-6;
|
|
let inset = 0;
|
|
for (const datum of tickData) {
|
|
const angle = this.scale.convert(datum.value);
|
|
const cos = Math.cos(angle);
|
|
const sin = Math.sin(angle);
|
|
const x = centerX + (radius + spacing) * cos;
|
|
const y = centerY + (radius + spacing) * sin;
|
|
const { textAlign, textBaseline } = this.getTickLabelAlign(angle);
|
|
tempText.text = datum.text;
|
|
tempText.x = x;
|
|
tempText.y = y;
|
|
tempText.textAlign = textAlign;
|
|
tempText.textBaseline = textBaseline;
|
|
tempText.rotationCenterX = x;
|
|
tempText.rotationCenterY = y;
|
|
const box = rotation ? Transformable4.toCanvas(tempText) : tempText.getBBox();
|
|
if (box == null)
|
|
continue;
|
|
const minX = box.x;
|
|
const maxX = box.x + box.width;
|
|
const minY = box.y;
|
|
const maxY = box.y + box.height;
|
|
const overflowLeft = Math.max(0, -minX);
|
|
const overflowRight = Math.max(0, maxX - seriesRectWidth);
|
|
const overflowTop = Math.max(0, -minY);
|
|
const overflowBottom = Math.max(0, maxY - seriesRectHeight);
|
|
const dxPerRadius = centerXOffset + cos;
|
|
if (Math.abs(dxPerRadius) > minComponent) {
|
|
if (overflowRight > 0 && dxPerRadius > 0) {
|
|
inset = Math.max(inset, overflowRight / dxPerRadius);
|
|
} else if (overflowLeft > 0 && dxPerRadius < 0) {
|
|
inset = Math.max(inset, overflowLeft / -dxPerRadius);
|
|
}
|
|
}
|
|
const dyPerRadius = centerYOffset + sin;
|
|
if (Math.abs(dyPerRadius) > minComponent) {
|
|
if (overflowBottom > 0 && dyPerRadius > 0) {
|
|
inset = Math.max(inset, overflowBottom / dyPerRadius);
|
|
} else if (overflowTop > 0 && dyPerRadius < 0) {
|
|
inset = Math.max(inset, overflowTop / -dyPerRadius);
|
|
}
|
|
}
|
|
}
|
|
return inset;
|
|
}
|
|
labelsHaveExplicitText() {
|
|
for (const { datum } of this.labelSelection) {
|
|
if (datum.text == null) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
formatLabelText(datum) {
|
|
const { labelSelection, radius, textAlign, verticalAlign } = this;
|
|
const { spacing: padding2, innerRadiusRatio } = this.properties;
|
|
formatRadialGaugeLabels(
|
|
this,
|
|
this.ctx,
|
|
labelSelection,
|
|
{ padding: padding2, textAlign, verticalAlign },
|
|
radius * innerRadiusRatio,
|
|
datum
|
|
);
|
|
}
|
|
resetAllAnimation() {
|
|
this.ctx.animationManager.stopByAnimationGroupId(this.id);
|
|
resetMotion4([this.datumSelection], resetRadialGaugeSeriesResetSectorFunction);
|
|
resetMotion4([this.needleSelection], resetRadialGaugeSeriesResetNeedleFunction);
|
|
this.formatLabelText();
|
|
}
|
|
resetAnimation(phase) {
|
|
if (phase === "initial") {
|
|
this.animationState.transition("reset");
|
|
} else if (phase === "ready") {
|
|
this.animationState.transition("skip");
|
|
}
|
|
}
|
|
animateLabelText(params = {}) {
|
|
const { animationManager } = this.ctx;
|
|
let labelFrom;
|
|
let labelTo;
|
|
let secondaryLabelFrom;
|
|
let secondaryLabelTo;
|
|
this.labelSelection.each((label, datum) => {
|
|
label.opacity = 1;
|
|
if (datum.label === "primary" /* Primary */) {
|
|
labelFrom = label.previousDatum?.value ?? params.from ?? datum.value;
|
|
labelTo = datum.value;
|
|
} else if (datum.label === "secondary" /* Secondary */) {
|
|
secondaryLabelFrom = label.previousDatum?.value ?? params.from ?? datum.value;
|
|
secondaryLabelTo = datum.value;
|
|
}
|
|
});
|
|
if (this.labelsHaveExplicitText()) {
|
|
} else if (labelTo == null || secondaryLabelTo == null) {
|
|
this.formatLabelText();
|
|
} else if (labelFrom === labelTo && secondaryLabelFrom === secondaryLabelTo) {
|
|
this.formatLabelText({ label: labelTo, secondaryLabel: secondaryLabelTo });
|
|
} else {
|
|
const animationId = `${this.id}_labels`;
|
|
animationManager.animate({
|
|
id: animationId,
|
|
groupId: "label",
|
|
from: { label: labelFrom, secondaryLabel: secondaryLabelFrom },
|
|
to: { label: labelTo, secondaryLabel: secondaryLabelTo },
|
|
phase: params.phase ?? "update",
|
|
onUpdate: (datum) => this.formatLabelText(datum),
|
|
onStop: () => this.formatLabelText({ label: labelTo, secondaryLabel: secondaryLabelTo })
|
|
});
|
|
}
|
|
}
|
|
animateEmptyUpdateReady() {
|
|
const { animationManager } = this.ctx;
|
|
const { node, needle } = prepareRadialGaugeSeriesAnimationFunctions(true, this.scale.range[0]);
|
|
fromToMotion5(this.id, "node", animationManager, [this.datumSelection], node, (_sector, datum) => datum.itemId);
|
|
fromToMotion5(this.id, "needle", animationManager, [this.needleSelection], needle, () => "needle");
|
|
fromToMotion5(
|
|
this.id,
|
|
"label",
|
|
animationManager,
|
|
[this.labelSelection],
|
|
fadeInFns,
|
|
(_label, datum) => datum.label
|
|
);
|
|
this.animateLabelText({
|
|
from: this.properties.scale.min,
|
|
phase: "initial"
|
|
});
|
|
}
|
|
animateWaitingUpdateReady() {
|
|
const { animationManager } = this.ctx;
|
|
const { node, needle } = prepareRadialGaugeSeriesAnimationFunctions(false, this.scale.range[0]);
|
|
fromToMotion5(this.id, "node", animationManager, [this.datumSelection], node, (_sector, datum) => datum.itemId);
|
|
fromToMotion5(this.id, "needle", animationManager, [this.needleSelection], needle, () => "needle");
|
|
this.animateLabelText();
|
|
}
|
|
animateReadyResize() {
|
|
this.resetAllAnimation();
|
|
}
|
|
dataCount() {
|
|
return Number.NaN;
|
|
}
|
|
getSeriesDomain() {
|
|
return { domain: [Number.NaN, Number.NaN] };
|
|
}
|
|
getSeriesRange() {
|
|
return [Number.NaN, Number.NaN];
|
|
}
|
|
getLegendData() {
|
|
return [];
|
|
}
|
|
getTooltipContent(datumIndex) {
|
|
const { id: seriesId, properties } = this;
|
|
const { tooltip } = properties;
|
|
let value;
|
|
let text2;
|
|
let fallbackLabel;
|
|
if (datumIndex.type === 0 /* Node */) {
|
|
value = properties.value;
|
|
text2 = properties.label.text;
|
|
fallbackLabel = this.ctx.localeManager.t("ariaLabelGaugeValue");
|
|
} else {
|
|
({ value, text: text2 } = properties.targets[datumIndex.index]);
|
|
fallbackLabel = this.ctx.localeManager.t("ariaLabelGaugeTarget");
|
|
}
|
|
if (value == null)
|
|
return;
|
|
return this.formatTooltipWithContext(
|
|
tooltip,
|
|
{
|
|
data: [{ label: text2, fallbackLabel, value: this.formatLabel(value) }]
|
|
},
|
|
{ seriesId, title: void 0, datum: void 0, value }
|
|
);
|
|
}
|
|
pickNodeClosestDatum(point) {
|
|
return pickGaugeNearestDatum(this, point);
|
|
}
|
|
pickFocus(opts) {
|
|
return pickGaugeFocus(this, opts);
|
|
}
|
|
getCaptionText() {
|
|
const { value } = this.properties;
|
|
const description = [];
|
|
description.push(this.formatLabel(value));
|
|
this.labelSelection.each((_label, datum) => {
|
|
const text2 = getLabelText(this.id, this.ctx, datum);
|
|
if (text2 != null) {
|
|
description.push(toPlainText10(text2));
|
|
}
|
|
});
|
|
return description.join(". ");
|
|
}
|
|
getCategoryValue(_datumIndex) {
|
|
return;
|
|
}
|
|
datumIndexForCategoryValue(_categoryValue) {
|
|
return;
|
|
}
|
|
hasItemStylers() {
|
|
return this.properties.label.itemStyler != null;
|
|
}
|
|
};
|
|
RadialGaugeSeries.className = "RadialGaugeSeries";
|
|
RadialGaugeSeries.type = "radial-gauge";
|
|
|
|
// packages/ag-charts-enterprise/src/series/radial-gauge/radialGaugeModule.ts
|
|
var RadialGaugeModule = {
|
|
type: "series",
|
|
name: "radial-gauge",
|
|
chartType: "standalone",
|
|
enterprise: true,
|
|
dependencies: [GaugePresetModule],
|
|
version: VERSION47,
|
|
options: radialGaugeSeriesOptionsDef2,
|
|
themeTemplate: {
|
|
minWidth: 200,
|
|
minHeight: 200,
|
|
tooltip: {
|
|
enabled: false
|
|
},
|
|
series: {
|
|
outerRadiusRatio: 1,
|
|
innerRadiusRatio: 0.8,
|
|
startAngle: 270,
|
|
endAngle: 270 + 180,
|
|
defaultColorRange: {
|
|
$if: [
|
|
{ $eq: [{ $palette: "type" }, "inbuilt"] },
|
|
{ $interpolate: [{ $palette: "secondDivergingColors" }, 5] },
|
|
SAFE_RANGE2_OPERATION7
|
|
]
|
|
},
|
|
scale: {
|
|
defaultFill: { $path: ["/1", { $palette: "fill" }, { $palette: "hierarchyColors" }] },
|
|
// TODO: mix backgroundColor and foregroundColor?
|
|
stroke: { $path: ["/2", SAFE_STROKE_FILL_OPERATION4, { $palette: "hierarchyColors" }] },
|
|
// TODO: mix backgroundColor and foregroundColor?
|
|
strokeWidth: { $isUserOption: ["./stroke", 2, 0] },
|
|
label: {
|
|
fontWeight: { $ref: "fontWeight" },
|
|
fontSize: { $ref: "fontSize" },
|
|
fontFamily: { $ref: "fontFamily" },
|
|
color: { $ref: "textColor" },
|
|
spacing: 12
|
|
}
|
|
},
|
|
bar: {
|
|
strokeWidth: { $isUserOption: ["./stroke", 2, 0] }
|
|
},
|
|
segmentation: {
|
|
enabled: false,
|
|
interval: {},
|
|
spacing: 2
|
|
},
|
|
defaultTarget: {
|
|
fill: { $ref: "foregroundColor" },
|
|
stroke: { $ref: "foregroundColor" },
|
|
size: 10,
|
|
shape: "triangle",
|
|
placement: "outside",
|
|
spacing: 5,
|
|
label: {
|
|
enabled: true,
|
|
fontWeight: { $ref: "fontWeight" },
|
|
fontSize: { $ref: "fontSize" },
|
|
fontFamily: { $ref: "fontFamily" },
|
|
color: { $ref: "textColor" },
|
|
spacing: 5
|
|
}
|
|
},
|
|
needle: {
|
|
enabled: false,
|
|
fill: { $ref: "foregroundColor" },
|
|
spacing: 10
|
|
},
|
|
label: {
|
|
...LABEL_BOXING_DEFAULTS17,
|
|
enabled: true,
|
|
fontWeight: { $ref: "fontWeight" },
|
|
fontSize: 56,
|
|
minimumFontSize: 18 / 56,
|
|
fontFamily: { $ref: "fontFamily" },
|
|
color: { $ref: "textColor" }
|
|
},
|
|
secondaryLabel: {
|
|
...LABEL_BOXING_DEFAULTS17,
|
|
enabled: true,
|
|
fontWeight: { $ref: "fontWeight" },
|
|
fontSize: { $rem: FONT_SIZE_RATIO3.LARGE },
|
|
minimumFontSize: { $ref: "fontSize" },
|
|
fontFamily: { $ref: "fontFamily" },
|
|
color: { $ref: "subtleTextColor" }
|
|
},
|
|
tooltip: {
|
|
range: { $path: ["/tooltip/range", 10] }
|
|
}
|
|
}
|
|
},
|
|
create: (ctx) => new RadialGaugeSeries(ctx)
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/series/sankey/sankeyModule.ts
|
|
import { VERSION as VERSION48 } from "ag-charts-community";
|
|
import {
|
|
FILL_GRADIENT_LINEAR_DEFAULTS as FILL_GRADIENT_LINEAR_DEFAULTS8,
|
|
FILL_IMAGE_DEFAULTS as FILL_IMAGE_DEFAULTS17,
|
|
FILL_PATTERN_DEFAULTS as FILL_PATTERN_DEFAULTS12,
|
|
LABEL_BOXING_DEFAULTS as LABEL_BOXING_DEFAULTS18,
|
|
SAFE_FILLS_OPERATION
|
|
} from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/series/sankey/sankeySeries.ts
|
|
import {
|
|
_ModuleSupport as _ModuleSupport205
|
|
} from "ag-charts-community";
|
|
import {
|
|
Logger as Logger22,
|
|
cachedTextMeasurer as cachedTextMeasurer12,
|
|
calcLineHeight as calcLineHeight7,
|
|
mergeDefaults as mergeDefaults22,
|
|
toPlainText as toPlainText11,
|
|
wrapText as wrapText4
|
|
} from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/series/sankey/sankeyLink.ts
|
|
import { _ModuleSupport as _ModuleSupport203 } from "ag-charts-community";
|
|
import { SceneChangeDetection as SceneChangeDetection9, Vec2 as Vec220, clamp as clamp13 } from "ag-charts-core";
|
|
var { BBox: BBox26, Path: Path14 } = _ModuleSupport203;
|
|
var SankeyLink = class extends Path14 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.x1 = 0;
|
|
this.x2 = 0;
|
|
this.y1 = 0;
|
|
this.y2 = 0;
|
|
this.height = 0;
|
|
this.inset = 0;
|
|
this.elbows = [];
|
|
}
|
|
computeBBox() {
|
|
const x = Math.min(this.x1, this.x2);
|
|
const width = Math.max(this.x1, this.x2) - x;
|
|
const y = Math.min(this.y1, this.y2);
|
|
const height = Math.max(this.y1, this.y2) - y + this.height;
|
|
return new BBox26(x, y, width, height);
|
|
}
|
|
updatePath() {
|
|
const { path, inset } = this;
|
|
path.clear();
|
|
const height = this.height - 2 * this.inset;
|
|
const offset = height / 2;
|
|
let x1 = this.x1 + inset;
|
|
let y1 = this.y1 + inset;
|
|
path.moveTo(x1, y1);
|
|
for (const elbow of this.elbows) {
|
|
this.updatePathSection(x1, y1, elbow.x, elbow.y, height, -offset);
|
|
x1 = elbow.x;
|
|
y1 = elbow.y;
|
|
}
|
|
const x2 = this.x2 - inset;
|
|
const y2 = this.y2 + inset;
|
|
this.updatePathSection(x1, y1, x2, y2, height, -offset);
|
|
path.lineTo(x2, y2 + height);
|
|
x1 = x2;
|
|
y1 = y2;
|
|
for (const elbow of this.elbows.toReversed()) {
|
|
this.updatePathSection(x1, y1, elbow.x, elbow.y, height, offset);
|
|
x1 = elbow.x;
|
|
y1 = elbow.y;
|
|
}
|
|
this.updatePathSection(x1, y1, this.x1 + inset, this.y1 + inset, height, offset);
|
|
path.closePath();
|
|
}
|
|
updatePathSection(x1, y1, x2, y2, height, yOffset) {
|
|
const { path } = this;
|
|
const start = Vec220.from(x1, y1 + yOffset + height / 2);
|
|
const end = Vec220.from(x2, y2 + yOffset + height / 2);
|
|
if (Math.abs(end.y - start.y) < 2) {
|
|
path.lineTo(end.x, end.y);
|
|
return;
|
|
}
|
|
let angle = Vec220.angle(Vec220.sub(end, start));
|
|
if (angle < 0)
|
|
angle = 2 * Math.PI + angle;
|
|
const right = 0;
|
|
const down = Math.PI / 2;
|
|
const left = Math.PI;
|
|
const up = Math.PI * 1.5;
|
|
const innerArc = getArcValues(start, end, 0);
|
|
const outerArc = getArcValues(start, end, height);
|
|
if (innerArc.radius < height) {
|
|
path.cubicCurveTo((start.x + end.x) / 2, start.y, (start.x + end.x) / 2, end.y, end.x, end.y);
|
|
return;
|
|
}
|
|
if (angle >= up) {
|
|
path.arc(start.x, y1 - innerArc.radius, innerArc.radius, down, down + outerArc.angle, true);
|
|
path.arc(end.x, y2 + outerArc.radius, outerArc.radius, up + outerArc.angle, up);
|
|
path.lineTo(end.x, end.y);
|
|
} else if (angle > right && angle <= down) {
|
|
path.arc(start.x, y1 + outerArc.radius, outerArc.radius, up, up + outerArc.angle);
|
|
path.arc(end.x, y2 - innerArc.radius, innerArc.radius, down + innerArc.angle, down, true);
|
|
path.lineTo(end.x, end.y);
|
|
} else if (angle > down && angle <= left) {
|
|
path.arc(start.x, y1 + outerArc.radius, outerArc.radius - height, up, up + outerArc.angle, true);
|
|
path.arc(end.x, y2 - innerArc.radius, innerArc.radius + height, down + innerArc.angle, down);
|
|
path.lineTo(end.x, end.y);
|
|
} else {
|
|
path.arc(start.x, y1 - innerArc.radius, innerArc.radius + height, down, down + innerArc.angle);
|
|
path.arc(end.x, y2 + outerArc.radius, outerArc.radius - height, up + outerArc.angle, up, true);
|
|
path.lineTo(end.x, end.y);
|
|
}
|
|
}
|
|
};
|
|
__decorateClass([
|
|
SceneChangeDetection9()
|
|
], SankeyLink.prototype, "x1", 2);
|
|
__decorateClass([
|
|
SceneChangeDetection9()
|
|
], SankeyLink.prototype, "x2", 2);
|
|
__decorateClass([
|
|
SceneChangeDetection9()
|
|
], SankeyLink.prototype, "y1", 2);
|
|
__decorateClass([
|
|
SceneChangeDetection9()
|
|
], SankeyLink.prototype, "y2", 2);
|
|
__decorateClass([
|
|
SceneChangeDetection9()
|
|
], SankeyLink.prototype, "height", 2);
|
|
__decorateClass([
|
|
SceneChangeDetection9()
|
|
], SankeyLink.prototype, "inset", 2);
|
|
function getArcValues(start, end, minRadius) {
|
|
const lineAngle = Vec220.angle(Vec220.sub(end, start));
|
|
const chordLength = Vec220.distance(start, end);
|
|
const bisect = Vec220.add(start, Vec220.rotate(Vec220.from(chordLength / 2, 0), lineAngle));
|
|
const gradient = -1 / Vec220.gradient(start, end);
|
|
const intercept = Vec220.intercept(bisect, gradient);
|
|
const offset = lerpClamp(0.1, 0.5, Math.PI / 2 - Math.abs(Vec220.gradient(start, end)));
|
|
const center = Vec220.intersectAtX(gradient, intercept, start.x);
|
|
const radius = Math.max(minRadius, Vec220.distance(start, center) * offset);
|
|
const angle = Vec220.angle(Vec220.sub(center, start), Vec220.sub(center, bisect)) / -(1.1 - offset);
|
|
return { angle, radius };
|
|
}
|
|
function lerpClamp(a, b, ratio8) {
|
|
return clamp13(a, (b - a) * ratio8 + a, b);
|
|
}
|
|
|
|
// packages/ag-charts-enterprise/src/series/sankey/sankeySeriesProperties.ts
|
|
import {
|
|
_ModuleSupport as _ModuleSupport204
|
|
} from "ag-charts-community";
|
|
import { BaseProperties as BaseProperties35, Property as Property87 } from "ag-charts-core";
|
|
var { FillGradientDefaults: FillGradientDefaults3, FillPatternDefaults: FillPatternDefaults3, FillImageDefaults: FillImageDefaults3, makeSeriesTooltip: makeSeriesTooltip22, SeriesProperties: SeriesProperties13, Label: Label17 } = _ModuleSupport204;
|
|
var SankeySeriesLabelProperties = class extends Label17 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.spacing = 1;
|
|
this.placement = void 0;
|
|
this.edgePlacement = void 0;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property87
|
|
], SankeySeriesLabelProperties.prototype, "spacing", 2);
|
|
__decorateClass([
|
|
Property87
|
|
], SankeySeriesLabelProperties.prototype, "placement", 2);
|
|
__decorateClass([
|
|
Property87
|
|
], SankeySeriesLabelProperties.prototype, "edgePlacement", 2);
|
|
var SankeySeriesLinkProperties = class extends BaseProperties35 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.fill = void 0;
|
|
this.fillOpacity = 1;
|
|
this.stroke = void 0;
|
|
this.strokeOpacity = 1;
|
|
this.strokeWidth = 1;
|
|
this.lineDash = [0];
|
|
this.lineDashOffset = 0;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property87
|
|
], SankeySeriesLinkProperties.prototype, "fill", 2);
|
|
__decorateClass([
|
|
Property87
|
|
], SankeySeriesLinkProperties.prototype, "fillOpacity", 2);
|
|
__decorateClass([
|
|
Property87
|
|
], SankeySeriesLinkProperties.prototype, "stroke", 2);
|
|
__decorateClass([
|
|
Property87
|
|
], SankeySeriesLinkProperties.prototype, "strokeOpacity", 2);
|
|
__decorateClass([
|
|
Property87
|
|
], SankeySeriesLinkProperties.prototype, "strokeWidth", 2);
|
|
__decorateClass([
|
|
Property87
|
|
], SankeySeriesLinkProperties.prototype, "lineDash", 2);
|
|
__decorateClass([
|
|
Property87
|
|
], SankeySeriesLinkProperties.prototype, "lineDashOffset", 2);
|
|
__decorateClass([
|
|
Property87
|
|
], SankeySeriesLinkProperties.prototype, "itemStyler", 2);
|
|
var SankeySeriesNodeProperties = class extends BaseProperties35 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.spacing = 1;
|
|
this.minSpacing = 0;
|
|
this.width = 1;
|
|
this.alignment = "justify";
|
|
this.verticalAlignment = "center";
|
|
this.sort = "auto";
|
|
this.fill = void 0;
|
|
this.fillOpacity = 1;
|
|
this.stroke = void 0;
|
|
this.strokeOpacity = 1;
|
|
this.strokeWidth = 1;
|
|
this.lineDash = [0];
|
|
this.lineDashOffset = 0;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property87
|
|
], SankeySeriesNodeProperties.prototype, "spacing", 2);
|
|
__decorateClass([
|
|
Property87
|
|
], SankeySeriesNodeProperties.prototype, "minSpacing", 2);
|
|
__decorateClass([
|
|
Property87
|
|
], SankeySeriesNodeProperties.prototype, "width", 2);
|
|
__decorateClass([
|
|
Property87
|
|
], SankeySeriesNodeProperties.prototype, "alignment", 2);
|
|
__decorateClass([
|
|
Property87
|
|
], SankeySeriesNodeProperties.prototype, "verticalAlignment", 2);
|
|
__decorateClass([
|
|
Property87
|
|
], SankeySeriesNodeProperties.prototype, "sort", 2);
|
|
__decorateClass([
|
|
Property87
|
|
], SankeySeriesNodeProperties.prototype, "fill", 2);
|
|
__decorateClass([
|
|
Property87
|
|
], SankeySeriesNodeProperties.prototype, "fillOpacity", 2);
|
|
__decorateClass([
|
|
Property87
|
|
], SankeySeriesNodeProperties.prototype, "stroke", 2);
|
|
__decorateClass([
|
|
Property87
|
|
], SankeySeriesNodeProperties.prototype, "strokeOpacity", 2);
|
|
__decorateClass([
|
|
Property87
|
|
], SankeySeriesNodeProperties.prototype, "strokeWidth", 2);
|
|
__decorateClass([
|
|
Property87
|
|
], SankeySeriesNodeProperties.prototype, "lineDash", 2);
|
|
__decorateClass([
|
|
Property87
|
|
], SankeySeriesNodeProperties.prototype, "lineDashOffset", 2);
|
|
__decorateClass([
|
|
Property87
|
|
], SankeySeriesNodeProperties.prototype, "itemStyler", 2);
|
|
var SankeySeriesProperties = class extends SeriesProperties13 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.nodes = void 0;
|
|
this.idKey = "";
|
|
this.idName = void 0;
|
|
this.labelKey = void 0;
|
|
this.labelName = void 0;
|
|
this.sizeKey = void 0;
|
|
this.sizeName = void 0;
|
|
this.fillGradientDefaults = new FillGradientDefaults3();
|
|
this.fillPatternDefaults = new FillPatternDefaults3();
|
|
this.fillImageDefaults = new FillImageDefaults3();
|
|
this.defaultColorRange = [];
|
|
this.defaultPatternFills = [];
|
|
this.fills = [];
|
|
this.strokes = [];
|
|
this.label = new SankeySeriesLabelProperties();
|
|
this.link = new SankeySeriesLinkProperties();
|
|
this.node = new SankeySeriesNodeProperties();
|
|
this.tooltip = makeSeriesTooltip22();
|
|
}
|
|
getStyle(isLink, fills, strokes, index) {
|
|
const {
|
|
fillOpacity,
|
|
strokeWidth,
|
|
strokeOpacity,
|
|
lineDash,
|
|
lineDashOffset,
|
|
fill = fills[index % fills.length],
|
|
stroke: stroke3 = strokes[index % fills.length]
|
|
} = isLink ? this.link : this.node;
|
|
return {
|
|
fill,
|
|
fillOpacity,
|
|
stroke: stroke3,
|
|
strokeWidth,
|
|
strokeOpacity,
|
|
lineDash,
|
|
lineDashOffset
|
|
};
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property87
|
|
], SankeySeriesProperties.prototype, "nodes", 2);
|
|
__decorateClass([
|
|
Property87
|
|
], SankeySeriesProperties.prototype, "fromKey", 2);
|
|
__decorateClass([
|
|
Property87
|
|
], SankeySeriesProperties.prototype, "toKey", 2);
|
|
__decorateClass([
|
|
Property87
|
|
], SankeySeriesProperties.prototype, "idKey", 2);
|
|
__decorateClass([
|
|
Property87
|
|
], SankeySeriesProperties.prototype, "idName", 2);
|
|
__decorateClass([
|
|
Property87
|
|
], SankeySeriesProperties.prototype, "labelKey", 2);
|
|
__decorateClass([
|
|
Property87
|
|
], SankeySeriesProperties.prototype, "labelName", 2);
|
|
__decorateClass([
|
|
Property87
|
|
], SankeySeriesProperties.prototype, "sizeKey", 2);
|
|
__decorateClass([
|
|
Property87
|
|
], SankeySeriesProperties.prototype, "sizeName", 2);
|
|
__decorateClass([
|
|
Property87
|
|
], SankeySeriesProperties.prototype, "fillGradientDefaults", 2);
|
|
__decorateClass([
|
|
Property87
|
|
], SankeySeriesProperties.prototype, "fillPatternDefaults", 2);
|
|
__decorateClass([
|
|
Property87
|
|
], SankeySeriesProperties.prototype, "fillImageDefaults", 2);
|
|
__decorateClass([
|
|
Property87
|
|
], SankeySeriesProperties.prototype, "defaultColorRange", 2);
|
|
__decorateClass([
|
|
Property87
|
|
], SankeySeriesProperties.prototype, "defaultPatternFills", 2);
|
|
__decorateClass([
|
|
Property87
|
|
], SankeySeriesProperties.prototype, "fills", 2);
|
|
__decorateClass([
|
|
Property87
|
|
], SankeySeriesProperties.prototype, "strokes", 2);
|
|
__decorateClass([
|
|
Property87
|
|
], SankeySeriesProperties.prototype, "label", 2);
|
|
__decorateClass([
|
|
Property87
|
|
], SankeySeriesProperties.prototype, "link", 2);
|
|
__decorateClass([
|
|
Property87
|
|
], SankeySeriesProperties.prototype, "node", 2);
|
|
__decorateClass([
|
|
Property87
|
|
], SankeySeriesProperties.prototype, "tooltip", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/series/sankey/sankeySeries.ts
|
|
var { Transformable: Transformable5, SeriesNodePickMode: SeriesNodePickMode16, createDatumId: createDatumId21, getShapeStyle: getShapeStyle2, getLabelStyles: getLabelStyles6, Rect: Rect9, BBox: BBox27 } = _ModuleSupport205;
|
|
var SankeySeries = class extends FlowProportionSeries {
|
|
constructor(moduleCtx) {
|
|
super({
|
|
moduleCtx,
|
|
pickModes: [SeriesNodePickMode16.NEAREST_NODE, SeriesNodePickMode16.EXACT_SHAPE_MATCH]
|
|
});
|
|
this.properties = new SankeySeriesProperties();
|
|
}
|
|
isLabelEnabled() {
|
|
return (this.properties.labelKey != null || this.nodes == null) && this.properties.label.enabled;
|
|
}
|
|
linkFactory() {
|
|
return new SankeyLink();
|
|
}
|
|
nodeFactory() {
|
|
return new Rect9();
|
|
}
|
|
createNodeData() {
|
|
const seriesRectWidth = this._nodeDataDependencies?.seriesRectWidth ?? 0;
|
|
const nodeWidth = this.properties.node.width;
|
|
const {
|
|
nodeGraph: baseNodeGraph,
|
|
links,
|
|
maxPathLength
|
|
} = this.getNodeGraph(this.createNode.bind(this, nodeWidth), this.createLink, {
|
|
includeCircularReferences: false
|
|
});
|
|
const nodeGraph = baseNodeGraph;
|
|
if (nodeGraph.size === 0)
|
|
return;
|
|
const columns = this.initialiseColumns(maxPathLength);
|
|
this.assignNodesToColumns(nodeGraph, columns, maxPathLength);
|
|
const measurer3 = cachedTextMeasurer12(this.properties.label);
|
|
const { columnLabelInsetBefore, columnLabelInsetAfter } = this.getColumnLabelInsets(
|
|
columns,
|
|
measurer3,
|
|
maxPathLength
|
|
);
|
|
const columnWidth = (seriesRectWidth - nodeWidth - columnLabelInsetBefore - columnLabelInsetAfter) / (maxPathLength - 1);
|
|
this.positionNodesInColumnsX(columns, columnWidth, columnLabelInsetBefore);
|
|
this.createGhostNodesAndColumnDiffs(nodeGraph, columns);
|
|
this.weightNodes(columns);
|
|
const minSize = 1;
|
|
const { sizeScale, nodeSpacing } = this.getScaleAndSpacing(columns, minSize);
|
|
if (sizeScale < 0) {
|
|
Logger22.warnOnce(
|
|
"There was insufficient space to display the Sankey Series. Reduce [node.spacing], [node.minSpacing], or provide a larger container."
|
|
);
|
|
return;
|
|
}
|
|
this.positionNodesInColumnsY(columns, minSize, sizeScale, nodeSpacing);
|
|
this.sortAndPositionLinks(nodeGraph, sizeScale);
|
|
const nodeData = [];
|
|
const labelData = [];
|
|
this.createNodesNodeData(nodeData, nodeGraph, columns, columnWidth, measurer3, labelData);
|
|
this.createLinksNodeData(nodeData, links, minSize, sizeScale);
|
|
return {
|
|
itemId: this.id,
|
|
nodeData,
|
|
labelData
|
|
};
|
|
}
|
|
createNode(nodeWidth, node) {
|
|
return {
|
|
...node,
|
|
x: Number.NaN,
|
|
y: Number.NaN,
|
|
width: nodeWidth,
|
|
height: Number.NaN
|
|
};
|
|
}
|
|
createLink(link) {
|
|
return {
|
|
...link,
|
|
x1: Number.NaN,
|
|
x2: Number.NaN,
|
|
y1: Number.NaN,
|
|
y2: Number.NaN,
|
|
height: Number.NaN,
|
|
elbows: []
|
|
};
|
|
}
|
|
initialiseColumns(maxPathLength) {
|
|
const columns = [];
|
|
for (let index = 0; index < maxPathLength; index += 1) {
|
|
columns.push({ index, size: 0, nodes: [], x: 0 });
|
|
}
|
|
return columns;
|
|
}
|
|
assignNodesToColumns(nodeGraph, columns, maxPathLength) {
|
|
const { fromKey, toKey, sizeKey, labelKey } = this.properties;
|
|
for (const graphNode of nodeGraph.values()) {
|
|
const { datum: node, linksBefore, linksAfter } = graphNode;
|
|
const size = Math.max(
|
|
linksBefore.reduce((acc, { link }) => acc + link.size, 0),
|
|
linksAfter.reduce((acc, { link }) => acc + link.size, 0)
|
|
);
|
|
if (linksBefore.length === 0 && linksAfter.length === 0 || size === 0) {
|
|
graphNode.columnIndex = -1;
|
|
continue;
|
|
}
|
|
const column = this.getNodeColumn(columns, graphNode, maxPathLength);
|
|
node.size = size;
|
|
const { label } = this.properties;
|
|
const labelText = label.enabled ? this.getLabelText(
|
|
node.label,
|
|
node.datum,
|
|
labelKey,
|
|
"label",
|
|
[],
|
|
this.properties.label,
|
|
{ datum: node.datum, value: node.label, fromKey, toKey, sizeKey, size }
|
|
) : void 0;
|
|
node.label = toPlainText11(labelText);
|
|
column.nodes.push(graphNode);
|
|
column.size += size;
|
|
graphNode.columnIndex = column.index;
|
|
}
|
|
}
|
|
getNodeColumn(columns, graphNode, maxPathLength) {
|
|
const {
|
|
node: { alignment }
|
|
} = this.properties;
|
|
const { linksBefore, linksAfter, maxPathLengthBefore, maxPathLengthAfter } = graphNode;
|
|
let column;
|
|
switch (alignment) {
|
|
case "left":
|
|
column = columns[maxPathLengthBefore];
|
|
break;
|
|
case "right":
|
|
column = columns[maxPathLength - 1 - maxPathLengthAfter];
|
|
break;
|
|
case "center": {
|
|
if (linksBefore.length !== 0) {
|
|
column = columns[maxPathLengthBefore];
|
|
} else if (linksAfter.length === 0) {
|
|
column = columns[0];
|
|
} else {
|
|
const columnIndex = linksAfter.reduce((acc, link) => Math.min(acc, link.node.maxPathLengthBefore), maxPathLength) - 1;
|
|
column = columns[columnIndex];
|
|
}
|
|
break;
|
|
}
|
|
case "justify": {
|
|
column = linksAfter.length === 0 ? columns[maxPathLength - 1] : columns[maxPathLengthBefore];
|
|
break;
|
|
}
|
|
}
|
|
return column;
|
|
}
|
|
getColumnLabelInsets(columns, measurer3, maxPathLength) {
|
|
const {
|
|
label: { spacing: labelSpacing, placement: labelPlacement, edgePlacement: edgeLabelPlacement },
|
|
node: { width: nodeWidth }
|
|
} = this.properties;
|
|
const seriesRectWidth = this._nodeDataDependencies?.seriesRectWidth ?? 0;
|
|
let columnLabelInsetBefore = 0;
|
|
let columnLabelInsetAfter = 0;
|
|
if (this.isLabelEnabled() && (edgeLabelPlacement === "outside" || edgeLabelPlacement == null)) {
|
|
const reduceLabelWidthFn = (acc, n) => {
|
|
const node = n;
|
|
if (node.datum.label == null || node.datum.label === "")
|
|
return acc;
|
|
let maxWidth = (seriesRectWidth - nodeWidth) / (maxPathLength - 1) - labelSpacing;
|
|
if (labelPlacement === "center" && edgeLabelPlacement == null)
|
|
maxWidth /= 2;
|
|
const text2 = wrapText4(node.datum.label, {
|
|
maxWidth,
|
|
maxHeight: node.datum.height,
|
|
font: this.properties.label,
|
|
textWrap: "never"
|
|
});
|
|
let { width } = measurer3.measureLines(text2);
|
|
if (labelPlacement === "center" && edgeLabelPlacement == null)
|
|
width /= 2;
|
|
return Math.max(acc, width);
|
|
};
|
|
if (labelPlacement !== "right" || edgeLabelPlacement === "outside") {
|
|
columnLabelInsetBefore = nodeWidth + columns[0].nodes.reduce(reduceLabelWidthFn, 0);
|
|
}
|
|
if (labelPlacement !== "left" || edgeLabelPlacement === "outside") {
|
|
columnLabelInsetAfter = nodeWidth + columns.at(-1).nodes.reduce(reduceLabelWidthFn, 0);
|
|
}
|
|
}
|
|
return { columnLabelInsetBefore, columnLabelInsetAfter };
|
|
}
|
|
positionNodesInColumnsX(columns, columnWidth, columnLabelInsetBefore) {
|
|
for (let index = 0; index < columns.length; index++) {
|
|
const column = columns[index];
|
|
column.x = columnLabelInsetBefore + index * columnWidth;
|
|
for (const graphNode of column.nodes) {
|
|
graphNode.datum.x = column.x;
|
|
}
|
|
}
|
|
}
|
|
createGhostNodesAndColumnDiffs(nodeGraph, columns) {
|
|
for (const graphNode of nodeGraph.values()) {
|
|
graphNode.weight = 0;
|
|
let closestColumnDiff = Infinity;
|
|
for (const link of graphNode.linksAfter) {
|
|
const node = link.node;
|
|
closestColumnDiff = Math.min(closestColumnDiff, node.columnIndex - graphNode.columnIndex);
|
|
}
|
|
if (closestColumnDiff === Infinity) {
|
|
for (const link of graphNode.linksBefore) {
|
|
const node = link.node;
|
|
closestColumnDiff = Math.min(closestColumnDiff, graphNode.columnIndex - node.columnIndex);
|
|
}
|
|
}
|
|
graphNode.closestColumnDiff = closestColumnDiff;
|
|
this.createNodeGhostNodes(graphNode, columns, closestColumnDiff);
|
|
}
|
|
}
|
|
createNodeGhostNodes(graphNode, columns, closestColumnDiff) {
|
|
for (const link of graphNode.linksAfter) {
|
|
const node = link.node;
|
|
if (node.columnIndex <= graphNode.columnIndex)
|
|
continue;
|
|
for (let i = node.columnIndex - 1; i > graphNode.columnIndex; i--) {
|
|
const size = link.link.size;
|
|
const ghostNode = {
|
|
ghost: true,
|
|
datum: { ...graphNode.datum, size, y: 0, height: 0 },
|
|
weight: 0,
|
|
linksBefore: [{ node: { columnIndex: i - 1, datum: { size } } }],
|
|
linksAfter: [{ node: { columnIndex: i + 1, datum: { size } } }],
|
|
link: link.link,
|
|
columnIndex: graphNode.columnIndex,
|
|
size: graphNode.datum.size,
|
|
closestColumnDiff,
|
|
fromNode: { y: node.datum.y },
|
|
toNode: { y: 0 }
|
|
};
|
|
columns[i].size += size;
|
|
columns[i].nodes.push(ghostNode);
|
|
}
|
|
}
|
|
}
|
|
weightNodes(columns) {
|
|
const { properties } = this;
|
|
if (properties.node.sort === "data")
|
|
return;
|
|
if (properties.node.sort !== "auto") {
|
|
for (const column of columns) {
|
|
column.nodes.sort((a, b) => this.sortNodes(a, b));
|
|
}
|
|
return;
|
|
}
|
|
const sortedColumns = columns.toSorted((a, b) => {
|
|
const aMax = a.nodes.reduce((acc, n) => Math.max(acc, n.datum.size), 0);
|
|
const bMax = b.nodes.reduce((acc, n) => Math.max(acc, n.datum.size), 0);
|
|
return bMax - aMax;
|
|
});
|
|
const columnWeights = {};
|
|
for (let i = 0; i < sortedColumns.length; i++) {
|
|
columnWeights[sortedColumns[i].index] = Math.pow(10, sortedColumns.length - i - 1);
|
|
}
|
|
for (const column of columns) {
|
|
for (const node of column.nodes) {
|
|
if ("ghost" in node && node.ghost) {
|
|
node.weight = node.size / column.size * columnWeights[column.index];
|
|
continue;
|
|
}
|
|
node.weight = node.datum.size / column.size * columnWeights[column.index];
|
|
}
|
|
column.nodes.sort((a, b) => a.weight - b.weight);
|
|
}
|
|
for (const column of columns) {
|
|
for (const node of column.nodes) {
|
|
if ("ghost" in node && node.ghost) {
|
|
continue;
|
|
}
|
|
node.weight += node.linksBefore.reduce((acc, before) => {
|
|
if (before.node.columnIndex !== column.index - 1)
|
|
return acc;
|
|
const weight = columns[before.node.columnIndex].nodes.indexOf(before.node) * columnWeights[before.node.columnIndex];
|
|
return Math.max(acc, weight);
|
|
}, 0);
|
|
node.weight += node.linksAfter.reduce((acc, after) => {
|
|
if (after.node.columnIndex !== column.index + 1)
|
|
return acc;
|
|
const weight = columns[after.node.columnIndex].nodes.indexOf(after.node) * columnWeights[after.node.columnIndex];
|
|
return Math.max(acc, weight);
|
|
}, 0);
|
|
}
|
|
column.nodes.sort((a, b) => this.sortNodes(a, b));
|
|
}
|
|
}
|
|
getScaleAndSpacing(columns, minSize) {
|
|
const seriesRectHeight = this._nodeDataDependencies?.seriesRectHeight ?? 0;
|
|
const getSizeScale = (spacing) => {
|
|
return columns.reduce((acc, { size, nodes }) => {
|
|
const spacingAccomodation = seriesRectHeight - nodes.length * minSize;
|
|
const spacingOccupation = (nodes.length - 1) * spacing / spacingAccomodation;
|
|
const columnSizeScale = (1 - spacingOccupation) / size;
|
|
return Math.min(acc, columnSizeScale);
|
|
}, Infinity);
|
|
};
|
|
let nodeSpacing = this.properties.node.spacing;
|
|
let sizeScale = getSizeScale(nodeSpacing);
|
|
while (sizeScale < 0 && nodeSpacing > this.properties.node.minSpacing) {
|
|
nodeSpacing -= 1;
|
|
sizeScale = getSizeScale(nodeSpacing);
|
|
}
|
|
return { nodeSpacing, sizeScale };
|
|
}
|
|
positionNodesInColumnsY(columns, minSize, sizeScale, nodeSpacing) {
|
|
const seriesRectHeight = this._nodeDataDependencies?.seriesRectHeight ?? 0;
|
|
for (const column of columns) {
|
|
let columnNodesHeight = 0;
|
|
for (const node of column.nodes) {
|
|
const height = seriesRectHeight * node.datum.size * sizeScale;
|
|
node.datum.height = Math.max(minSize, height);
|
|
columnNodesHeight += height;
|
|
}
|
|
const spacingOccupation = nodeSpacing * (column.nodes.length - 1);
|
|
let y = 0;
|
|
if (this.properties.node.verticalAlignment === "bottom") {
|
|
y = seriesRectHeight - columnNodesHeight - spacingOccupation;
|
|
} else if (this.properties.node.verticalAlignment === "center") {
|
|
y = (seriesRectHeight - columnNodesHeight - spacingOccupation) / 2;
|
|
}
|
|
for (const node of column.nodes) {
|
|
node.datum.y = y;
|
|
y += seriesRectHeight * node.datum.size * sizeScale + nodeSpacing;
|
|
if ("ghost" in node && node.ghost) {
|
|
node.link.elbows.push({ x: column.x, y: node.datum.y });
|
|
}
|
|
}
|
|
}
|
|
}
|
|
sortAndPositionLinks(nodeGraph, sizeScale) {
|
|
const seriesRectHeight = this._nodeDataDependencies?.seriesRectHeight ?? 0;
|
|
for (const { datum, linksBefore, linksAfter } of nodeGraph.values()) {
|
|
let y2 = datum.y;
|
|
linksBefore.sort(
|
|
(a, b) => this.sortNodes(a.node, b.node)
|
|
);
|
|
for (const { link } of linksBefore) {
|
|
link.y2 = y2;
|
|
y2 += link.size * seriesRectHeight * sizeScale;
|
|
}
|
|
let y1 = datum.y;
|
|
linksAfter.sort(
|
|
(a, b) => this.sortNodes(a.node, b.node, {
|
|
invertColumnSort: true
|
|
})
|
|
);
|
|
for (const { link } of linksAfter) {
|
|
link.y1 = y1;
|
|
y1 += link.size * seriesRectHeight * sizeScale;
|
|
}
|
|
}
|
|
}
|
|
createNodesNodeData(nodeData, nodeGraph, columns, columnWidth, measurer3, labelData) {
|
|
for (const [index, column] of columns.entries()) {
|
|
const leading = index === 0;
|
|
const trailing = index === columns.length - 1;
|
|
let bottom = -Infinity;
|
|
column.nodes.sort((a, b) => a.datum.y - b.datum.y);
|
|
for (const n of column.nodes) {
|
|
if ("ghost" in n && n.ghost)
|
|
continue;
|
|
const { datum: node } = n;
|
|
node.midPoint = {
|
|
x: node.x + node.width / 2,
|
|
y: node.y + node.height / 2
|
|
};
|
|
nodeData.push(node);
|
|
bottom = this.createNodeLabelData(
|
|
nodeGraph,
|
|
columnWidth,
|
|
measurer3,
|
|
labelData,
|
|
node,
|
|
leading,
|
|
trailing,
|
|
bottom
|
|
);
|
|
}
|
|
}
|
|
}
|
|
createNodeLabelData(nodeGraph, columnWidth, measurer3, labelData, node, leading, trailing, bottom) {
|
|
if (node.label == null)
|
|
return bottom;
|
|
const {
|
|
label: { spacing: labelSpacing, edgePlacement: edgeLabelPlacement, fontSize }
|
|
} = this.properties;
|
|
const seriesRectWidth = this._nodeDataDependencies?.seriesRectWidth ?? 0;
|
|
const y = node.y + node.height / 2;
|
|
let text2;
|
|
if (!leading && !trailing) {
|
|
const lineHeight = calcLineHeight7(fontSize);
|
|
const y12 = y - lineHeight;
|
|
const y2 = y + lineHeight;
|
|
let maxX = seriesRectWidth;
|
|
for (const { datum } of nodeGraph.values()) {
|
|
const intersectsLabel = datum.x > node.x && Math.max(datum.y, y12) <= Math.min(datum.y + datum.height, y2);
|
|
if (intersectsLabel) {
|
|
maxX = Math.min(maxX, datum.x - labelSpacing);
|
|
}
|
|
}
|
|
const maxWidth = maxX - node.x - 2 * labelSpacing;
|
|
text2 = wrapText4(node.label, {
|
|
maxWidth,
|
|
maxHeight: node.height,
|
|
font: this.properties.label,
|
|
textWrap: "never",
|
|
overflow: "hide"
|
|
});
|
|
}
|
|
if (text2 == null || text2 === "") {
|
|
const labelInset = edgeLabelPlacement == null && (leading || trailing) ? labelSpacing : labelSpacing * 2;
|
|
text2 = wrapText4(node.label, {
|
|
maxWidth: columnWidth - labelInset,
|
|
maxHeight: node.height,
|
|
font: this.properties.label,
|
|
textWrap: "never"
|
|
});
|
|
}
|
|
if (text2 === "")
|
|
return bottom;
|
|
const { height } = measurer3.measureLines(text2);
|
|
const y0 = y - height / 2;
|
|
const y1 = y + height / 2;
|
|
const { x, textAlign } = this.getNodeLabelPlacement(node, leading, trailing);
|
|
if (y0 >= bottom) {
|
|
labelData.push({
|
|
x,
|
|
y,
|
|
textAlign,
|
|
text: text2,
|
|
size: node.size,
|
|
nodeDatum: node,
|
|
datumIndex: node.datumIndex
|
|
});
|
|
bottom = y1;
|
|
}
|
|
return bottom;
|
|
}
|
|
getNodeLabelPlacement(node, leading, trailing) {
|
|
const {
|
|
label: { spacing: labelSpacing, placement: labelPlacement, edgePlacement: edgeLabelPlacement }
|
|
} = this.properties;
|
|
let x = node.x + node.width + labelSpacing;
|
|
let textAlign = "left";
|
|
let placement = labelPlacement;
|
|
if (leading && edgeLabelPlacement == null && labelPlacement == null) {
|
|
placement = "left";
|
|
}
|
|
if (edgeLabelPlacement === "outside") {
|
|
if (leading)
|
|
placement = "left";
|
|
if (trailing)
|
|
placement = "right";
|
|
} else if (edgeLabelPlacement === "inside") {
|
|
if (leading)
|
|
placement = "right";
|
|
if (trailing)
|
|
placement = "left";
|
|
}
|
|
if (placement === "left") {
|
|
x = node.x - labelSpacing;
|
|
textAlign = "right";
|
|
} else if (placement === "center") {
|
|
x = node.x + node.width / 2;
|
|
textAlign = "center";
|
|
}
|
|
return { x, textAlign };
|
|
}
|
|
createLinksNodeData(nodeData, links, minSize, sizeScale) {
|
|
const seriesRectHeight = this._nodeDataDependencies?.seriesRectHeight ?? 0;
|
|
const nodeWidth = this.properties.node.width;
|
|
for (const link of links) {
|
|
const { fromNode, toNode, size } = link;
|
|
link.height = Math.max(minSize, seriesRectHeight * size * sizeScale);
|
|
link.x1 = fromNode.x + nodeWidth;
|
|
link.x2 = toNode.x;
|
|
link.midPoint = {
|
|
x: (link.x1 + link.x2) / 2,
|
|
y: (link.y1 + link.y2) / 2 + link.height / 2
|
|
};
|
|
nodeData.push(link);
|
|
}
|
|
}
|
|
sortNodes(a, b, opts) {
|
|
const { properties } = this;
|
|
if (properties.node.sort === "ascending") {
|
|
return (a.datum.label ?? "").localeCompare(b.datum.label ?? "");
|
|
} else if (properties.node.sort === "descending") {
|
|
return (b.datum.label ?? "").localeCompare(a.datum.label ?? "");
|
|
} else if (properties.node.sort === "data") {
|
|
return 0;
|
|
}
|
|
if (a.columnIndex < b.columnIndex)
|
|
return opts?.invertColumnSort ? 1 : -1;
|
|
if (a.columnIndex > b.columnIndex)
|
|
return opts?.invertColumnSort ? -1 : 1;
|
|
if (a.weight === b.weight) {
|
|
return a.datum.size - b.datum.size;
|
|
}
|
|
if (a.closestColumnDiff < b.closestColumnDiff)
|
|
return 1;
|
|
if (a.closestColumnDiff > b.closestColumnDiff)
|
|
return -1;
|
|
return a.weight - b.weight;
|
|
}
|
|
updateLabelSelection(opts) {
|
|
const labels = this.isLabelEnabled() ? opts.labelData : [];
|
|
return opts.labelSelection.update(labels);
|
|
}
|
|
updateLabelNodes(opts) {
|
|
const activeHighlightDatum = this.getHighlightedDatum();
|
|
opts.labelSelection.each((label, datum) => {
|
|
const { x, y, textAlign, text: text2, datumIndex, nodeDatum } = datum;
|
|
const params = {
|
|
fromKey: this.properties.fromKey,
|
|
size: datum.size,
|
|
sizeKey: this.properties.sizeKey,
|
|
toKey: this.properties.toKey
|
|
};
|
|
const isHighlight = this.isLabelHighlighted(nodeDatum, activeHighlightDatum);
|
|
const highlightStyle = this.getHighlightStyle(isHighlight, datumIndex);
|
|
const style = getLabelStyles6(
|
|
this,
|
|
void 0,
|
|
params,
|
|
this.properties.label,
|
|
isHighlight,
|
|
activeHighlightDatum
|
|
);
|
|
const { color: fill, fontStyle, fontWeight, fontSize, fontFamily } = style;
|
|
label.visible = true;
|
|
label.x = x;
|
|
label.y = y;
|
|
label.text = text2;
|
|
label.fill = fill;
|
|
label.fontStyle = fontStyle;
|
|
label.fontWeight = fontWeight;
|
|
label.fontSize = fontSize;
|
|
label.fontFamily = fontFamily;
|
|
label.textAlign = textAlign;
|
|
label.textBaseline = "middle";
|
|
const opacity = highlightStyle.opacity ?? 1;
|
|
label.opacity = opacity;
|
|
label.fillOpacity = opacity;
|
|
label.setBoxing(style);
|
|
});
|
|
}
|
|
updateNodeSelection(opts) {
|
|
return opts.datumSelection.update(opts.nodeData, void 0, (datum) => createDatumId21(datum.type, datum.id));
|
|
}
|
|
getNodeStyle(nodeDatum, fromNodeDatumIndex, isHighlight) {
|
|
const { properties } = this;
|
|
const {
|
|
fills,
|
|
strokes,
|
|
defaultColorRange,
|
|
defaultPatternFills,
|
|
fillGradientDefaults: fillGradientDefaults3,
|
|
fillPatternDefaults: fillPatternDefaults3,
|
|
fillImageDefaults: fillImageDefaults3
|
|
} = properties;
|
|
const { itemStyler } = properties.node;
|
|
const defaultColorStops = defaultColorRange[fromNodeDatumIndex % defaultColorRange.length].map((color7) => ({
|
|
color: color7
|
|
}));
|
|
const defaultPatternFill = defaultPatternFills[fromNodeDatumIndex % defaultPatternFills.length];
|
|
const highlightStyle = this.getHighlightStyle(isHighlight, nodeDatum.datumIndex);
|
|
const baseStyle = mergeDefaults22(highlightStyle, properties.getStyle(false, fills, strokes, fromNodeDatumIndex));
|
|
const hasNodeFill = properties.node.fill != null;
|
|
let style = getShapeStyle2(
|
|
baseStyle,
|
|
hasNodeFill ? fillGradientDefaults3 : { ...fillGradientDefaults3.toJson(), colorStops: defaultColorStops },
|
|
hasNodeFill ? fillPatternDefaults3 : { ...fillPatternDefaults3.toJson(), fill: defaultPatternFill, stroke: defaultPatternFill },
|
|
fillImageDefaults3
|
|
);
|
|
if (itemStyler != null && nodeDatum.datumIndex != null) {
|
|
const overrides = this.cachedDatumCallback(
|
|
createDatumId21(nodeDatum.datumIndex.index, "node", isHighlight ? "highlight" : "node"),
|
|
() => {
|
|
const params = this.makeItemStylerParams(nodeDatum, isHighlight, style);
|
|
return this.callWithContext(itemStyler, params);
|
|
}
|
|
);
|
|
if (overrides) {
|
|
style = mergeDefaults22(
|
|
overrides,
|
|
style,
|
|
{ ...fillGradientDefaults3.toJson(), colorStops: defaultColorStops },
|
|
{ ...fillPatternDefaults3.toJson(), fill: defaultPatternFill, stroke: defaultPatternFill },
|
|
fillImageDefaults3
|
|
);
|
|
}
|
|
}
|
|
style.opacity = 1;
|
|
return style;
|
|
}
|
|
makeItemStylerParams({ datum, datumIndex, size = 0, label }, isHighlight, style) {
|
|
const { id: seriesId } = this;
|
|
const activeHighlight = this.ctx.highlightManager?.getActiveHighlight();
|
|
const highlightState = this.getHighlightStateString(activeHighlight, isHighlight, datumIndex);
|
|
const fill = this.filterItemStylerFillParams(style.fill) ?? style.fill;
|
|
return {
|
|
seriesId,
|
|
datum,
|
|
highlightState,
|
|
...style,
|
|
size,
|
|
label,
|
|
fill
|
|
};
|
|
}
|
|
updateNodeNodes(opts) {
|
|
const { datumSelection, isHighlight } = opts;
|
|
const fillBBox = this.getShapeFillBBox();
|
|
datumSelection.each((rect, datum) => {
|
|
const { datumIndex } = datum;
|
|
const style = this.getNodeStyle(datum, datumIndex.index, isHighlight);
|
|
rect.x = datum.x;
|
|
rect.y = datum.y;
|
|
rect.width = Math.max(datum.width, 0);
|
|
rect.height = Math.max(datum.height, 0);
|
|
rect.setStyleProperties(style, fillBBox);
|
|
});
|
|
}
|
|
getShapeFillBBox() {
|
|
const width = this._nodeDataDependencies?.seriesRectWidth ?? 0;
|
|
const height = this._nodeDataDependencies?.seriesRectHeight ?? 0;
|
|
const bbox = new BBox27(0, 0, width, height);
|
|
return { series: bbox, axis: bbox };
|
|
}
|
|
updateLinkSelection(opts) {
|
|
return opts.datumSelection.update(
|
|
opts.nodeData,
|
|
void 0,
|
|
(datum) => createDatumId21(datum.type, datum.index, datum.fromNode.id, datum.toNode.id)
|
|
);
|
|
}
|
|
getLinkStyle({ datumIndex, datum }, fromNodeDatumIndex, isHighlight) {
|
|
const { id: seriesId, properties } = this;
|
|
const {
|
|
fills,
|
|
strokes,
|
|
defaultColorRange,
|
|
defaultPatternFills,
|
|
fillGradientDefaults: fillGradientDefaults3,
|
|
fillPatternDefaults: fillPatternDefaults3,
|
|
fillImageDefaults: fillImageDefaults3
|
|
} = properties;
|
|
const { itemStyler } = properties.link;
|
|
const defaultColorStops = defaultColorRange[fromNodeDatumIndex.index % defaultColorRange.length].map(
|
|
(color7) => ({
|
|
color: color7
|
|
})
|
|
);
|
|
const defaultPatternFill = defaultPatternFills[fromNodeDatumIndex.index % defaultPatternFills.length];
|
|
const highlightStyle = this.getHighlightStyle(isHighlight, datumIndex);
|
|
const baseStyle = mergeDefaults22(
|
|
highlightStyle,
|
|
properties.getStyle(true, fills, strokes, fromNodeDatumIndex.index)
|
|
);
|
|
const hasLinkFill = properties.link.fill != null;
|
|
let style = getShapeStyle2(
|
|
baseStyle,
|
|
hasLinkFill ? fillGradientDefaults3 : { ...fillGradientDefaults3.toJson(), colorStops: defaultColorStops },
|
|
hasLinkFill ? fillPatternDefaults3 : { ...fillPatternDefaults3.toJson(), fill: defaultPatternFill, stroke: defaultPatternFill },
|
|
fillImageDefaults3
|
|
);
|
|
if (itemStyler != null && datumIndex != null) {
|
|
const overrides = this.cachedDatumCallback(
|
|
createDatumId21(datumIndex.index, "link", isHighlight ? "highlight" : "node"),
|
|
() => {
|
|
const activeHighlight = this.ctx.highlightManager?.getActiveHighlight();
|
|
const highlightState = this.getHighlightStateString(activeHighlight, isHighlight, datumIndex);
|
|
return this.callWithContext(itemStyler, {
|
|
seriesId,
|
|
datum,
|
|
highlightState,
|
|
...style
|
|
});
|
|
}
|
|
);
|
|
if (overrides) {
|
|
style = mergeDefaults22(
|
|
overrides,
|
|
style,
|
|
{ ...fillGradientDefaults3.toJson(), colorStops: defaultColorStops },
|
|
{ ...fillPatternDefaults3.toJson(), fill: defaultPatternFill, stroke: defaultPatternFill },
|
|
fillImageDefaults3
|
|
);
|
|
}
|
|
}
|
|
style.opacity = 1;
|
|
return style;
|
|
}
|
|
updateLinkNodes(opts) {
|
|
const { datumSelection, isHighlight } = opts;
|
|
const fillBBox = this.getShapeFillBBox();
|
|
datumSelection.each((link, datum) => {
|
|
const fromNodeDatumIndex = datum.fromNode.datumIndex;
|
|
const style = this.getLinkStyle(datum, fromNodeDatumIndex, isHighlight);
|
|
link.x1 = datum.x1;
|
|
link.y1 = datum.y1;
|
|
link.x2 = datum.x2;
|
|
link.y2 = datum.y2;
|
|
link.height = datum.height;
|
|
link.elbows = datum.elbows;
|
|
link.setStyleProperties(style, fillBBox);
|
|
link.inset = link.strokeWidth / 2;
|
|
});
|
|
}
|
|
getTooltipContent(datumIndex) {
|
|
const {
|
|
id: seriesId,
|
|
linksProcessedData,
|
|
nodesProcessedData,
|
|
properties,
|
|
ctx: { formatManager }
|
|
} = this;
|
|
const { fromKey, toKey, sizeKey, sizeName, tooltip } = properties;
|
|
const seriesDatum = this.contextNodeData?.nodeData.find(
|
|
(d) => d.datumIndex.type === datumIndex.type && d.datumIndex.index === datumIndex.index
|
|
);
|
|
if (seriesDatum == null)
|
|
return;
|
|
const nodeIndex = seriesDatum.type === 0 /* Link */ ? seriesDatum.fromNode.index : seriesDatum.index;
|
|
const title = seriesDatum.type === 0 /* Link */ ? `${seriesDatum.fromNode.label} - ${seriesDatum.toNode.label}` : seriesDatum.label;
|
|
const datum = datumIndex.type === 0 /* Link */ ? linksProcessedData?.dataSources.get(this.id)?.data[datumIndex.index] : nodesProcessedData?.dataSources.get(this.id)?.data[datumIndex.index];
|
|
const size = seriesDatum.size;
|
|
let format;
|
|
if (seriesDatum.type === 0 /* Link */) {
|
|
const fromNodeDatumIndex = seriesDatum.fromNode.datumIndex;
|
|
format = this.getLinkStyle({ datumIndex, datum }, fromNodeDatumIndex, false);
|
|
} else {
|
|
format = this.getNodeStyle({ datumIndex, datum }, datumIndex.index, false);
|
|
}
|
|
const data = [];
|
|
if (sizeKey != null) {
|
|
const content = formatManager.format(this.callWithContext.bind(this), {
|
|
type: "number",
|
|
value: size,
|
|
datum,
|
|
seriesId,
|
|
legendItemName: void 0,
|
|
key: sizeKey,
|
|
source: "tooltip",
|
|
property: "size",
|
|
domain: [],
|
|
boundSeries: this.getFormatterContext("size"),
|
|
fractionDigits: void 0,
|
|
visibleDomain: void 0
|
|
});
|
|
data.push({ label: sizeName, fallbackLabel: sizeKey, value: content ?? String(size) });
|
|
}
|
|
return this.formatTooltipWithContext(
|
|
tooltip,
|
|
{
|
|
title,
|
|
symbol: this.legendItemSymbol(seriesDatum.type, nodeIndex, format),
|
|
data
|
|
},
|
|
{
|
|
seriesId,
|
|
datum,
|
|
title,
|
|
fromKey,
|
|
toKey,
|
|
sizeKey,
|
|
sizeName,
|
|
size,
|
|
...format
|
|
}
|
|
);
|
|
}
|
|
computeFocusBounds(node) {
|
|
if (node instanceof Rect9) {
|
|
const { x, y, width, height } = node;
|
|
const bbox = new BBox27(x, y, width, height);
|
|
return Transformable5.toCanvas(this.contentGroup, bbox);
|
|
}
|
|
return node;
|
|
}
|
|
hasItemStylers() {
|
|
return this.properties.node.itemStyler != null || this.properties.link.itemStyler != null || this.properties.label.itemStyler != null;
|
|
}
|
|
};
|
|
SankeySeries.className = "SankeySeries";
|
|
SankeySeries.type = "sankey";
|
|
|
|
// packages/ag-charts-enterprise/src/series/sankey/sankeySeriesOptionsDef.ts
|
|
import { _ModuleSupport as _ModuleSupport206 } from "ag-charts-community";
|
|
import {
|
|
arrayOf as arrayOf4,
|
|
color as color5,
|
|
commonSeriesOptionsDefs as commonSeriesOptionsDefs21,
|
|
constant as constant22,
|
|
fillGradientDefaults as fillGradientDefaults2,
|
|
fillImageDefaults as fillImageDefaults2,
|
|
fillPatternDefaults as fillPatternDefaults2,
|
|
required as required22,
|
|
string as string22,
|
|
undocumented as undocumented17
|
|
} from "ag-charts-core";
|
|
var { sankeySeriesThemeableOptionsDef } = _ModuleSupport206;
|
|
var sankeySeriesOptionsDef = {
|
|
...sankeySeriesThemeableOptionsDef,
|
|
...commonSeriesOptionsDefs21,
|
|
type: required22(constant22("sankey")),
|
|
fromKey: required22(string22),
|
|
toKey: required22(string22),
|
|
sizeKey: string22,
|
|
sizeName: string22
|
|
};
|
|
sankeySeriesOptionsDef.fillGradientDefaults = undocumented17(fillGradientDefaults2);
|
|
sankeySeriesOptionsDef.fillPatternDefaults = undocumented17(fillPatternDefaults2);
|
|
sankeySeriesOptionsDef.fillImageDefaults = undocumented17(fillImageDefaults2);
|
|
sankeySeriesOptionsDef.defaultColorRange = undocumented17(arrayOf4(arrayOf4(color5)));
|
|
sankeySeriesOptionsDef.defaultPatternFills = undocumented17(arrayOf4(color5));
|
|
|
|
// packages/ag-charts-enterprise/src/series/sankey/sankeyModule.ts
|
|
var SankeySeriesModule = {
|
|
type: "series",
|
|
name: "sankey",
|
|
chartType: "standalone",
|
|
enterprise: true,
|
|
solo: true,
|
|
version: VERSION48,
|
|
dependencies: [StandaloneChartModule],
|
|
options: sankeySeriesOptionsDef,
|
|
themeTemplate: {
|
|
seriesArea: {
|
|
padding: {
|
|
top: 10,
|
|
bottom: 10
|
|
}
|
|
},
|
|
series: {
|
|
fills: { $palette: "fills" },
|
|
strokes: { $palette: "strokes" },
|
|
fillGradientDefaults: FILL_GRADIENT_LINEAR_DEFAULTS8,
|
|
fillPatternDefaults: FILL_PATTERN_DEFAULTS12,
|
|
fillImageDefaults: FILL_IMAGE_DEFAULTS17,
|
|
defaultColorRange: { $palette: "gradients" },
|
|
defaultPatternFills: SAFE_FILLS_OPERATION,
|
|
highlight: {
|
|
unhighlightedItem: {
|
|
opacity: 0.5
|
|
}
|
|
},
|
|
label: {
|
|
...LABEL_BOXING_DEFAULTS18,
|
|
enabled: true,
|
|
fontFamily: { $ref: "fontFamily" },
|
|
fontSize: { $ref: "fontSize" },
|
|
fontWeight: { $ref: "fontWeight" },
|
|
color: { $ref: "textColor" },
|
|
spacing: 10
|
|
},
|
|
node: {
|
|
spacing: { $if: [{ $greaterThan: [{ $path: "./minSpacing" }, 20] }, { $path: "./minSpacing" }, 20] },
|
|
minSpacing: 0,
|
|
width: 10,
|
|
strokeWidth: { $isUserOption: ["./stroke", 2, 0] }
|
|
},
|
|
link: {
|
|
fillOpacity: 0.5,
|
|
strokeWidth: { $isUserOption: ["./stroke", 2, 0] }
|
|
}
|
|
},
|
|
legend: {
|
|
enabled: false,
|
|
toggleSeries: false
|
|
}
|
|
},
|
|
create: (ctx) => new SankeySeries(ctx)
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/series/sunburst/sunburstModule.ts
|
|
import { VERSION as VERSION49 } from "ag-charts-community";
|
|
import {
|
|
BASE_FONT_SIZE,
|
|
FILL_GRADIENT_RADIAL_REVERSED_SERIES_DEFAULTS,
|
|
FILL_IMAGE_DEFAULTS as FILL_IMAGE_DEFAULTS18,
|
|
FILL_PATTERN_DEFAULTS as FILL_PATTERN_DEFAULTS13,
|
|
FONT_SIZE_RATIO as FONT_SIZE_RATIO4,
|
|
LABEL_BOXING_DEFAULTS as LABEL_BOXING_DEFAULTS19
|
|
} from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/series/sunburst/sunburstSeries.ts
|
|
import {
|
|
_ModuleSupport as _ModuleSupport208
|
|
} from "ag-charts-community";
|
|
import {
|
|
formatValue as formatValue2,
|
|
isGradientFill as isGradientFill4,
|
|
mergeDefaults as mergeDefaults23,
|
|
normalizeAngle360 as normalizeAngle3608,
|
|
toPlainText as toPlainText12
|
|
} from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/series/sunburst/sunburstSeriesProperties.ts
|
|
import { _ModuleSupport as _ModuleSupport207 } from "ag-charts-community";
|
|
import { BaseProperties as BaseProperties36, Property as Property88 } from "ag-charts-core";
|
|
var { HierarchySeriesProperties, makeSeriesTooltip: makeSeriesTooltip23, HighlightProperties } = _ModuleSupport207;
|
|
var SunburstSeriesHighlightStyle = class extends BaseProperties36 {
|
|
};
|
|
__decorateClass([
|
|
Property88
|
|
], SunburstSeriesHighlightStyle.prototype, "fill", 2);
|
|
__decorateClass([
|
|
Property88
|
|
], SunburstSeriesHighlightStyle.prototype, "fillOpacity", 2);
|
|
__decorateClass([
|
|
Property88
|
|
], SunburstSeriesHighlightStyle.prototype, "stroke", 2);
|
|
__decorateClass([
|
|
Property88
|
|
], SunburstSeriesHighlightStyle.prototype, "strokeWidth", 2);
|
|
__decorateClass([
|
|
Property88
|
|
], SunburstSeriesHighlightStyle.prototype, "strokeOpacity", 2);
|
|
__decorateClass([
|
|
Property88
|
|
], SunburstSeriesHighlightStyle.prototype, "opacity", 2);
|
|
var SunburstSeriesHighlight = class extends HighlightProperties {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.highlightedBranch = new SunburstSeriesHighlightStyle();
|
|
this.unhighlightedBranch = new SunburstSeriesHighlightStyle();
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property88
|
|
], SunburstSeriesHighlight.prototype, "highlightedBranch", 2);
|
|
__decorateClass([
|
|
Property88
|
|
], SunburstSeriesHighlight.prototype, "unhighlightedBranch", 2);
|
|
var SunburstSeriesProperties = class extends HierarchySeriesProperties {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.fillOpacity = 1;
|
|
this.strokeWidth = 0;
|
|
this.strokeOpacity = 1;
|
|
this.cornerRadius = 0;
|
|
this.highlight = new SunburstSeriesHighlight();
|
|
this.label = new AutoSizedLabel();
|
|
this.secondaryLabel = new AutoSizedSecondaryLabel();
|
|
this.tooltip = makeSeriesTooltip23();
|
|
}
|
|
getStyle(index) {
|
|
const { fills, strokes, fillOpacity, strokeWidth, strokeOpacity } = this;
|
|
return {
|
|
fill: fills[index % fills.length],
|
|
fillOpacity,
|
|
stroke: strokes[index % strokes.length],
|
|
strokeWidth,
|
|
strokeOpacity,
|
|
opacity: 1
|
|
};
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property88
|
|
], SunburstSeriesProperties.prototype, "sizeName", 2);
|
|
__decorateClass([
|
|
Property88
|
|
], SunburstSeriesProperties.prototype, "labelKey", 2);
|
|
__decorateClass([
|
|
Property88
|
|
], SunburstSeriesProperties.prototype, "secondaryLabelKey", 2);
|
|
__decorateClass([
|
|
Property88
|
|
], SunburstSeriesProperties.prototype, "fillOpacity", 2);
|
|
__decorateClass([
|
|
Property88
|
|
], SunburstSeriesProperties.prototype, "strokeWidth", 2);
|
|
__decorateClass([
|
|
Property88
|
|
], SunburstSeriesProperties.prototype, "strokeOpacity", 2);
|
|
__decorateClass([
|
|
Property88
|
|
], SunburstSeriesProperties.prototype, "cornerRadius", 2);
|
|
__decorateClass([
|
|
Property88
|
|
], SunburstSeriesProperties.prototype, "sectorSpacing", 2);
|
|
__decorateClass([
|
|
Property88
|
|
], SunburstSeriesProperties.prototype, "padding", 2);
|
|
__decorateClass([
|
|
Property88
|
|
], SunburstSeriesProperties.prototype, "itemStyler", 2);
|
|
__decorateClass([
|
|
Property88
|
|
], SunburstSeriesProperties.prototype, "highlight", 2);
|
|
__decorateClass([
|
|
Property88
|
|
], SunburstSeriesProperties.prototype, "label", 2);
|
|
__decorateClass([
|
|
Property88
|
|
], SunburstSeriesProperties.prototype, "secondaryLabel", 2);
|
|
__decorateClass([
|
|
Property88
|
|
], SunburstSeriesProperties.prototype, "tooltip", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/series/sunburst/sunburstSeries.ts
|
|
var {
|
|
fromToMotion: fromToMotion6,
|
|
createDatumId: createDatumId22,
|
|
PointerEvents: PointerEvents13,
|
|
Sector: Sector7,
|
|
Group: Group21,
|
|
ScalableGroup,
|
|
Selection: Selection17,
|
|
TransformableText: TransformableText4,
|
|
BBox: BBox28,
|
|
getLabelStyles: getLabelStyles7,
|
|
toHierarchyHighlightString
|
|
} = _ModuleSupport208;
|
|
var SunburstNode = class extends _ModuleSupport208.HierarchyNode {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.label = void 0;
|
|
this.secondaryLabel = void 0;
|
|
this.contentHeight = 0;
|
|
this.bbox = void 0;
|
|
// cspell:ignore bbox
|
|
this.startAngle = 0;
|
|
this.endAngle = 0;
|
|
}
|
|
};
|
|
function setAngleData(node, startAngle = 0, angleScale = 2 * Math.PI / node.sumSize) {
|
|
for (const child of node.children) {
|
|
const endAngle = startAngle + child.sumSize * angleScale;
|
|
child.startAngle = startAngle;
|
|
child.endAngle = endAngle;
|
|
setAngleData(child, startAngle, angleScale);
|
|
startAngle = endAngle;
|
|
}
|
|
}
|
|
var SunburstSeries = class extends _ModuleSupport208.HierarchySeries {
|
|
constructor(moduleCtx) {
|
|
super(moduleCtx);
|
|
this.NodeClass = SunburstNode;
|
|
this.properties = new SunburstSeriesProperties();
|
|
this.scalingGroup = this.contentGroup.appendChild(new ScalableGroup());
|
|
this.sectorGroup = this.scalingGroup.appendChild(new Group21());
|
|
this.highlightSectorGroup = this.scalingGroup.appendChild(new Group21());
|
|
this.sectorLabelGroup = this.scalingGroup.appendChild(new Group21());
|
|
this.datumSelection = Selection17.select(this.sectorGroup, Sector7);
|
|
this.labelSelection = Selection17.select(
|
|
this.sectorLabelGroup,
|
|
Group21
|
|
);
|
|
this.highlightSelection = Selection17.select(
|
|
this.highlightSectorGroup,
|
|
Sector7
|
|
);
|
|
this.sectorLabelGroup.pointerEvents = PointerEvents13.None;
|
|
}
|
|
processData() {
|
|
super.processData();
|
|
setAngleData(this.rootNode);
|
|
}
|
|
updateSelections() {
|
|
const highlightedNode = this.getActiveHighlightNode();
|
|
this.highlightSelection.update(
|
|
highlightedNode == null ? [] : [highlightedNode],
|
|
void 0,
|
|
(node) => this.getDatumId(node)
|
|
);
|
|
if (!this.nodeDataRefresh)
|
|
return;
|
|
this.nodeDataRefresh = false;
|
|
const { chart } = this;
|
|
if (chart == null)
|
|
return;
|
|
const seriesRect = chart.seriesRect;
|
|
if (seriesRect == null)
|
|
return;
|
|
const descendants = Array.from(this.rootNode);
|
|
const updateLabelGroup = (group) => {
|
|
group.append([
|
|
new TransformableText4({ tag: 0 /* Primary */ }),
|
|
new TransformableText4({ tag: 1 /* Secondary */ })
|
|
]);
|
|
};
|
|
this.datumSelection.update(descendants, void 0, (node) => this.getDatumId(node));
|
|
this.labelSelection.update(descendants, updateLabelGroup, (node) => this.getDatumId(node));
|
|
}
|
|
getItemStyle(nodeDatum, isHighlight) {
|
|
const { properties, colorScale } = this;
|
|
const { itemStyler } = properties;
|
|
const rootIndex = nodeDatum.datumIndex?.[0] ?? 0;
|
|
const highlightedNode = this.getActiveHighlightNode();
|
|
const highlightState = this.getHierarchyHighlightState(isHighlight, highlightedNode, nodeDatum);
|
|
const highlightStyles = this.getHierarchyHighlightStyles(highlightState, this.properties.highlight);
|
|
const baseStyle = mergeDefaults23(highlightStyles, properties.getStyle(rootIndex));
|
|
if (nodeDatum.colorValue != null && highlightStyles?.fill == null) {
|
|
baseStyle.fill = colorScale.convert(nodeDatum.colorValue);
|
|
}
|
|
let style = baseStyle;
|
|
if (itemStyler != null && nodeDatum != null) {
|
|
const overrides = this.cachedDatumCallback(
|
|
createDatumId22(this.getDatumId(nodeDatum), isHighlight ? "highlight" : "node"),
|
|
() => {
|
|
const params = this.makeItemStylerParams(
|
|
nodeDatum,
|
|
style,
|
|
toHierarchyHighlightString(highlightState)
|
|
);
|
|
return this.callWithContext(itemStyler, params);
|
|
}
|
|
);
|
|
if (overrides) {
|
|
style = mergeDefaults23(overrides, style);
|
|
}
|
|
}
|
|
return style;
|
|
}
|
|
makeItemStylerParams(nodeDatum, style, highlightState) {
|
|
const { id: seriesId } = this;
|
|
const fill = this.filterItemStylerFillParams(style.fill) ?? style.fill;
|
|
return {
|
|
seriesId,
|
|
datum: nodeDatum.datum,
|
|
depth: nodeDatum.depth ?? 0,
|
|
highlightState,
|
|
...style,
|
|
fill
|
|
};
|
|
}
|
|
updateNodes() {
|
|
const { chart, data, maxDepth } = this;
|
|
if (chart == null || data == null) {
|
|
return;
|
|
}
|
|
const { width, height } = chart.seriesRect;
|
|
const {
|
|
sectorSpacing = 0,
|
|
padding: padding2 = 0,
|
|
cornerRadius,
|
|
childrenKey,
|
|
colorKey,
|
|
colorName,
|
|
labelKey,
|
|
secondaryLabelKey,
|
|
sizeKey,
|
|
sizeName
|
|
} = this.properties;
|
|
this.contentGroup.translationX = width / 2;
|
|
this.contentGroup.translationY = height / 2;
|
|
const baseInset = sectorSpacing * 0.5;
|
|
const radius = Math.min(width, height) / 2;
|
|
const radiusScale = radius / (maxDepth + 1);
|
|
const angleOffset = -Math.PI / 2;
|
|
const seriesFillBBox = {
|
|
series: new BBox28(-radius, -radius, 2 * radius, 2 * radius),
|
|
axis: new BBox28(-radius, -radius, 2 * radius, 2 * radius)
|
|
};
|
|
this.rootNode?.walk((node) => {
|
|
const { startAngle, endAngle } = node;
|
|
if (node.depth != null) {
|
|
const midAngle = (startAngle + endAngle) / 2 + angleOffset;
|
|
const midRadius = (node.depth + 0.5) * radiusScale;
|
|
node.midPoint.x = Math.cos(midAngle) * midRadius;
|
|
node.midPoint.y = Math.sin(midAngle) * midRadius;
|
|
}
|
|
});
|
|
this.rootNode?.walk((node) => {
|
|
const { datum, depth, startAngle, endAngle, parent, sumSize } = node;
|
|
node.label = void 0;
|
|
node.secondaryLabel = void 0;
|
|
node.contentHeight = 0;
|
|
let labelValue;
|
|
if (datum != null && depth != null && labelKey != null) {
|
|
const value = datum[labelKey];
|
|
labelValue = this.getLabelText(
|
|
value,
|
|
datum,
|
|
labelKey,
|
|
"label",
|
|
[],
|
|
this.properties.label,
|
|
{
|
|
depth,
|
|
datum,
|
|
childrenKey,
|
|
colorKey,
|
|
colorName,
|
|
labelKey,
|
|
secondaryLabelKey,
|
|
sizeKey,
|
|
sizeName,
|
|
value
|
|
}
|
|
);
|
|
}
|
|
if (labelValue === "") {
|
|
labelValue = void 0;
|
|
}
|
|
let secondaryLabelValue;
|
|
if (datum != null && depth != null && secondaryLabelKey != null) {
|
|
const value = datum[secondaryLabelKey];
|
|
secondaryLabelValue = this.getLabelText(
|
|
value,
|
|
datum,
|
|
secondaryLabelKey,
|
|
"secondaryLabel",
|
|
[],
|
|
this.properties.secondaryLabel,
|
|
{
|
|
depth,
|
|
datum,
|
|
childrenKey,
|
|
colorKey,
|
|
colorName,
|
|
labelKey,
|
|
secondaryLabelKey,
|
|
sizeKey,
|
|
sizeName,
|
|
value
|
|
}
|
|
);
|
|
}
|
|
if (secondaryLabelValue === "") {
|
|
secondaryLabelValue = void 0;
|
|
}
|
|
if (depth == null)
|
|
return;
|
|
const innerRadius = depth * radiusScale + baseInset;
|
|
const outerRadius = (depth + 1) * radiusScale - baseInset;
|
|
const innerAngleOffset = innerRadius > baseInset ? baseInset / innerRadius : baseInset;
|
|
const outerAngleOffset = outerRadius > baseInset ? baseInset / outerRadius : baseInset;
|
|
const innerStartAngle = startAngle + innerAngleOffset;
|
|
const innerEndAngle = endAngle + innerAngleOffset;
|
|
const deltaInnerAngle = innerEndAngle - innerStartAngle;
|
|
const outerStartAngle = startAngle + outerAngleOffset;
|
|
const outerEndAngle = endAngle + outerAngleOffset;
|
|
const deltaOuterAngle = outerEndAngle - outerStartAngle;
|
|
const sizeFittingHeight = (labelHeight2) => {
|
|
const isCenterCircle = depth === 0 && parent?.sumSize === sumSize;
|
|
if (isCenterCircle) {
|
|
const labelWidth2 = 2 * Math.sqrt(outerRadius ** 2 - (labelHeight2 * 0.5) ** 2);
|
|
return { width: labelWidth2, height: labelHeight2, meta: 0 /* CenterCircle */ };
|
|
}
|
|
const parallelHeight = labelHeight2;
|
|
const availableWidthUntilItHitsTheOuterRadius = 2 * Math.sqrt(outerRadius ** 2 - (innerRadius + parallelHeight) ** 2);
|
|
const availableWidthUntilItHitsTheStraightEdges = deltaInnerAngle < Math.PI ? 2 * innerRadius * Math.tan(deltaInnerAngle * 0.5) : Infinity;
|
|
const parallelWidth = Math.min(
|
|
availableWidthUntilItHitsTheOuterRadius,
|
|
availableWidthUntilItHitsTheStraightEdges
|
|
);
|
|
const maxPerpendicularAngle = Math.PI / 4;
|
|
let perpendicularHeight;
|
|
let perpendicularWidth;
|
|
if (depth === 0) {
|
|
perpendicularHeight = labelHeight2;
|
|
perpendicularWidth = Math.sqrt(outerRadius ** 2 - (perpendicularHeight / 2) ** 2) - labelHeight2 / (2 * Math.tan(deltaOuterAngle * 0.5));
|
|
} else if (normalizeAngle3608(deltaInnerAngle) < maxPerpendicularAngle) {
|
|
perpendicularHeight = 2 * innerRadius * Math.tan(deltaInnerAngle * 0.5);
|
|
perpendicularWidth = Math.sqrt(outerRadius ** 2 - (perpendicularHeight / 2) ** 2) - innerRadius;
|
|
} else {
|
|
perpendicularWidth = 0;
|
|
perpendicularHeight = 0;
|
|
}
|
|
return parallelWidth >= perpendicularWidth ? { width: parallelWidth, height: parallelHeight, meta: 1 /* Parallel */ } : { width: perpendicularWidth, height: perpendicularHeight, meta: 2 /* Perpendicular */ };
|
|
};
|
|
const formatting = formatLabels(
|
|
toPlainText12(labelValue),
|
|
this.properties.label,
|
|
toPlainText12(secondaryLabelValue),
|
|
this.properties.secondaryLabel,
|
|
{ padding: padding2 },
|
|
sizeFittingHeight
|
|
);
|
|
if (formatting == null)
|
|
return;
|
|
const { width: labelWidth, height: labelHeight, meta: labelPlacement, label, secondaryLabel } = formatting;
|
|
const theta = angleOffset + (startAngle + endAngle) / 2;
|
|
const top = Math.sin(theta) >= 0;
|
|
const right = Math.cos(theta) >= 0;
|
|
const circleQuarter = (top ? 3 /* Top */ : 12 /* Bottom */) & (right ? 6 /* Right */ : 9 /* Left */);
|
|
let labelRadius;
|
|
switch (labelPlacement) {
|
|
case 0 /* CenterCircle */:
|
|
labelRadius = 0;
|
|
break;
|
|
case 1 /* Parallel */: {
|
|
const opticalCentering = 0.58;
|
|
const idealRadius = outerRadius - (radiusScale - labelHeight) * opticalCentering;
|
|
const maximumRadius = Math.sqrt((outerRadius - padding2) ** 2 - (labelWidth / 2) ** 2);
|
|
labelRadius = Math.min(idealRadius, maximumRadius);
|
|
break;
|
|
}
|
|
case 2 /* Perpendicular */:
|
|
if (depth === 0) {
|
|
const minimumRadius = labelHeight / (2 * Math.tan(deltaInnerAngle * 0.5)) + labelWidth * 0.5;
|
|
const maximumRadius = Math.sqrt(outerRadius ** 2 - (labelHeight * 0.5) ** 2) - labelWidth * 0.5;
|
|
labelRadius = (minimumRadius + maximumRadius) * 0.5;
|
|
} else {
|
|
labelRadius = (innerRadius + outerRadius) * 0.5;
|
|
}
|
|
break;
|
|
}
|
|
if (label != null) {
|
|
const {
|
|
fontStyle = "normal",
|
|
fontFamily,
|
|
fontWeight = "normal",
|
|
color: color7 = "black"
|
|
} = this.properties.label;
|
|
node.label = {
|
|
...label,
|
|
fontStyle,
|
|
fontFamily,
|
|
fontWeight,
|
|
color: color7,
|
|
labelPlacement,
|
|
circleQuarter,
|
|
radius: labelRadius,
|
|
theta
|
|
};
|
|
}
|
|
if (secondaryLabel != null) {
|
|
const {
|
|
fontStyle = "normal",
|
|
fontFamily,
|
|
fontWeight = "normal",
|
|
color: color7 = "black"
|
|
} = this.properties.secondaryLabel;
|
|
node.secondaryLabel = {
|
|
...secondaryLabel,
|
|
fontStyle,
|
|
fontFamily,
|
|
fontWeight,
|
|
color: color7,
|
|
labelPlacement,
|
|
circleQuarter,
|
|
radius: labelRadius,
|
|
theta
|
|
};
|
|
}
|
|
node.contentHeight = formatting.height;
|
|
});
|
|
const updateSector = (nodeDatum, sector, highlighted) => {
|
|
const { depth, startAngle, endAngle } = nodeDatum;
|
|
if (depth == null) {
|
|
sector.visible = false;
|
|
return;
|
|
}
|
|
sector.visible = true;
|
|
const style = this.getItemStyle(nodeDatum, highlighted);
|
|
const fill = style.fill;
|
|
const strokeWidth = style.strokeWidth;
|
|
const fillBBox = isGradientFill4(fill) && fill.bounds !== "item" ? seriesFillBBox : void 0;
|
|
sector.setStyleProperties(style, fillBBox);
|
|
sector.centerX = 0;
|
|
sector.centerY = 0;
|
|
sector.innerRadius = depth * radiusScale;
|
|
sector.outerRadius = (depth + 1) * radiusScale;
|
|
sector.startAngle = startAngle + angleOffset;
|
|
sector.endAngle = endAngle + angleOffset;
|
|
sector.inset = baseInset + strokeWidth * 0.5;
|
|
sector.cornerRadius = cornerRadius;
|
|
};
|
|
this.datumSelection.each((sector, datum) => {
|
|
updateSector(datum, sector, false);
|
|
});
|
|
this.highlightSelection.each((rect, datum) => {
|
|
updateSector(datum, rect, true);
|
|
});
|
|
const highlightedNode = this.getActiveHighlightNode();
|
|
const updateText = (node, text2, tag, highlighted) => {
|
|
const { depth, contentHeight } = node;
|
|
const primary = tag === 0 /* Primary */;
|
|
const label = primary ? node.label : node.secondaryLabel;
|
|
if (depth == null || label == null) {
|
|
text2.visible = false;
|
|
return;
|
|
}
|
|
const { labelPlacement, circleQuarter, radius: textRadius, theta } = label;
|
|
const highlightState = this.getHierarchyHighlightState(highlighted, highlightedNode, node);
|
|
const { opacity: highlightOpacity } = this.getHierarchyHighlightStyles(highlightState, this.properties.highlight) ?? {};
|
|
const params = {
|
|
childrenKey: this.properties.childrenKey,
|
|
colorKey: this.properties.colorKey,
|
|
colorName: this.properties.colorName ?? this.properties.colorKey,
|
|
depth: node.depth ?? Number.NaN,
|
|
labelKey: this.properties.labelKey,
|
|
secondaryLabelKey: this.properties.secondaryLabelKey,
|
|
sizeKey: this.properties.sizeKey,
|
|
sizeName: this.properties.sizeName ?? this.properties.sizeKey
|
|
};
|
|
const baseLabelStyle = primary ? this.properties.label : this.properties.secondaryLabel;
|
|
const activeHighlight = this.ctx.highlightManager?.getActiveHighlight();
|
|
const style = getLabelStyles7(this, node, params, baseLabelStyle, highlighted, activeHighlight);
|
|
text2.text = label.text;
|
|
text2.fontSize = label.fontSize;
|
|
text2.lineHeight = label.lineHeight;
|
|
text2.fontStyle = label.fontStyle;
|
|
text2.fontFamily = label.fontFamily;
|
|
text2.fontWeight = label.fontWeight;
|
|
text2.fillOpacity = highlightOpacity ?? 1;
|
|
text2.fill = style.color;
|
|
text2.setBoxing(style);
|
|
switch (labelPlacement) {
|
|
case 0 /* CenterCircle */:
|
|
text2.textAlign = "center";
|
|
text2.textBaseline = "top";
|
|
text2.translationX = 0;
|
|
text2.translationY = (primary ? 0 : contentHeight - label.height) - contentHeight * 0.5;
|
|
text2.rotation = 0;
|
|
break;
|
|
case 1 /* Parallel */: {
|
|
const topHalf = (circleQuarter & 3 /* Top */) !== 0;
|
|
const translationRadius = primary === !topHalf ? textRadius : textRadius - (contentHeight - label.height);
|
|
text2.textAlign = "center";
|
|
text2.textBaseline = topHalf ? "bottom" : "top";
|
|
text2.translationX = Math.cos(theta) * translationRadius;
|
|
text2.translationY = Math.sin(theta) * translationRadius;
|
|
text2.rotation = topHalf ? theta - Math.PI * 0.5 : theta + Math.PI * 0.5;
|
|
break;
|
|
}
|
|
case 2 /* Perpendicular */: {
|
|
const rightHalf = (circleQuarter & 6 /* Right */) !== 0;
|
|
const translation = primary === !rightHalf ? (contentHeight - label.height) * 0.5 : (label.height - contentHeight) * 0.5;
|
|
text2.textAlign = "center";
|
|
text2.textBaseline = "middle";
|
|
text2.translationX = Math.cos(theta) * textRadius + Math.cos(theta + Math.PI / 2) * translation;
|
|
text2.translationY = Math.sin(theta) * textRadius + Math.sin(theta + Math.PI / 2) * translation;
|
|
text2.rotation = rightHalf ? theta : theta + Math.PI;
|
|
break;
|
|
}
|
|
}
|
|
text2.visible = true;
|
|
};
|
|
const highlightedDatum = this.getActiveHighlightNode();
|
|
for (const text2 of this.labelSelection.selectByClass(TransformableText4)) {
|
|
const datum = text2.closestDatum();
|
|
updateText(datum, text2, text2.tag, datum === highlightedDatum);
|
|
}
|
|
}
|
|
getTooltipContent(datumIndex) {
|
|
const { id: seriesId, properties, ctx } = this;
|
|
const { labelKey, secondaryLabelKey, childrenKey, sizeKey, sizeName, colorKey, colorName, tooltip } = properties;
|
|
const { formatManager } = ctx;
|
|
const nodeDatum = datumIndex.reduce((n, i) => n?.children[i], this.rootNode);
|
|
if (nodeDatum == null)
|
|
return;
|
|
const { datum, depth } = nodeDatum;
|
|
if (datum == null || depth == null)
|
|
return;
|
|
const data = [];
|
|
const datumSize = sizeKey == null ? void 0 : datum[sizeKey];
|
|
if (datumSize != null) {
|
|
const sizeDomain = [0, this.rootNode?.sumSize ?? 0];
|
|
const content = formatManager.format(this.callWithContext.bind(this), {
|
|
type: "number",
|
|
value: datumSize,
|
|
datum,
|
|
seriesId,
|
|
legendItemName: void 0,
|
|
key: sizeKey,
|
|
source: "tooltip",
|
|
property: "size",
|
|
boundSeries: this.getFormatterContext("size"),
|
|
domain: sizeDomain,
|
|
fractionDigits: void 0,
|
|
visibleDomain: void 0
|
|
});
|
|
data.push({ label: sizeName, fallbackLabel: sizeKey, value: content ?? formatValue2(datumSize) });
|
|
}
|
|
const datumColor = colorKey == null ? void 0 : datum[colorKey];
|
|
if (datumColor != null) {
|
|
const { colorDomain } = this;
|
|
const content = formatManager.format(this.callWithContext.bind(this), {
|
|
type: "number",
|
|
value: datumColor,
|
|
datum,
|
|
seriesId,
|
|
legendItemName: void 0,
|
|
key: colorKey,
|
|
source: "tooltip",
|
|
property: "color",
|
|
boundSeries: this.getFormatterContext("color"),
|
|
domain: colorDomain,
|
|
fractionDigits: void 0,
|
|
visibleDomain: void 0
|
|
});
|
|
data.push({ label: colorName, fallbackLabel: colorKey, value: content ?? formatValue2(datumColor) });
|
|
}
|
|
const format = this.getItemStyle(
|
|
{ ...nodeDatum, colorValue: datumColor ?? nodeDatum.colorValue },
|
|
false
|
|
);
|
|
const color7 = format.fill;
|
|
const markerStyle = {
|
|
shape: "square",
|
|
fill: color7,
|
|
fillOpacity: 1,
|
|
stroke: void 0,
|
|
strokeWidth: 0,
|
|
strokeOpacity: 1,
|
|
lineDash: [0],
|
|
lineDashOffset: 0
|
|
};
|
|
if (isGradientFill4(markerStyle.fill)) {
|
|
markerStyle.fill = { ...markerStyle.fill, gradient: "linear", rotation: 0, reverse: false };
|
|
}
|
|
return this.formatTooltipWithContext(
|
|
tooltip,
|
|
{
|
|
title: labelKey == null ? void 0 : datum[labelKey],
|
|
symbol: {
|
|
marker: markerStyle
|
|
},
|
|
data
|
|
},
|
|
{
|
|
seriesId,
|
|
datum,
|
|
title: void 0,
|
|
depth,
|
|
labelKey,
|
|
secondaryLabelKey,
|
|
childrenKey,
|
|
sizeKey,
|
|
sizeName,
|
|
colorKey,
|
|
colorName,
|
|
...format
|
|
}
|
|
);
|
|
}
|
|
createNodeData() {
|
|
return void 0;
|
|
}
|
|
pickNodeClosestDatum(point) {
|
|
return this.pickNodeNearestDistantObject(point, this.datumSelection.nodes());
|
|
}
|
|
animateEmptyUpdateReady() {
|
|
fromToMotion6(this.id, "nodes", this.ctx.animationManager, [this.scalingGroup], {
|
|
toFn() {
|
|
return { scalingX: 1, scalingY: 1 };
|
|
},
|
|
fromFn() {
|
|
return { scalingX: 0, scalingY: 0 };
|
|
}
|
|
});
|
|
}
|
|
computeFocusBounds(node) {
|
|
return node;
|
|
}
|
|
hasItemStylers() {
|
|
return this.properties.itemStyler != null || this.properties.label.itemStyler != null;
|
|
}
|
|
};
|
|
SunburstSeries.className = "SunburstSeries";
|
|
SunburstSeries.type = "sunburst";
|
|
|
|
// packages/ag-charts-enterprise/src/series/sunburst/sunburstSeriesOptionsDef.ts
|
|
import { _ModuleSupport as _ModuleSupport209 } from "ag-charts-community";
|
|
import { commonSeriesOptionsDefs as commonSeriesOptionsDefs22, constant as constant23, required as required23, string as string23, without as without9 } from "ag-charts-core";
|
|
var { sunburstSeriesThemeableOptionsDef } = _ModuleSupport209;
|
|
var sunburstSeriesOptionsDef = {
|
|
...sunburstSeriesThemeableOptionsDef,
|
|
...without9(commonSeriesOptionsDefs22, ["highlightStyle", "highlight", "showInLegend"]),
|
|
type: required23(constant23("sunburst")),
|
|
labelKey: string23,
|
|
secondaryLabelKey: string23,
|
|
childrenKey: string23,
|
|
sizeKey: string23,
|
|
colorKey: string23,
|
|
sizeName: string23,
|
|
colorName: string23
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/series/sunburst/sunburstModule.ts
|
|
var themeTemplate3 = {
|
|
series: {
|
|
fills: {
|
|
$applyCycle: [
|
|
{ $size: { $path: ["./data", { $path: "/data" }] } },
|
|
{ $palette: "fills" },
|
|
{
|
|
$applySwitch: [
|
|
{ $path: ["/type", void 0, { $value: "$1" }] },
|
|
{ $value: "$1" },
|
|
["gradient", FILL_GRADIENT_RADIAL_REVERSED_SERIES_DEFAULTS],
|
|
["pattern", FILL_PATTERN_DEFAULTS13],
|
|
["image", FILL_IMAGE_DEFAULTS18]
|
|
]
|
|
}
|
|
]
|
|
},
|
|
strokes: {
|
|
$applyCycle: [{ $size: { $path: ["./data", { $path: "/data" }] } }, { $palette: "strokes" }]
|
|
},
|
|
colorRange: { $palette: "divergingColors" },
|
|
strokeWidth: { $isUserOption: ["./strokes/0", 2, 0] },
|
|
label: {
|
|
...LABEL_BOXING_DEFAULTS19,
|
|
enabled: true,
|
|
fontFamily: { $ref: "fontFamily" },
|
|
fontSize: { $rem: FONT_SIZE_RATIO4.LARGE },
|
|
minimumFontSize: { $rem: 9 / BASE_FONT_SIZE },
|
|
fontWeight: { $ref: "fontWeight" },
|
|
color: { $ref: "chartBackgroundColor" },
|
|
overflowStrategy: "ellipsis",
|
|
wrapping: "never",
|
|
spacing: 2
|
|
},
|
|
secondaryLabel: {
|
|
...LABEL_BOXING_DEFAULTS19,
|
|
enabled: true,
|
|
fontFamily: { $ref: "fontFamily" },
|
|
fontSize: { $rem: FONT_SIZE_RATIO4.SMALLEST },
|
|
minimumFontSize: { $rem: 7 / BASE_FONT_SIZE },
|
|
fontWeight: { $ref: "fontWeight" },
|
|
color: { $ref: "chartBackgroundColor" },
|
|
overflowStrategy: "ellipsis",
|
|
wrapping: "never"
|
|
},
|
|
sectorSpacing: 2,
|
|
padding: 3,
|
|
highlight: {
|
|
unhighlightedItem: {
|
|
fillOpacity: 0.6,
|
|
strokeOpacity: 0.6
|
|
},
|
|
unhighlightedBranch: {
|
|
fillOpacity: 0.2,
|
|
strokeOpacity: 0.2
|
|
}
|
|
}
|
|
},
|
|
gradientLegend: {
|
|
enabled: { $if: [{ $path: "../series/0/colorKey" }, true, false] }
|
|
}
|
|
};
|
|
var SunburstSeriesModule = {
|
|
type: "series",
|
|
name: "sunburst",
|
|
chartType: "standalone",
|
|
enterprise: true,
|
|
solo: true,
|
|
version: VERSION49,
|
|
dependencies: [StandaloneChartModule],
|
|
options: sunburstSeriesOptionsDef,
|
|
themeTemplate: themeTemplate3,
|
|
create: (ctx) => new SunburstSeries(ctx)
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/series/treemap/treemapModule.ts
|
|
import { VERSION as VERSION50 } from "ag-charts-community";
|
|
import {
|
|
FILL_GRADIENT_LINEAR_DEFAULTS as FILL_GRADIENT_LINEAR_DEFAULTS9,
|
|
FILL_IMAGE_DEFAULTS as FILL_IMAGE_DEFAULTS19,
|
|
FILL_PATTERN_DEFAULTS as FILL_PATTERN_DEFAULTS14,
|
|
FONT_SIZE_RATIO as FONT_SIZE_RATIO5,
|
|
LABEL_BOXING_DEFAULTS as LABEL_BOXING_DEFAULTS20
|
|
} from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/series/treemap/treemapSeries.ts
|
|
import {
|
|
_ModuleSupport as _ModuleSupport211
|
|
} from "ag-charts-community";
|
|
import {
|
|
cachedTextMeasurer as cachedTextMeasurer13,
|
|
calcLineHeight as calcLineHeight8,
|
|
formatValue as formatValue3,
|
|
isGradientFill as isGradientFill5,
|
|
isNumberEqual as isNumberEqual11,
|
|
mergeDefaults as mergeDefaults24,
|
|
toPlainText as toPlainText13,
|
|
wrapText as wrapText5
|
|
} from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/series/treemap/treemapSeriesProperties.ts
|
|
import { _ModuleSupport as _ModuleSupport210 } from "ag-charts-community";
|
|
import { BaseProperties as BaseProperties37, Property as Property89 } from "ag-charts-core";
|
|
var { HierarchySeriesProperties: HierarchySeriesProperties2, makeSeriesTooltip: makeSeriesTooltip24, Label: Label18 } = _ModuleSupport210;
|
|
var TreemapGroupLabel = class extends Label18 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.spacing = 0;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property89
|
|
], TreemapGroupLabel.prototype, "spacing", 2);
|
|
var TreemapSeriesGroupHighlightStyle = class extends BaseProperties37 {
|
|
};
|
|
__decorateClass([
|
|
Property89
|
|
], TreemapSeriesGroupHighlightStyle.prototype, "fill", 2);
|
|
__decorateClass([
|
|
Property89
|
|
], TreemapSeriesGroupHighlightStyle.prototype, "fillOpacity", 2);
|
|
__decorateClass([
|
|
Property89
|
|
], TreemapSeriesGroupHighlightStyle.prototype, "stroke", 2);
|
|
__decorateClass([
|
|
Property89
|
|
], TreemapSeriesGroupHighlightStyle.prototype, "strokeWidth", 2);
|
|
__decorateClass([
|
|
Property89
|
|
], TreemapSeriesGroupHighlightStyle.prototype, "strokeOpacity", 2);
|
|
__decorateClass([
|
|
Property89
|
|
], TreemapSeriesGroupHighlightStyle.prototype, "opacity", 2);
|
|
var TreemapSeriesGroupHighlight = class extends BaseProperties37 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.highlightedItem = new TreemapSeriesGroupHighlightStyle();
|
|
this.unhighlightedItem = new TreemapSeriesGroupHighlightStyle();
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property89
|
|
], TreemapSeriesGroupHighlight.prototype, "highlightedItem", 2);
|
|
__decorateClass([
|
|
Property89
|
|
], TreemapSeriesGroupHighlight.prototype, "unhighlightedItem", 2);
|
|
var TreemapSeriesTileHighlightStyle = class extends BaseProperties37 {
|
|
};
|
|
__decorateClass([
|
|
Property89
|
|
], TreemapSeriesTileHighlightStyle.prototype, "fill", 2);
|
|
__decorateClass([
|
|
Property89
|
|
], TreemapSeriesTileHighlightStyle.prototype, "fillOpacity", 2);
|
|
__decorateClass([
|
|
Property89
|
|
], TreemapSeriesTileHighlightStyle.prototype, "stroke", 2);
|
|
__decorateClass([
|
|
Property89
|
|
], TreemapSeriesTileHighlightStyle.prototype, "strokeWidth", 2);
|
|
__decorateClass([
|
|
Property89
|
|
], TreemapSeriesTileHighlightStyle.prototype, "strokeOpacity", 2);
|
|
__decorateClass([
|
|
Property89
|
|
], TreemapSeriesTileHighlightStyle.prototype, "opacity", 2);
|
|
var TreemapSeriesTileHighlight = class extends BaseProperties37 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.highlightedBranch = new TreemapSeriesTileHighlightStyle();
|
|
this.highlightedItem = new TreemapSeriesTileHighlightStyle();
|
|
this.unhighlightedItem = new TreemapSeriesTileHighlightStyle();
|
|
this.unhighlightedBranch = new TreemapSeriesTileHighlightStyle();
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property89
|
|
], TreemapSeriesTileHighlight.prototype, "highlightedBranch", 2);
|
|
__decorateClass([
|
|
Property89
|
|
], TreemapSeriesTileHighlight.prototype, "highlightedItem", 2);
|
|
__decorateClass([
|
|
Property89
|
|
], TreemapSeriesTileHighlight.prototype, "unhighlightedItem", 2);
|
|
__decorateClass([
|
|
Property89
|
|
], TreemapSeriesTileHighlight.prototype, "unhighlightedBranch", 2);
|
|
var TreemapSeriesGroup = class extends BaseProperties37 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.fill = void 0;
|
|
this.fillOpacity = 1;
|
|
this.strokeWidth = 1;
|
|
this.strokeOpacity = 1;
|
|
this.cornerRadius = 0;
|
|
this.textAlign = "center";
|
|
this.gap = 0;
|
|
this.padding = 0;
|
|
this.interactive = true;
|
|
this.label = new TreemapGroupLabel();
|
|
this.highlight = new TreemapSeriesGroupHighlight();
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property89
|
|
], TreemapSeriesGroup.prototype, "fill", 2);
|
|
__decorateClass([
|
|
Property89
|
|
], TreemapSeriesGroup.prototype, "fillOpacity", 2);
|
|
__decorateClass([
|
|
Property89
|
|
], TreemapSeriesGroup.prototype, "stroke", 2);
|
|
__decorateClass([
|
|
Property89
|
|
], TreemapSeriesGroup.prototype, "strokeWidth", 2);
|
|
__decorateClass([
|
|
Property89
|
|
], TreemapSeriesGroup.prototype, "strokeOpacity", 2);
|
|
__decorateClass([
|
|
Property89
|
|
], TreemapSeriesGroup.prototype, "cornerRadius", 2);
|
|
__decorateClass([
|
|
Property89
|
|
], TreemapSeriesGroup.prototype, "textAlign", 2);
|
|
__decorateClass([
|
|
Property89
|
|
], TreemapSeriesGroup.prototype, "gap", 2);
|
|
__decorateClass([
|
|
Property89
|
|
], TreemapSeriesGroup.prototype, "padding", 2);
|
|
__decorateClass([
|
|
Property89
|
|
], TreemapSeriesGroup.prototype, "interactive", 2);
|
|
__decorateClass([
|
|
Property89
|
|
], TreemapSeriesGroup.prototype, "label", 2);
|
|
__decorateClass([
|
|
Property89
|
|
], TreemapSeriesGroup.prototype, "highlight", 2);
|
|
var TreemapSeriesTile = class extends BaseProperties37 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.fill = void 0;
|
|
this.fillOpacity = 1;
|
|
this.strokeWidth = 1;
|
|
this.strokeOpacity = 1;
|
|
this.cornerRadius = 0;
|
|
this.textAlign = "center";
|
|
this.verticalAlign = "middle";
|
|
this.gap = 0;
|
|
this.padding = 0;
|
|
this.label = new AutoSizedLabel();
|
|
this.secondaryLabel = new AutoSizedSecondaryLabel();
|
|
this.highlight = new TreemapSeriesTileHighlight();
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property89
|
|
], TreemapSeriesTile.prototype, "fill", 2);
|
|
__decorateClass([
|
|
Property89
|
|
], TreemapSeriesTile.prototype, "fillOpacity", 2);
|
|
__decorateClass([
|
|
Property89
|
|
], TreemapSeriesTile.prototype, "stroke", 2);
|
|
__decorateClass([
|
|
Property89
|
|
], TreemapSeriesTile.prototype, "strokeWidth", 2);
|
|
__decorateClass([
|
|
Property89
|
|
], TreemapSeriesTile.prototype, "strokeOpacity", 2);
|
|
__decorateClass([
|
|
Property89
|
|
], TreemapSeriesTile.prototype, "cornerRadius", 2);
|
|
__decorateClass([
|
|
Property89
|
|
], TreemapSeriesTile.prototype, "textAlign", 2);
|
|
__decorateClass([
|
|
Property89
|
|
], TreemapSeriesTile.prototype, "verticalAlign", 2);
|
|
__decorateClass([
|
|
Property89
|
|
], TreemapSeriesTile.prototype, "gap", 2);
|
|
__decorateClass([
|
|
Property89
|
|
], TreemapSeriesTile.prototype, "padding", 2);
|
|
__decorateClass([
|
|
Property89
|
|
], TreemapSeriesTile.prototype, "label", 2);
|
|
__decorateClass([
|
|
Property89
|
|
], TreemapSeriesTile.prototype, "secondaryLabel", 2);
|
|
__decorateClass([
|
|
Property89
|
|
], TreemapSeriesTile.prototype, "highlight", 2);
|
|
var TreemapSeriesProperties = class extends HierarchySeriesProperties2 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.tooltip = makeSeriesTooltip24();
|
|
this.group = new TreemapSeriesGroup();
|
|
this.tile = new TreemapSeriesTile();
|
|
this.undocumentedGroupFills = [];
|
|
this.undocumentedGroupStrokes = [];
|
|
}
|
|
getStyle(isLeaf, fills, strokes, index) {
|
|
const {
|
|
fillOpacity,
|
|
strokeWidth,
|
|
strokeOpacity,
|
|
fill = isLeaf ? fills[index % fills.length] : fills[Math.min(index, fills.length)],
|
|
stroke: stroke3 = isLeaf ? strokes[index % fills.length] : strokes[Math.min(index, strokes.length)]
|
|
} = isLeaf ? this.tile : this.group;
|
|
return {
|
|
fill,
|
|
fillOpacity,
|
|
stroke: stroke3,
|
|
strokeWidth,
|
|
strokeOpacity,
|
|
opacity: 1
|
|
};
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Property89
|
|
], TreemapSeriesProperties.prototype, "sizeName", 2);
|
|
__decorateClass([
|
|
Property89
|
|
], TreemapSeriesProperties.prototype, "labelKey", 2);
|
|
__decorateClass([
|
|
Property89
|
|
], TreemapSeriesProperties.prototype, "secondaryLabelKey", 2);
|
|
__decorateClass([
|
|
Property89
|
|
], TreemapSeriesProperties.prototype, "itemStyler", 2);
|
|
__decorateClass([
|
|
Property89
|
|
], TreemapSeriesProperties.prototype, "tooltip", 2);
|
|
__decorateClass([
|
|
Property89
|
|
], TreemapSeriesProperties.prototype, "group", 2);
|
|
__decorateClass([
|
|
Property89
|
|
], TreemapSeriesProperties.prototype, "tile", 2);
|
|
__decorateClass([
|
|
Property89
|
|
], TreemapSeriesProperties.prototype, "undocumentedGroupFills", 2);
|
|
__decorateClass([
|
|
Property89
|
|
], TreemapSeriesProperties.prototype, "undocumentedGroupStrokes", 2);
|
|
|
|
// packages/ag-charts-enterprise/src/series/treemap/treemapSeries.ts
|
|
var {
|
|
createDatumId: createDatumId23,
|
|
Rect: Rect10,
|
|
Group: Group22,
|
|
BBox: BBox29,
|
|
Selection: Selection18,
|
|
Text: Text10,
|
|
Transformable: Transformable6,
|
|
getLabelStyles: getLabelStyles8,
|
|
HierarchyHighlightState,
|
|
toHierarchyHighlightString: toHierarchyHighlightString2
|
|
} = _ModuleSupport211;
|
|
var TreemapNode = class extends _ModuleSupport211.HierarchyNode {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.labelValue = void 0;
|
|
this.secondaryLabelValue = void 0;
|
|
this.label = void 0;
|
|
this.secondaryLabel = void 0;
|
|
this.bbox = void 0;
|
|
this.padding = void 0;
|
|
}
|
|
};
|
|
function nodeSize(node) {
|
|
return node.children.length > 0 ? node.sumSize - node.sizeValue : node.sizeValue;
|
|
}
|
|
var textAlignFactors2 = {
|
|
left: 0,
|
|
center: 0.5,
|
|
right: 1
|
|
};
|
|
var verticalAlignFactors4 = {
|
|
top: 0,
|
|
middle: 0.5,
|
|
bottom: 1
|
|
};
|
|
var DistantGroup = class extends _ModuleSupport211.Group {
|
|
distanceSquared(x, y) {
|
|
return this.getBBox().distanceSquared(x, y);
|
|
}
|
|
};
|
|
var TreemapSeries = class extends _ModuleSupport211.HierarchySeries {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.NodeClass = TreemapNode;
|
|
this.properties = new TreemapSeriesProperties();
|
|
this.rectGroup = this.contentGroup.appendChild(new Group22());
|
|
this.datumSelection = Selection18.select(this.rectGroup, Rect10);
|
|
this.labelSelection = Selection18.select(this.labelGroup, Group22);
|
|
this.highlightSelection = Selection18.select(
|
|
this.rectGroup,
|
|
Rect10
|
|
);
|
|
}
|
|
groupTitleHeight(node, bbox) {
|
|
const heightRatioThreshold = 3;
|
|
const { label } = this.properties.group;
|
|
const { labelValue } = node;
|
|
const { fontSize } = label;
|
|
if (label.enabled && labelValue != null && fontSize <= bbox.width / heightRatioThreshold && fontSize <= bbox.height / heightRatioThreshold) {
|
|
const { height: fontHeight } = cachedTextMeasurer13(label).measureLines(labelValue);
|
|
return Math.max(fontHeight, fontSize);
|
|
}
|
|
}
|
|
getNodePadding(node, bbox) {
|
|
if (node.parent == null) {
|
|
return { top: 0, right: 0, bottom: 0, left: 0 };
|
|
} else if (node.children.length === 0) {
|
|
const { padding: padding3 } = this.properties.tile;
|
|
return { top: padding3, right: padding3, bottom: padding3, left: padding3 };
|
|
}
|
|
const {
|
|
padding: padding2,
|
|
label: { spacing }
|
|
} = this.properties.group;
|
|
const fontHeight = this.groupTitleHeight(node, bbox);
|
|
const titleHeight = fontHeight == null ? 0 : fontHeight + spacing;
|
|
return {
|
|
top: padding2 + titleHeight,
|
|
right: padding2,
|
|
bottom: padding2,
|
|
left: padding2
|
|
};
|
|
}
|
|
sortChildren({ children }) {
|
|
const sortedChildrenIndices = Array.from(children, (_, i) => i).filter((i) => nodeSize(children[i]) > 0).sort((aIndex, bIndex) => nodeSize(children[bIndex]) - nodeSize(children[aIndex]));
|
|
const childAt = (i) => {
|
|
const sortedIndex = sortedChildrenIndices[i];
|
|
return children[sortedIndex];
|
|
};
|
|
return { sortedChildrenIndices, childAt };
|
|
}
|
|
/**
|
|
* Squarified Treemap algorithm
|
|
* https://www.win.tue.nl/~vanwijk/stm.pdf
|
|
*/
|
|
squarify(node, bbox) {
|
|
const { datum, children } = node;
|
|
if (bbox.width <= 0 || bbox.height <= 0) {
|
|
node.bbox = void 0;
|
|
node.padding = void 0;
|
|
node.midPoint.x = Number.NaN;
|
|
node.midPoint.y = Number.NaN;
|
|
return;
|
|
}
|
|
const padding2 = datum == null ? { top: 0, right: 0, bottom: 0, left: 0 } : this.getNodePadding(node, bbox);
|
|
if (node.parent == null) {
|
|
node.bbox = void 0;
|
|
node.padding = void 0;
|
|
node.midPoint.x = Number.NaN;
|
|
node.midPoint.y = Number.NaN;
|
|
} else {
|
|
node.bbox = bbox;
|
|
node.padding = padding2;
|
|
node.midPoint.x = bbox.x + bbox.width / 2;
|
|
node.midPoint.y = bbox.y;
|
|
}
|
|
const { sortedChildrenIndices, childAt } = this.sortChildren(node);
|
|
const allLeafNodes = sortedChildrenIndices.every((sortedIndex) => children[sortedIndex].children.length === 0);
|
|
const targetTileAspectRatio = 1;
|
|
const width = bbox.width - padding2.left - padding2.right;
|
|
const height = bbox.height - padding2.top - padding2.bottom;
|
|
if (width <= 0 || height <= 0)
|
|
return;
|
|
const numChildren = sortedChildrenIndices.length;
|
|
let stackSum = 0;
|
|
let startIndex = 0;
|
|
let minRatioDiff = Infinity;
|
|
let partitionSum = sortedChildrenIndices.reduce((sum, sortedIndex) => sum + nodeSize(children[sortedIndex]), 0);
|
|
const innerBox = new BBox29(bbox.x + padding2.left, bbox.y + padding2.top, width, height);
|
|
const partition = innerBox.clone();
|
|
let i = 0;
|
|
while (i < numChildren) {
|
|
const value = nodeSize(childAt(i));
|
|
const firstValue = nodeSize(childAt(startIndex));
|
|
const isVertical2 = partition.width < partition.height;
|
|
stackSum += value;
|
|
const partThickness = isVertical2 ? partition.height : partition.width;
|
|
const partLength = isVertical2 ? partition.width : partition.height;
|
|
const firstTileLength = partLength * firstValue / stackSum;
|
|
let stackThickness = partThickness * stackSum / partitionSum;
|
|
const ratio8 = Math.max(firstTileLength, stackThickness) / Math.min(firstTileLength, stackThickness);
|
|
const diff8 = Math.abs(targetTileAspectRatio - ratio8);
|
|
if (diff8 < minRatioDiff) {
|
|
minRatioDiff = diff8;
|
|
i++;
|
|
continue;
|
|
}
|
|
stackSum -= value;
|
|
stackThickness = partThickness * stackSum / partitionSum;
|
|
let start2 = isVertical2 ? partition.x : partition.y;
|
|
for (let j = startIndex; j < i; j++) {
|
|
const child = childAt(j);
|
|
const childSize = nodeSize(child);
|
|
const x = isVertical2 ? start2 : partition.x;
|
|
const y = isVertical2 ? partition.y : start2;
|
|
const length = partLength * childSize / stackSum;
|
|
const stackWidth = isVertical2 ? length : stackThickness;
|
|
const stackHeight = isVertical2 ? stackThickness : length;
|
|
const childBbox = new BBox29(x, y, stackWidth, stackHeight);
|
|
this.applyGap(innerBox, childBbox, allLeafNodes);
|
|
this.squarify(child, childBbox);
|
|
partitionSum -= childSize;
|
|
start2 += length;
|
|
}
|
|
if (isVertical2) {
|
|
partition.y += stackThickness;
|
|
partition.height -= stackThickness;
|
|
} else {
|
|
partition.x += stackThickness;
|
|
partition.width -= stackThickness;
|
|
}
|
|
startIndex = i;
|
|
stackSum = 0;
|
|
minRatioDiff = Infinity;
|
|
}
|
|
const isVertical = partition.width < partition.height;
|
|
let start = isVertical ? partition.x : partition.y;
|
|
for (let childIdx = startIndex; childIdx < numChildren; childIdx++) {
|
|
const child = childAt(childIdx);
|
|
const x = isVertical ? start : partition.x;
|
|
const y = isVertical ? partition.y : start;
|
|
const part = nodeSize(child) / partitionSum;
|
|
const childWidth = partition.width * (isVertical ? part : 1);
|
|
const childHeight = partition.height * (isVertical ? 1 : part);
|
|
const childBox = new BBox29(x, y, childWidth, childHeight);
|
|
this.applyGap(innerBox, childBox, allLeafNodes);
|
|
this.squarify(child, childBox);
|
|
start += isVertical ? childWidth : childHeight;
|
|
}
|
|
}
|
|
applyGap(innerBox, childBox, allLeafNodes) {
|
|
const gap = allLeafNodes ? this.properties.tile.gap * 0.5 : this.properties.group.gap * 0.5;
|
|
const getBounds = (box) => ({
|
|
left: box.x,
|
|
top: box.y,
|
|
right: box.x + box.width,
|
|
bottom: box.y + box.height
|
|
});
|
|
const innerBounds = getBounds(innerBox);
|
|
const childBounds = getBounds(childBox);
|
|
const sides = ["top", "right", "bottom", "left"];
|
|
for (const side of sides) {
|
|
if (!isNumberEqual11(innerBounds[side], childBounds[side])) {
|
|
childBox.shrink(gap, side);
|
|
}
|
|
}
|
|
}
|
|
createNodeData() {
|
|
return void 0;
|
|
}
|
|
getItemStyle(nodeDatum, isLeaf, isHighlight) {
|
|
const { properties, colorScale } = this;
|
|
const { itemStyler } = properties;
|
|
const rootIndex = nodeDatum.datumIndex?.[0] ?? 0;
|
|
const fills = isLeaf ? properties.fills : properties.undocumentedGroupFills;
|
|
const strokes = isLeaf ? properties.strokes : properties.undocumentedGroupStrokes;
|
|
const index = isLeaf ? rootIndex : nodeDatum.depth ?? -1;
|
|
const highlightedNode = this.getActiveHighlightNode();
|
|
const tileHighlightState = this.getHierarchyHighlightState(isHighlight, highlightedNode, nodeDatum);
|
|
const groupHighlightState = this.getGroupHighlightState(isHighlight, highlightedNode, nodeDatum);
|
|
const highlightState = isLeaf ? tileHighlightState : groupHighlightState;
|
|
const highlightStyle = isLeaf ? this.getTileHighlightStyle(tileHighlightState, groupHighlightState, highlightedNode) : this.getGroupHighlightStyle(groupHighlightState);
|
|
const baseStyle = mergeDefaults24(highlightStyle, properties.getStyle(isLeaf, fills, strokes, index));
|
|
if (isLeaf && nodeDatum.colorValue != null && highlightStyle?.fill == null) {
|
|
baseStyle.fill = colorScale.convert(nodeDatum.colorValue);
|
|
}
|
|
let style = baseStyle;
|
|
if (itemStyler != null && nodeDatum != null) {
|
|
const overrides = this.cachedDatumCallback(
|
|
createDatumId23(this.getDatumId(nodeDatum), isHighlight ? "highlight" : "node"),
|
|
() => {
|
|
const params = this.makeItemStylerParams(
|
|
nodeDatum,
|
|
style,
|
|
toHierarchyHighlightString2(highlightState)
|
|
);
|
|
return this.callWithContext(itemStyler, params);
|
|
}
|
|
);
|
|
if (overrides) {
|
|
style = mergeDefaults24(overrides, style);
|
|
}
|
|
}
|
|
return style;
|
|
}
|
|
makeItemStylerParams(nodeDatum, style, highlightState) {
|
|
const { id: seriesId } = this;
|
|
const fill = this.filterItemStylerFillParams(style.fill) ?? style.fill;
|
|
return {
|
|
seriesId,
|
|
datum: nodeDatum.datum,
|
|
depth: nodeDatum.depth ?? -1,
|
|
highlightState,
|
|
...style,
|
|
fill
|
|
};
|
|
}
|
|
updateSelections() {
|
|
const highlightedNode = this.getActiveHighlightNode();
|
|
this.highlightSelection.update(
|
|
highlightedNode == null ? [] : [highlightedNode],
|
|
void 0,
|
|
(node) => this.getDatumId(node)
|
|
);
|
|
if (!this.nodeDataRefresh) {
|
|
return;
|
|
}
|
|
this.nodeDataRefresh = false;
|
|
const { seriesRect } = this.chart ?? {};
|
|
if (!seriesRect)
|
|
return;
|
|
const descendants = Array.from(this.rootNode);
|
|
const updateLabelGroup = (group) => {
|
|
group.append([new Text10({ tag: 0 /* Primary */ }), new Text10({ tag: 1 /* Secondary */ })]);
|
|
};
|
|
this.datumSelection.update(descendants, void 0, (node) => this.getDatumId(node));
|
|
this.labelSelection.update(descendants, updateLabelGroup, (node) => this.getDatumId(node));
|
|
}
|
|
getActiveHighlightNode() {
|
|
const highlightedNode = super.getActiveHighlightNode();
|
|
if (highlightedNode?.children.length && !this.properties.group.interactive) {
|
|
return void 0;
|
|
}
|
|
return highlightedNode;
|
|
}
|
|
updateNodes() {
|
|
const { rootNode, data } = this;
|
|
const { childrenKey, colorKey, colorName, labelKey, secondaryLabelKey, sizeKey, sizeName, tile, group } = this.properties;
|
|
const { seriesRect } = this.chart ?? {};
|
|
if (!seriesRect || !data)
|
|
return;
|
|
this.rootNode?.walk((node) => {
|
|
const { datum, depth, children } = node;
|
|
const isLeaf = children.length === 0;
|
|
const labelStyle = isLeaf ? tile.label : group.label;
|
|
let labelValue;
|
|
if (labelStyle.enabled && datum != null && depth != null && labelKey != null) {
|
|
const value = datum[labelKey];
|
|
labelValue = this.getLabelText(
|
|
value,
|
|
datum,
|
|
labelKey,
|
|
"label",
|
|
[],
|
|
labelStyle,
|
|
{
|
|
depth,
|
|
datum,
|
|
childrenKey,
|
|
colorKey,
|
|
colorName,
|
|
labelKey,
|
|
secondaryLabelKey,
|
|
sizeKey,
|
|
sizeName,
|
|
value
|
|
}
|
|
);
|
|
}
|
|
if (labelValue === "") {
|
|
labelValue = void 0;
|
|
}
|
|
let secondaryLabelValue;
|
|
if (tile.secondaryLabel.enabled && isLeaf && datum != null && depth != null && secondaryLabelKey != null) {
|
|
const value = datum[secondaryLabelKey];
|
|
secondaryLabelValue = this.getLabelText(
|
|
value,
|
|
datum,
|
|
secondaryLabelKey,
|
|
"secondaryLabel",
|
|
[],
|
|
tile.secondaryLabel,
|
|
{
|
|
depth,
|
|
datum,
|
|
childrenKey,
|
|
colorKey,
|
|
colorName,
|
|
labelKey,
|
|
secondaryLabelKey,
|
|
sizeKey,
|
|
sizeName,
|
|
value
|
|
}
|
|
);
|
|
}
|
|
if (secondaryLabelValue === "") {
|
|
secondaryLabelValue = void 0;
|
|
}
|
|
node.labelValue = toPlainText13(labelValue);
|
|
node.secondaryLabelValue = toPlainText13(secondaryLabelValue);
|
|
});
|
|
const { width, height } = seriesRect;
|
|
this.squarify(rootNode, new BBox29(0, 0, width, height));
|
|
this.rootNode?.walk((node) => {
|
|
const { bbox, children, labelValue, secondaryLabelValue } = node;
|
|
node.label = void 0;
|
|
node.secondaryLabel = void 0;
|
|
if (bbox == null)
|
|
return;
|
|
if (children.length === 0) {
|
|
const layout = {
|
|
width: bbox.width,
|
|
height: bbox.height,
|
|
meta: null
|
|
};
|
|
const formatting = formatLabels(
|
|
labelValue,
|
|
this.properties.tile.label,
|
|
secondaryLabelValue,
|
|
this.properties.tile.secondaryLabel,
|
|
{ padding: tile.padding },
|
|
() => layout
|
|
);
|
|
if (formatting == null) {
|
|
return;
|
|
}
|
|
const { height: labelHeight, label, secondaryLabel } = formatting;
|
|
const { textAlign, verticalAlign, padding: padding2 } = tile;
|
|
const textAlignFactor = textAlignFactors2[textAlign] ?? 0.5;
|
|
const labelX = bbox.x + padding2 + (bbox.width - 2 * padding2) * textAlignFactor;
|
|
const verticalAlignFactor = verticalAlignFactors4[verticalAlign] ?? 0.5;
|
|
const labelYStart = bbox.y + padding2 + labelHeight * 0.5 + (bbox.height - 2 * padding2 - labelHeight) * verticalAlignFactor;
|
|
if (label != null) {
|
|
const {
|
|
fontStyle = "normal",
|
|
fontFamily,
|
|
fontWeight = "normal",
|
|
color: color7 = "black"
|
|
} = this.properties.tile.label;
|
|
node.label = {
|
|
text: label.text,
|
|
fontSize: label.fontSize,
|
|
lineHeight: label.lineHeight,
|
|
fontStyle,
|
|
fontFamily,
|
|
fontWeight,
|
|
color: color7,
|
|
textAlign,
|
|
verticalAlign: "middle",
|
|
x: labelX,
|
|
y: labelYStart - (labelHeight - label.height) * 0.5
|
|
};
|
|
}
|
|
if (secondaryLabel != null) {
|
|
const {
|
|
fontStyle = "normal",
|
|
fontFamily,
|
|
fontWeight = "normal",
|
|
color: color7 = "black"
|
|
} = this.properties.tile.secondaryLabel;
|
|
node.secondaryLabel = {
|
|
text: secondaryLabel.text,
|
|
fontSize: secondaryLabel.fontSize,
|
|
lineHeight: secondaryLabel.fontSize,
|
|
fontStyle,
|
|
fontFamily,
|
|
fontWeight,
|
|
color: color7,
|
|
textAlign,
|
|
verticalAlign: "middle",
|
|
x: labelX,
|
|
y: labelYStart + (labelHeight - secondaryLabel.height) * 0.5
|
|
};
|
|
}
|
|
} else if (labelValue == null) {
|
|
return;
|
|
} else {
|
|
const { padding: padding2, textAlign } = group;
|
|
const groupTitleHeight = this.groupTitleHeight(node, bbox);
|
|
if (groupTitleHeight == null)
|
|
return;
|
|
const innerWidth = bbox.width - 2 * padding2;
|
|
const text2 = wrapText5(labelValue, {
|
|
maxWidth: bbox.width - 2 * padding2,
|
|
font: group.label,
|
|
textWrap: "never"
|
|
});
|
|
const textAlignFactor = textAlignFactors2[textAlign] ?? 0.5;
|
|
const {
|
|
fontStyle = "normal",
|
|
fontFamily,
|
|
fontWeight = "normal",
|
|
color: color7 = "black"
|
|
} = this.properties.group.label;
|
|
node.label = {
|
|
text: text2,
|
|
fontSize: group.label.fontSize,
|
|
lineHeight: calcLineHeight8(group.label.fontSize),
|
|
fontStyle,
|
|
fontFamily,
|
|
fontWeight,
|
|
color: color7,
|
|
textAlign,
|
|
verticalAlign: "middle",
|
|
x: bbox.x + padding2 + innerWidth * textAlignFactor,
|
|
y: bbox.y + padding2 + groupTitleHeight * 0.5
|
|
};
|
|
}
|
|
});
|
|
const fillBBox = {
|
|
series: new BBox29(0, 0, width, height),
|
|
axis: new BBox29(0, 0, width, height)
|
|
};
|
|
const updateRectFn = (node, rect, isHighlight) => {
|
|
const { bbox } = node;
|
|
if (bbox == null) {
|
|
rect.visible = false;
|
|
return;
|
|
}
|
|
const { depth = -1 } = node;
|
|
const isLeaf = node.children.length === 0;
|
|
const style = this.getItemStyle(node, isLeaf, isHighlight);
|
|
rect.crisp = true;
|
|
rect.setStyleProperties(style, fillBBox);
|
|
rect.cornerRadius = isLeaf ? tile.cornerRadius : group.cornerRadius;
|
|
rect.zIndex = [0, depth, isHighlight ? 1 : 0];
|
|
const onlyLeaves = node.parent?.children.every((n) => n.children.length === 0);
|
|
const parentBbox = node.parent == null ? void 0 : node.parent.bbox;
|
|
const parentPadding = node.parent == null ? void 0 : node.parent.padding;
|
|
if (onlyLeaves === true && parentBbox != null && parentPadding != null) {
|
|
rect.clipBBox = bbox;
|
|
rect.x = parentBbox.x + parentPadding.left;
|
|
rect.y = parentBbox.y + parentPadding.top;
|
|
rect.width = parentBbox.width - (parentPadding.left + parentPadding.right);
|
|
rect.height = parentBbox.height - (parentPadding.top + parentPadding.bottom);
|
|
} else {
|
|
rect.clipBBox = void 0;
|
|
rect.x = bbox.x;
|
|
rect.y = bbox.y;
|
|
rect.width = bbox.width;
|
|
rect.height = bbox.height;
|
|
}
|
|
rect.visible = true;
|
|
};
|
|
this.datumSelection.each((rect, datum) => updateRectFn(datum, rect, false));
|
|
this.highlightSelection.each((rect, datum) => {
|
|
updateRectFn(datum, rect, true);
|
|
});
|
|
const updateLabelFn = (node, text2, tag, highlighted) => {
|
|
const isLeaf = node.children.length === 0;
|
|
const label = tag === 0 /* Primary */ ? node.label : node.secondaryLabel;
|
|
if (label == null) {
|
|
text2.visible = false;
|
|
return;
|
|
}
|
|
let labelProps;
|
|
let labelPath;
|
|
if (tag === 0 /* Primary */) {
|
|
labelProps = isLeaf ? tile.label : group.label;
|
|
labelPath = ["series", `${this.declarationOrder}`, isLeaf ? "tile" : "group", "label"];
|
|
} else {
|
|
labelProps = tile.secondaryLabel;
|
|
labelPath = ["series", `${this.declarationOrder}`, "tile", "secondaryLabel"];
|
|
}
|
|
const { opacity: highlightOpacity } = this.getItemStyle(node, isLeaf, highlighted) ?? {};
|
|
const params = {
|
|
childrenKey: this.properties.childrenKey,
|
|
colorKey: this.properties.colorKey,
|
|
colorName: this.properties.colorName ?? this.properties.colorKey,
|
|
depth: node.depth ?? Number.NaN,
|
|
labelKey: this.properties.labelKey,
|
|
secondaryLabelKey: this.properties.secondaryLabelKey,
|
|
sizeKey: this.properties.sizeKey,
|
|
sizeName: this.properties.sizeName ?? this.properties.sizeKey
|
|
};
|
|
const activeHighlight = this.ctx.highlightManager?.getActiveHighlight();
|
|
const style = getLabelStyles8(this, node, params, labelProps, highlighted, activeHighlight, labelPath);
|
|
text2.text = label.text;
|
|
text2.fontSize = label.fontSize;
|
|
text2.lineHeight = label.lineHeight;
|
|
text2.fontStyle = label.fontStyle;
|
|
text2.fontFamily = label.fontFamily;
|
|
text2.fontWeight = label.fontWeight;
|
|
text2.fillOpacity = highlightOpacity ?? 1;
|
|
text2.fill = style.color;
|
|
text2.setBoxing(style);
|
|
text2.textAlign = label.textAlign;
|
|
text2.textBaseline = label.verticalAlign;
|
|
text2.x = label.x;
|
|
text2.y = label.y;
|
|
text2.visible = true;
|
|
text2.zIndex = 1;
|
|
};
|
|
const highlightedDatum = this.getActiveHighlightNode();
|
|
for (const text2 of this.labelSelection.selectByClass(Text10)) {
|
|
const datum = text2.closestDatum();
|
|
updateLabelFn(datum, text2, text2.tag, datum === highlightedDatum);
|
|
}
|
|
}
|
|
getGroupHighlightState(isHighlight, highlightedNode, nodeDatum) {
|
|
const nodeIndex = nodeDatum.datumIndex;
|
|
const highlightedIndex = highlightedNode?.datumIndex;
|
|
const isDescendant = this.isDescendantDatumIndex(nodeIndex, highlightedIndex);
|
|
if (nodeDatum.children?.length === 0) {
|
|
if (nodeIndex == null || highlightedNode == null || highlightedNode.children?.length === 0) {
|
|
return HierarchyHighlightState.None;
|
|
}
|
|
return isDescendant ? HierarchyHighlightState.Item : HierarchyHighlightState.OtherItem;
|
|
}
|
|
if (highlightedNode == null || highlightedNode.children?.length === 0) {
|
|
return HierarchyHighlightState.None;
|
|
}
|
|
const isSibling = nodeDatum.depth != null && highlightedNode.depth != null && nodeDatum.depth === highlightedNode.depth;
|
|
if (isDescendant && !isSibling) {
|
|
return HierarchyHighlightState.None;
|
|
}
|
|
return isHighlight ? HierarchyHighlightState.Item : HierarchyHighlightState.OtherItem;
|
|
}
|
|
getTileHighlightStyle(tileHighlightState, groupHighlightState, highlightedNode) {
|
|
const isGroupHighlighted = highlightedNode?.children && highlightedNode.children.length > 0;
|
|
if (isGroupHighlighted) {
|
|
const groupStyle = this.getGroupHighlightStyle(groupHighlightState);
|
|
if (groupStyle?.fillOpacity == null && groupStyle?.strokeOpacity == null) {
|
|
return void 0;
|
|
}
|
|
return { fillOpacity: groupStyle.fillOpacity, strokeOpacity: groupStyle.strokeOpacity };
|
|
}
|
|
return this.getHierarchyHighlightStyles(tileHighlightState, this.properties.tile.highlight);
|
|
}
|
|
getGroupHighlightStyle(highlightState) {
|
|
const { highlight } = this.properties.group;
|
|
switch (highlightState) {
|
|
case HierarchyHighlightState.Item:
|
|
return highlight.highlightedItem;
|
|
case HierarchyHighlightState.OtherItem:
|
|
return highlight.unhighlightedItem;
|
|
default:
|
|
return void 0;
|
|
}
|
|
}
|
|
getHighlightStateString(_datum, isHighlight, datumIndex) {
|
|
if (datumIndex == null) {
|
|
return toHierarchyHighlightString2(HierarchyHighlightState.None);
|
|
}
|
|
const nodeDatum = datumIndex.reduce((node, idx) => node?.children[idx], this.rootNode);
|
|
const highlightedNode = this.getActiveHighlightNode();
|
|
if (nodeDatum == null) {
|
|
return toHierarchyHighlightString2(HierarchyHighlightState.None);
|
|
}
|
|
const isLeaf = (nodeDatum.children?.length ?? 0) === 0;
|
|
if (isLeaf) {
|
|
const tileState = this.getHierarchyHighlightState(isHighlight ?? false, highlightedNode, nodeDatum);
|
|
return toHierarchyHighlightString2(tileState);
|
|
}
|
|
const groupState = this.getGroupHighlightState(isHighlight ?? false, highlightedNode, nodeDatum);
|
|
return toHierarchyHighlightString2(groupState);
|
|
}
|
|
isDescendantDatumIndex(nodeIndex, ancestorIndex) {
|
|
if (ancestorIndex == null || ancestorIndex.length === 0) {
|
|
return true;
|
|
}
|
|
if (nodeIndex == null || nodeIndex.length < ancestorIndex.length) {
|
|
return false;
|
|
}
|
|
for (let i = 0; i < ancestorIndex.length; i += 1) {
|
|
if (nodeIndex[i] !== ancestorIndex[i]) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
pickNodesExactShape(point) {
|
|
const nodes = super.pickNodesExactShape(point);
|
|
nodes.sort((a, b) => b.datumIndex.length - a.datumIndex.length);
|
|
return nodes;
|
|
}
|
|
pickNodeClosestDatum(point) {
|
|
const exactMatch = this.pickNodesExactShape(point);
|
|
if (exactMatch.length !== 0) {
|
|
return { datum: exactMatch[0], distance: 0 };
|
|
}
|
|
return this.pickNodeNearestDistantObject(point, this.datumSelection.nodes());
|
|
}
|
|
getTooltipContent(datumIndex) {
|
|
const { id: seriesId, properties, ctx } = this;
|
|
const { formatManager } = ctx;
|
|
const { labelKey, secondaryLabelKey, childrenKey, sizeKey, sizeName, colorKey, colorName, tooltip } = properties;
|
|
const nodeDatum = datumIndex.reduce((n, i) => n?.children[i], this.rootNode);
|
|
if (nodeDatum == null)
|
|
return;
|
|
const { datum, depth, children } = nodeDatum;
|
|
if (datum == null || depth == null)
|
|
return;
|
|
const isLeaf = children.length === 0;
|
|
const data = [];
|
|
const datumSize = sizeKey == null ? void 0 : datum[sizeKey];
|
|
if (datumSize != null) {
|
|
const sizeDomain = [0, this.rootNode?.sumSize ?? 0];
|
|
const content = formatManager.format(this.callWithContext.bind(this), {
|
|
type: "number",
|
|
value: datumSize,
|
|
datum,
|
|
seriesId,
|
|
legendItemName: void 0,
|
|
key: sizeKey,
|
|
source: "tooltip",
|
|
property: "size",
|
|
boundSeries: this.getFormatterContext("size"),
|
|
domain: sizeDomain,
|
|
fractionDigits: void 0,
|
|
visibleDomain: void 0
|
|
});
|
|
data.push({ label: sizeName, fallbackLabel: sizeKey, value: content ?? formatValue3(datumSize) });
|
|
}
|
|
const datumColor = colorKey == null ? void 0 : datum[colorKey];
|
|
if (datumColor != null) {
|
|
const { colorDomain } = this;
|
|
const content = formatManager.format(this.callWithContext.bind(this), {
|
|
type: "number",
|
|
value: datumColor,
|
|
datum,
|
|
seriesId,
|
|
legendItemName: void 0,
|
|
key: colorKey,
|
|
source: "tooltip",
|
|
property: "color",
|
|
boundSeries: this.getFormatterContext("color"),
|
|
domain: colorDomain,
|
|
fractionDigits: void 0,
|
|
visibleDomain: void 0
|
|
});
|
|
data.push({ label: colorName, fallbackLabel: colorKey, value: content ?? formatValue3(datumColor) });
|
|
}
|
|
const format = this.getItemStyle(
|
|
{ ...nodeDatum, colorValue: datumColor ?? nodeDatum.colorValue },
|
|
isLeaf,
|
|
false
|
|
);
|
|
const color7 = format.fill;
|
|
const markerStyle = {
|
|
shape: "square",
|
|
fill: color7,
|
|
fillOpacity: 1,
|
|
stroke: void 0,
|
|
strokeWidth: 0,
|
|
strokeOpacity: 1,
|
|
lineDash: [0],
|
|
lineDashOffset: 0
|
|
};
|
|
if (isGradientFill5(markerStyle.fill)) {
|
|
markerStyle.fill = { ...markerStyle.fill, gradient: "linear", rotation: 0, reverse: false };
|
|
}
|
|
const symbol = isLeaf ? { marker: markerStyle } : void 0;
|
|
return this.formatTooltipWithContext(
|
|
tooltip,
|
|
{
|
|
title: labelKey == null ? void 0 : datum[labelKey],
|
|
symbol,
|
|
data
|
|
},
|
|
{
|
|
seriesId,
|
|
datum,
|
|
title: void 0,
|
|
depth,
|
|
labelKey,
|
|
secondaryLabelKey,
|
|
childrenKey,
|
|
sizeKey,
|
|
sizeName,
|
|
colorKey,
|
|
colorName,
|
|
...format
|
|
}
|
|
);
|
|
}
|
|
computeFocusBounds(node) {
|
|
return Transformable6.toCanvas(this.contentGroup, node.getBBox());
|
|
}
|
|
hasItemStylers() {
|
|
return this.properties.itemStyler != null || this.properties.tile.label.itemStyler != null || this.properties.group.label.itemStyler != null;
|
|
}
|
|
};
|
|
TreemapSeries.className = "TreemapSeries";
|
|
TreemapSeries.type = "treemap";
|
|
|
|
// packages/ag-charts-enterprise/src/series/treemap/treemapSeriesOptionsDef.ts
|
|
import { _ModuleSupport as _ModuleSupport212 } from "ag-charts-community";
|
|
import {
|
|
arrayOf as arrayOf5,
|
|
color as color6,
|
|
commonSeriesOptionsDefs as commonSeriesOptionsDefs23,
|
|
constant as constant24,
|
|
required as required24,
|
|
string as string24,
|
|
undocumented as undocumented18,
|
|
without as without10
|
|
} from "ag-charts-core";
|
|
var { treemapSeriesThemeableOptionsDef } = _ModuleSupport212;
|
|
var treemapSeriesOptionsDef = {
|
|
...treemapSeriesThemeableOptionsDef,
|
|
...without10(commonSeriesOptionsDefs23, ["highlightStyle", "highlight", "showInLegend"]),
|
|
type: required24(constant24("treemap")),
|
|
labelKey: string24,
|
|
secondaryLabelKey: string24,
|
|
childrenKey: string24,
|
|
sizeKey: string24,
|
|
colorKey: string24,
|
|
sizeName: string24,
|
|
colorName: string24
|
|
};
|
|
treemapSeriesOptionsDef.undocumentedGroupFills = undocumented18(arrayOf5(color6));
|
|
treemapSeriesOptionsDef.undocumentedGroupStrokes = undocumented18(arrayOf5(color6));
|
|
|
|
// packages/ag-charts-enterprise/src/series/treemap/treemapModule.ts
|
|
var TreemapSeriesModule = {
|
|
type: "series",
|
|
name: "treemap",
|
|
chartType: "standalone",
|
|
enterprise: true,
|
|
solo: true,
|
|
version: VERSION50,
|
|
dependencies: [StandaloneChartModule],
|
|
options: treemapSeriesOptionsDef,
|
|
themeTemplate: {
|
|
series: {
|
|
fills: {
|
|
$applyCycle: [
|
|
{ $size: { $path: ["./data", { $path: "/data" }] } },
|
|
{ $palette: "fills" },
|
|
{
|
|
$applySwitch: [
|
|
{ $path: ["/type", void 0, { $value: "$1" }] },
|
|
{ $value: "$1" },
|
|
["gradient", FILL_GRADIENT_LINEAR_DEFAULTS9],
|
|
["pattern", FILL_PATTERN_DEFAULTS14],
|
|
["image", FILL_IMAGE_DEFAULTS19]
|
|
]
|
|
}
|
|
]
|
|
},
|
|
strokes: {
|
|
$applyCycle: [{ $size: { $path: ["./data", { $path: "/data" }] } }, { $palette: "strokes" }]
|
|
},
|
|
colorRange: { $palette: "divergingColors" },
|
|
undocumentedGroupFills: { $palette: "hierarchyColors" },
|
|
undocumentedGroupStrokes: { $palette: "secondHierarchyColors" },
|
|
group: {
|
|
label: {
|
|
...LABEL_BOXING_DEFAULTS20,
|
|
enabled: true,
|
|
color: { $ref: "textColor" },
|
|
fontStyle: void 0,
|
|
fontWeight: { $ref: "fontWeight" },
|
|
fontSize: { $ref: "fontSize" },
|
|
fontFamily: { $ref: "fontFamily" },
|
|
spacing: 4
|
|
},
|
|
fill: void 0,
|
|
// Override default fill
|
|
stroke: void 0,
|
|
// Override default stroke
|
|
strokeWidth: 1,
|
|
padding: 4,
|
|
gap: 2,
|
|
textAlign: "left",
|
|
highlight: {
|
|
unhighlightedItem: {
|
|
opacity: 0.2,
|
|
fillOpacity: 0.2,
|
|
strokeOpacity: 0.2
|
|
}
|
|
}
|
|
},
|
|
tile: {
|
|
label: {
|
|
...LABEL_BOXING_DEFAULTS20,
|
|
enabled: true,
|
|
color: { $ref: "chartBackgroundColor" },
|
|
fontStyle: void 0,
|
|
fontWeight: { $ref: "fontWeight" },
|
|
fontSize: { $rem: 1.5 },
|
|
minimumFontSize: { $rem: FONT_SIZE_RATIO5.SMALLER },
|
|
fontFamily: { $ref: "fontFamily" },
|
|
wrapping: "on-space",
|
|
overflowStrategy: "ellipsis",
|
|
spacing: 2
|
|
},
|
|
secondaryLabel: {
|
|
...LABEL_BOXING_DEFAULTS20,
|
|
enabled: true,
|
|
color: { $ref: "chartBackgroundColor" },
|
|
fontStyle: void 0,
|
|
fontWeight: void 0,
|
|
fontSize: { $ref: "fontSize" },
|
|
minimumFontSize: { $rem: FONT_SIZE_RATIO5.SMALLER },
|
|
fontFamily: { $ref: "fontFamily" },
|
|
wrapping: "never",
|
|
overflowStrategy: "ellipsis"
|
|
},
|
|
fill: void 0,
|
|
// Override default fill
|
|
stroke: void 0,
|
|
// Override default stroke
|
|
strokeWidth: { $isUserOption: ["../strokes/0", 2, { $isUserOption: ["./stroke", 2, 0] }] },
|
|
padding: 3,
|
|
gap: 1,
|
|
highlight: {
|
|
unhighlightedItem: {
|
|
fillOpacity: 0.6,
|
|
strokeOpacity: 0.6
|
|
},
|
|
unhighlightedBranch: {
|
|
fillOpacity: 0.2,
|
|
strokeOpacity: 0.2
|
|
}
|
|
}
|
|
}
|
|
},
|
|
gradientLegend: {
|
|
enabled: { $if: [{ $path: "../series/0/colorKey" }, true, false] }
|
|
}
|
|
},
|
|
create: (ctx) => new TreemapSeries(ctx)
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/module-bundles/all.ts
|
|
import { AllCommunityModule } from "ag-charts-community";
|
|
|
|
// packages/ag-charts-enterprise/src/module-bundles/cartesian-axes.ts
|
|
import { AllCartesianAxesModule as AllCommunityCartesianAxesModule } from "ag-charts-community";
|
|
var AllCartesianAxesModule = [
|
|
AllCommunityCartesianAxesModule,
|
|
OrdinalTimeAxisModule
|
|
].flat();
|
|
|
|
// packages/ag-charts-enterprise/src/module-bundles/cartesian-series.ts
|
|
import { AllCartesianSeriesModule as AllCommunityCartesianSeriesModule } from "ag-charts-community";
|
|
var AllCartesianSeriesModule = [
|
|
AllCommunityCartesianSeriesModule,
|
|
BoxPlotSeriesModule,
|
|
CandlestickSeriesModule,
|
|
ConeFunnelSeriesModule,
|
|
FunnelSeriesModule,
|
|
HeatmapSeriesModule,
|
|
OhlcSeriesModule,
|
|
RangeAreaSeriesModule,
|
|
RangeBarSeriesModule,
|
|
WaterfallSeriesModule
|
|
].flat();
|
|
|
|
// packages/ag-charts-enterprise/src/module-bundles/cartesian.ts
|
|
var AllCartesianModule = [
|
|
AllCartesianAxesModule,
|
|
AllCartesianSeriesModule,
|
|
AnimationModule,
|
|
AnnotationsModule,
|
|
BandHighlightModule,
|
|
ChartToolbarModule,
|
|
ContextMenuModule,
|
|
CrosshairModule,
|
|
DataSourceModule,
|
|
ErrorBarsModule,
|
|
FlashOnUpdateModule,
|
|
GradientLegendModule,
|
|
NavigatorModule,
|
|
RangesModule,
|
|
ScrollbarModule,
|
|
StatusBarModule,
|
|
SyncModule,
|
|
ZoomModule
|
|
].flat();
|
|
|
|
// packages/ag-charts-enterprise/src/module-bundles/financial.ts
|
|
import { BarSeriesModule as BarSeriesModule2, LineSeriesModule as LineSeriesModule2, NumberAxisModule, TimeAxisModule } from "ag-charts-community";
|
|
|
|
// packages/ag-charts-enterprise/src/preset/priceVolumePresetModules.ts
|
|
import { VERSION as VERSION51 } from "ag-charts-community";
|
|
import {
|
|
array as array3,
|
|
boolean as boolean20,
|
|
commonChartOptionsDefs as commonChartOptionsDefs2,
|
|
defined as defined2,
|
|
positiveNumber as positiveNumber10,
|
|
string as string25,
|
|
tooltipOptionsDefs as tooltipOptionsDefs2,
|
|
undocumented as undocumented19,
|
|
union as union5
|
|
} from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/preset/priceVolumePreset.ts
|
|
import "ag-charts-community";
|
|
import { Logger as Logger23, SAFE_STROKE_FILL_OPERATION as SAFE_STROKE_FILL_OPERATION5, mergeDefaults as mergeDefaults25 } from "ag-charts-core";
|
|
|
|
// packages/ag-charts-enterprise/src/preset/priceVolumePresetTheme.ts
|
|
import * as ThemeSymbols2 from "ag-charts-core";
|
|
import { FONT_SIZE_RATIO as FONT_SIZE_RATIO6 } from "ag-charts-core";
|
|
var {
|
|
DEFAULT_ANNOTATION_HANDLE_FILL: DEFAULT_ANNOTATION_HANDLE_FILL2,
|
|
DEFAULT_ANNOTATION_STATISTICS_COLOR: DEFAULT_ANNOTATION_STATISTICS_COLOR2,
|
|
DEFAULT_ANNOTATION_STATISTICS_DIVIDER_STROKE: DEFAULT_ANNOTATION_STATISTICS_DIVIDER_STROKE2,
|
|
DEFAULT_ANNOTATION_STATISTICS_DOWN_FILL: DEFAULT_ANNOTATION_STATISTICS_DOWN_FILL2,
|
|
DEFAULT_ANNOTATION_STATISTICS_DOWN_STROKE: DEFAULT_ANNOTATION_STATISTICS_DOWN_STROKE2,
|
|
DEFAULT_ANNOTATION_STATISTICS_FILL: DEFAULT_ANNOTATION_STATISTICS_FILL2,
|
|
DEFAULT_ANNOTATION_STATISTICS_STROKE: DEFAULT_ANNOTATION_STATISTICS_STROKE2,
|
|
DEFAULT_FIBONACCI_STROKES: DEFAULT_FIBONACCI_STROKES2,
|
|
DEFAULT_FINANCIAL_CHARTS_ANNOTATION_BACKGROUND_FILL: DEFAULT_FINANCIAL_CHARTS_ANNOTATION_BACKGROUND_FILL2,
|
|
DEFAULT_FINANCIAL_CHARTS_ANNOTATION_COLOR: DEFAULT_FINANCIAL_CHARTS_ANNOTATION_COLOR2,
|
|
DEFAULT_TEXTBOX_COLOR: DEFAULT_TEXTBOX_COLOR2,
|
|
DEFAULT_TEXTBOX_FILL: DEFAULT_TEXTBOX_FILL2,
|
|
DEFAULT_TEXTBOX_STROKE: DEFAULT_TEXTBOX_STROKE2,
|
|
DEFAULT_TEXT_ANNOTATION_COLOR
|
|
} = ThemeSymbols2;
|
|
var stroke2 = {
|
|
stroke: DEFAULT_FINANCIAL_CHARTS_ANNOTATION_COLOR2
|
|
};
|
|
var handle2 = {
|
|
fill: DEFAULT_ANNOTATION_HANDLE_FILL2
|
|
};
|
|
var axisLabel2 = {
|
|
color: "white",
|
|
fill: DEFAULT_FINANCIAL_CHARTS_ANNOTATION_COLOR2
|
|
};
|
|
var lineText2 = {
|
|
color: DEFAULT_FINANCIAL_CHARTS_ANNOTATION_COLOR2
|
|
};
|
|
var font2 = {
|
|
color: DEFAULT_TEXT_ANNOTATION_COLOR,
|
|
fontSize: { $rem: FONT_SIZE_RATIO6.LARGE },
|
|
fontFamily: { $ref: "fontFamily" }
|
|
};
|
|
var measurerStatistics2 = {
|
|
...font2,
|
|
fontSize: { $ref: "fontSize" },
|
|
color: DEFAULT_ANNOTATION_STATISTICS_COLOR2,
|
|
fill: DEFAULT_ANNOTATION_STATISTICS_FILL2,
|
|
stroke: DEFAULT_ANNOTATION_STATISTICS_STROKE2,
|
|
strokeWidth: 1,
|
|
divider: {
|
|
stroke: DEFAULT_ANNOTATION_STATISTICS_DIVIDER_STROKE2,
|
|
strokeWidth: 1,
|
|
strokeOpacity: 0.5
|
|
}
|
|
};
|
|
var measurer2 = {
|
|
...stroke2,
|
|
background: {
|
|
fill: DEFAULT_FINANCIAL_CHARTS_ANNOTATION_BACKGROUND_FILL2,
|
|
fillOpacity: 0.2
|
|
},
|
|
handle: { ...handle2 },
|
|
text: { ...lineText2 },
|
|
statistics: { ...measurerStatistics2 }
|
|
};
|
|
var annotationsTheme2 = {
|
|
// Lines
|
|
line: {
|
|
...stroke2,
|
|
handle: { ...handle2 },
|
|
text: { ...lineText2 }
|
|
},
|
|
"horizontal-line": {
|
|
...stroke2,
|
|
handle: { ...handle2 },
|
|
axisLabel: { ...axisLabel2 },
|
|
text: { ...lineText2 }
|
|
},
|
|
"vertical-line": {
|
|
...stroke2,
|
|
handle: { ...handle2 },
|
|
axisLabel: { ...axisLabel2 },
|
|
text: { ...lineText2 }
|
|
},
|
|
// Channels
|
|
"disjoint-channel": {
|
|
...stroke2,
|
|
background: {
|
|
fill: DEFAULT_FINANCIAL_CHARTS_ANNOTATION_BACKGROUND_FILL2,
|
|
fillOpacity: 0.2
|
|
},
|
|
handle: { ...handle2 },
|
|
text: { ...lineText2 }
|
|
},
|
|
"parallel-channel": {
|
|
...stroke2,
|
|
background: {
|
|
fill: DEFAULT_FINANCIAL_CHARTS_ANNOTATION_BACKGROUND_FILL2,
|
|
fillOpacity: 0.2
|
|
},
|
|
handle: { ...handle2 },
|
|
text: { ...lineText2 }
|
|
},
|
|
// Fibonnaccis
|
|
"fibonacci-retracement": {
|
|
...stroke2,
|
|
strokes: DEFAULT_FIBONACCI_STROKES2,
|
|
rangeStroke: DEFAULT_FINANCIAL_CHARTS_ANNOTATION_COLOR2,
|
|
handle: { ...handle2 },
|
|
text: { ...lineText2, position: "center" },
|
|
label: {
|
|
...font2,
|
|
color: void 0,
|
|
fontSize: { $rem: FONT_SIZE_RATIO6.SMALLER }
|
|
}
|
|
},
|
|
"fibonacci-retracement-trend-based": {
|
|
...stroke2,
|
|
strokes: DEFAULT_FIBONACCI_STROKES2,
|
|
rangeStroke: DEFAULT_FINANCIAL_CHARTS_ANNOTATION_COLOR2,
|
|
handle: { ...handle2 },
|
|
text: { ...lineText2, position: "center" },
|
|
label: {
|
|
...font2,
|
|
color: void 0,
|
|
fontSize: { $rem: FONT_SIZE_RATIO6.SMALLER }
|
|
}
|
|
},
|
|
// Texts
|
|
callout: {
|
|
...stroke2,
|
|
...font2,
|
|
color: { $ref: "textColor" },
|
|
handle: { ...handle2 },
|
|
fill: DEFAULT_FINANCIAL_CHARTS_ANNOTATION_BACKGROUND_FILL2,
|
|
fillOpacity: 0.2
|
|
},
|
|
comment: {
|
|
...font2,
|
|
color: "white",
|
|
fontWeight: 700,
|
|
handle: { ...handle2 },
|
|
fill: DEFAULT_FINANCIAL_CHARTS_ANNOTATION_COLOR2
|
|
},
|
|
note: {
|
|
...font2,
|
|
color: DEFAULT_TEXTBOX_COLOR2,
|
|
fill: DEFAULT_FINANCIAL_CHARTS_ANNOTATION_COLOR2,
|
|
stroke: { $ref: "chartBackgroundColor" },
|
|
strokeWidth: 1,
|
|
strokeOpacity: 1,
|
|
handle: { ...handle2 },
|
|
background: {
|
|
fill: DEFAULT_TEXTBOX_FILL2,
|
|
stroke: DEFAULT_TEXTBOX_STROKE2,
|
|
strokeWidth: 1
|
|
}
|
|
},
|
|
text: {
|
|
...font2,
|
|
handle: { ...handle2 }
|
|
},
|
|
// Shapes
|
|
arrow: {
|
|
...stroke2,
|
|
handle: { ...handle2 },
|
|
text: { ...lineText2 }
|
|
},
|
|
"arrow-up": {
|
|
fill: { $palette: "up.fill" },
|
|
handle: { ...handle2, stroke: DEFAULT_FINANCIAL_CHARTS_ANNOTATION_COLOR2 }
|
|
},
|
|
"arrow-down": {
|
|
fill: { $palette: "down.fill" },
|
|
handle: { ...handle2, stroke: DEFAULT_FINANCIAL_CHARTS_ANNOTATION_COLOR2 }
|
|
},
|
|
// Measurers
|
|
"date-range": {
|
|
...measurer2
|
|
},
|
|
"price-range": {
|
|
...measurer2
|
|
},
|
|
"date-price-range": {
|
|
...measurer2
|
|
},
|
|
"quick-date-price-range": {
|
|
up: {
|
|
...stroke2,
|
|
fill: DEFAULT_FINANCIAL_CHARTS_ANNOTATION_BACKGROUND_FILL2,
|
|
fillOpacity: 0.2,
|
|
handle: { ...handle2 },
|
|
statistics: {
|
|
...measurerStatistics2,
|
|
color: "#fff",
|
|
fill: DEFAULT_FINANCIAL_CHARTS_ANNOTATION_BACKGROUND_FILL2,
|
|
strokeWidth: 0,
|
|
divider: {
|
|
stroke: "#fff",
|
|
strokeWidth: 1,
|
|
strokeOpacity: 0.5
|
|
}
|
|
}
|
|
},
|
|
down: {
|
|
...stroke2,
|
|
stroke: DEFAULT_ANNOTATION_STATISTICS_DOWN_STROKE2,
|
|
fill: DEFAULT_ANNOTATION_STATISTICS_DOWN_FILL2,
|
|
fillOpacity: 0.2,
|
|
handle: {
|
|
...handle2,
|
|
stroke: DEFAULT_ANNOTATION_STATISTICS_DOWN_STROKE2
|
|
},
|
|
statistics: {
|
|
...measurerStatistics2,
|
|
color: "#fff",
|
|
fill: DEFAULT_ANNOTATION_STATISTICS_DOWN_FILL2,
|
|
strokeWidth: 0,
|
|
divider: {
|
|
stroke: "#fff",
|
|
strokeWidth: 1,
|
|
strokeOpacity: 0.5
|
|
}
|
|
}
|
|
}
|
|
},
|
|
axesButtons: {
|
|
enabled: true
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/preset/priceVolumePreset.ts
|
|
var chartTypes = ["ohlc", "line", "step-line", "hlc", "high-low", "candlestick", "hollow-candlestick"];
|
|
var toolbarButtons = [
|
|
{
|
|
icon: "trend-line-drawing",
|
|
tooltip: "toolbarAnnotationsLineAnnotations",
|
|
value: "line-menu"
|
|
},
|
|
{
|
|
icon: "fibonacci-retracement-drawing",
|
|
tooltip: "toolbarAnnotationsFibonacciAnnotations",
|
|
value: "fibonacci-menu"
|
|
},
|
|
{
|
|
icon: "text-annotation",
|
|
tooltip: "toolbarAnnotationsTextAnnotations",
|
|
value: "text-menu"
|
|
},
|
|
{
|
|
icon: "arrow-drawing",
|
|
tooltip: "toolbarAnnotationsShapeAnnotations",
|
|
value: "shape-menu"
|
|
},
|
|
{
|
|
icon: "measurer-drawing",
|
|
tooltip: "toolbarAnnotationsMeasurerAnnotations",
|
|
value: "measurer-menu"
|
|
},
|
|
{
|
|
icon: "delete",
|
|
tooltip: "toolbarAnnotationsClearAll",
|
|
value: "clear"
|
|
}
|
|
];
|
|
function priceVolume(opts, _presetTheme, getTheme) {
|
|
const {
|
|
dateKey = "date",
|
|
highKey = "high",
|
|
openKey = "open",
|
|
lowKey = "low",
|
|
closeKey = "close",
|
|
volumeKey = "volume",
|
|
chartType = "candlestick",
|
|
navigator = false,
|
|
volume = true,
|
|
rangeButtons = true,
|
|
statusBar = true,
|
|
toolbar: toolbar2 = true,
|
|
zoom = true,
|
|
sync = false,
|
|
theme,
|
|
data,
|
|
formatter,
|
|
...unusedOpts
|
|
} = opts;
|
|
const priceSeries = createPriceSeries(chartType, dateKey, highKey, lowKey, openKey, closeKey);
|
|
const volumeSeries = createVolumeSeries(getTheme, dateKey, openKey, closeKey, volume, volumeKey);
|
|
const miniChart = volume ? {
|
|
miniChart: {
|
|
enabled: navigator,
|
|
series: [
|
|
{
|
|
type: "line",
|
|
xKey: dateKey,
|
|
yKey: volumeKey,
|
|
stroke: SAFE_STROKE_FILL_OPERATION5,
|
|
marker: { enabled: false }
|
|
}
|
|
]
|
|
},
|
|
height: 40,
|
|
minHandle: {
|
|
height: 46
|
|
},
|
|
maxHandle: {
|
|
height: 46
|
|
}
|
|
} : null;
|
|
const navigatorOpts = {
|
|
navigator: {
|
|
enabled: navigator,
|
|
...miniChart
|
|
}
|
|
};
|
|
const annotationOpts = {
|
|
annotations: {
|
|
enabled: toolbar2,
|
|
optionsToolbar: {
|
|
enabled: toolbar2
|
|
},
|
|
// @ts-expect-error undocumented option
|
|
snap: true,
|
|
toolbar: {
|
|
enabled: toolbar2,
|
|
buttons: toolbarButtons,
|
|
padding: 0
|
|
},
|
|
data,
|
|
xKey: dateKey,
|
|
volumeKey: volume ? volumeKey : void 0
|
|
}
|
|
};
|
|
const statusBarOpts = statusBar ? {
|
|
statusBar: {
|
|
enabled: true,
|
|
highKey,
|
|
openKey,
|
|
lowKey,
|
|
closeKey,
|
|
volumeKey: volume ? volumeKey : void 0
|
|
}
|
|
} : null;
|
|
const zoomOpts = {
|
|
zoom: {
|
|
enabled: zoom,
|
|
autoScaling: {
|
|
enabled: true
|
|
},
|
|
onDataChange: {
|
|
stickToEnd: true
|
|
},
|
|
// @ts-expect-error undocumented option
|
|
enableIndependentAxes: true
|
|
}
|
|
};
|
|
const toolbarOpts = {
|
|
ranges: {
|
|
enabled: rangeButtons
|
|
}
|
|
};
|
|
const syncGroup = sync ? {
|
|
sync: {
|
|
enabled: sync,
|
|
nodeInteraction: true,
|
|
zoom: true
|
|
}
|
|
} : null;
|
|
const volumeAxis = volume ? {
|
|
yVolume: {
|
|
type: "number",
|
|
position: "left",
|
|
label: { enabled: false },
|
|
crosshair: { enabled: false },
|
|
gridLine: { enabled: false },
|
|
nice: false,
|
|
// @ts-expect-error undocumented option
|
|
layoutConstraints: {
|
|
stacked: false,
|
|
width: 20,
|
|
unit: "percent",
|
|
align: "end"
|
|
}
|
|
}
|
|
} : {};
|
|
return {
|
|
theme: {
|
|
baseTheme: typeof theme === "string" ? theme : "ag-financial",
|
|
...mergeDefaults25(typeof theme === "object" ? theme : null, {
|
|
overrides: {
|
|
common: {
|
|
title: { padding: 4 },
|
|
padding: {
|
|
top: 6,
|
|
right: 8,
|
|
bottom: 6
|
|
},
|
|
chartToolbar: {
|
|
enabled: toolbar2
|
|
},
|
|
annotations: { ...annotationsTheme2 },
|
|
axes: {
|
|
number: {
|
|
interval: { maxSpacing: 45 },
|
|
label: { format: ".2f" }
|
|
},
|
|
category: {
|
|
gridLine: { enabled: true }
|
|
},
|
|
time: {
|
|
gridLine: { enabled: true }
|
|
},
|
|
"unit-time": {
|
|
gridLine: { enabled: true }
|
|
},
|
|
"ordinal-time": {
|
|
gridLine: { enabled: true }
|
|
}
|
|
}
|
|
},
|
|
bar: {
|
|
series: {
|
|
fillOpacity: 0.5,
|
|
highlight: { unhighlightedItem: { opacity: 1 }, unhighlightedSeries: { opacity: 1 } }
|
|
}
|
|
},
|
|
line: {
|
|
series: {
|
|
marker: { enabled: false },
|
|
highlight: { unhighlightedSeries: { opacity: 1 } },
|
|
...inlineSwitch(chartType, {
|
|
hlc: {
|
|
stroke: { $palette: "altNeutral.stroke" },
|
|
strokeWidth: 2
|
|
},
|
|
line: {
|
|
stroke: { $palette: "neutral.stroke" }
|
|
},
|
|
"step-line": {
|
|
stroke: { $palette: "neutral.stroke" },
|
|
interpolation: { type: "step" }
|
|
}
|
|
})
|
|
}
|
|
},
|
|
candlestick: {
|
|
series: {
|
|
highlight: { unhighlightedItem: { opacity: 1 }, unhighlightedSeries: { opacity: 1 } },
|
|
...inlineSwitch(chartType, {
|
|
"hollow-candlestick": {
|
|
item: {
|
|
up: { fill: "transparent" }
|
|
}
|
|
}
|
|
})
|
|
}
|
|
},
|
|
ohlc: {
|
|
series: {
|
|
highlight: { unhighlightedItem: { opacity: 1 }, unhighlightedSeries: { opacity: 1 } }
|
|
}
|
|
},
|
|
"range-area": {
|
|
series: {
|
|
fillOpacity: 0.3,
|
|
strokeWidth: 2,
|
|
highlight: {
|
|
bringToFront: false,
|
|
unhighlightedItem: { opacity: 1 },
|
|
unhighlightedSeries: { opacity: 1 }
|
|
},
|
|
...inlineSwitch(chartType, {
|
|
hlc: {
|
|
fill: {
|
|
$if: [
|
|
{ $eq: [{ $value: "$index" }, 1] },
|
|
{ $palette: "up.fill" },
|
|
{ $palette: "down.fill" }
|
|
]
|
|
},
|
|
stroke: {
|
|
$if: [
|
|
{ $eq: [{ $value: "$index" }, 1] },
|
|
{ $palette: "up.stroke" },
|
|
{ $palette: "down.stroke" }
|
|
]
|
|
}
|
|
}
|
|
})
|
|
}
|
|
},
|
|
"range-bar": {
|
|
series: {
|
|
highlight: {
|
|
unhighlightedItem: { opacity: 1 },
|
|
unhighlightedSeries: { opacity: 1 }
|
|
},
|
|
...inlineSwitch(chartType, {
|
|
"high-low": {
|
|
fill: { $palette: "neutral.fill" },
|
|
stroke: { $palette: "neutral.stroke" }
|
|
}
|
|
})
|
|
}
|
|
}
|
|
}
|
|
})
|
|
},
|
|
animation: { enabled: false },
|
|
legend: { enabled: false },
|
|
series: [...volumeSeries, ...priceSeries],
|
|
axes: {
|
|
y: {
|
|
type: "number",
|
|
position: "right",
|
|
crosshair: {
|
|
enabled: true,
|
|
snap: false
|
|
},
|
|
// @ts-expect-error undocumented option
|
|
layoutConstraints: {
|
|
stacked: false,
|
|
width: 100,
|
|
unit: "percent",
|
|
align: "start"
|
|
}
|
|
},
|
|
...volumeAxis,
|
|
x: {
|
|
type: "ordinal-time",
|
|
position: "bottom",
|
|
line: {
|
|
enabled: false
|
|
},
|
|
label: {
|
|
enabled: true
|
|
},
|
|
crosshair: {
|
|
enabled: true
|
|
}
|
|
}
|
|
},
|
|
tooltip: { enabled: false },
|
|
data,
|
|
formatter,
|
|
...annotationOpts,
|
|
...navigatorOpts,
|
|
...statusBarOpts,
|
|
...zoomOpts,
|
|
...toolbarOpts,
|
|
...syncGroup,
|
|
...unusedOpts
|
|
};
|
|
}
|
|
function createVolumeSeries(getTheme, xKey, openKey, closeKey, volume, volumeKey) {
|
|
if (!volume)
|
|
return [];
|
|
return [
|
|
{
|
|
type: "bar",
|
|
xKey,
|
|
yKey: volumeKey,
|
|
yKeyAxis: "yVolume",
|
|
tooltip: { enabled: false },
|
|
// @ts-expect-error undocumented options: simpleItemStyler, focusPriority
|
|
simpleItemStyler(datum) {
|
|
const { up, down } = getTheme().palette;
|
|
return { fill: datum[openKey] < datum[closeKey] ? up?.fill : down?.fill };
|
|
},
|
|
focusPriority: 1,
|
|
highlight: { unhighlightedSeries: { opacity: 1 } }
|
|
}
|
|
];
|
|
}
|
|
var RANGE_AREA_TYPE = "range-area";
|
|
function createPriceSeries(chartType, xKey, highKey, lowKey, openKey, closeKey) {
|
|
const keys = {
|
|
xKey,
|
|
openKey,
|
|
closeKey,
|
|
highKey,
|
|
lowKey
|
|
};
|
|
const singleKeys = {
|
|
xKey,
|
|
yKey: closeKey
|
|
};
|
|
const common = {
|
|
pickOutsideVisibleMinorAxis: true
|
|
};
|
|
switch (chartType ?? "candlestick") {
|
|
case "ohlc":
|
|
return createPriceSeriesOHLC(common, keys);
|
|
case "line":
|
|
case "step-line":
|
|
return createPriceSeriesLine(common, singleKeys);
|
|
case "hlc":
|
|
return createPriceSeriesHLC(common, singleKeys, keys);
|
|
case "high-low":
|
|
return createPriceSeriesHighLow(common, keys);
|
|
case "candlestick":
|
|
case "hollow-candlestick":
|
|
return createPriceSeriesCandlestick(common, keys);
|
|
default:
|
|
Logger23.warnOnce(`unknown chart type: ${chartType}; expected one of: ${chartTypes.join(", ")}`);
|
|
return createPriceSeriesCandlestick(common, keys);
|
|
}
|
|
}
|
|
function createPriceSeriesOHLC(common, keys) {
|
|
return [
|
|
{
|
|
type: "ohlc",
|
|
// @ts-expect-error undocumented option
|
|
focusPriority: 0,
|
|
...common,
|
|
...keys
|
|
}
|
|
];
|
|
}
|
|
function createPriceSeriesLine(common, singleKeys) {
|
|
return [
|
|
{
|
|
type: "line",
|
|
// @ts-expect-error undocumented option
|
|
focusPriority: 0,
|
|
...common,
|
|
...singleKeys
|
|
}
|
|
];
|
|
}
|
|
function createPriceSeriesHLC(common, singleKeys, { xKey, highKey, closeKey, lowKey }) {
|
|
return [
|
|
{
|
|
type: RANGE_AREA_TYPE,
|
|
// @ts-expect-error undocumented option
|
|
focusPriority: 0,
|
|
...common,
|
|
xKey,
|
|
yHighKey: highKey,
|
|
yLowKey: closeKey
|
|
},
|
|
{
|
|
type: RANGE_AREA_TYPE,
|
|
// @ts-expect-error undocumented option
|
|
focusPriority: 0,
|
|
...common,
|
|
xKey,
|
|
yHighKey: closeKey,
|
|
yLowKey: lowKey
|
|
},
|
|
{
|
|
type: "line",
|
|
...common,
|
|
...singleKeys
|
|
}
|
|
];
|
|
}
|
|
function createPriceSeriesHighLow(common, { xKey, highKey, lowKey }) {
|
|
return [
|
|
{
|
|
type: "range-bar",
|
|
...common,
|
|
xKey,
|
|
yHighKey: highKey,
|
|
yLowKey: lowKey,
|
|
tooltip: { range: "nearest" },
|
|
// @ts-expect-error undocumented option
|
|
focusPriority: 0
|
|
}
|
|
];
|
|
}
|
|
function createPriceSeriesCandlestick(common, keys) {
|
|
return [
|
|
{
|
|
type: "candlestick",
|
|
// @ts-expect-error undocumented option
|
|
focusPriority: 0,
|
|
...common,
|
|
...keys
|
|
}
|
|
];
|
|
}
|
|
function inlineSwitch(caseName, switchCases) {
|
|
return switchCases[caseName] ?? switchCases.default;
|
|
}
|
|
|
|
// packages/ag-charts-enterprise/src/preset/priceVolumePresetModules.ts
|
|
var priceVolumeOptionsDef = {
|
|
chartType: union5("candlestick", "hollow-candlestick", "ohlc", "line", "step-line", "hlc", "high-low"),
|
|
dateKey: string25,
|
|
openKey: string25,
|
|
highKey: string25,
|
|
lowKey: string25,
|
|
closeKey: string25,
|
|
volumeKey: string25,
|
|
navigator: boolean20,
|
|
volume: boolean20,
|
|
rangeButtons: boolean20,
|
|
statusBar: boolean20,
|
|
toolbar: boolean20,
|
|
zoom: boolean20,
|
|
sync: boolean20,
|
|
// Valid pass-through options
|
|
theme: defined2,
|
|
container: defined2,
|
|
width: defined2,
|
|
height: defined2,
|
|
minWidth: defined2,
|
|
minHeight: defined2,
|
|
listeners: defined2,
|
|
initialState: defined2,
|
|
title: defined2,
|
|
data: array3,
|
|
formatter: defined2
|
|
};
|
|
var commonGaugeOptions2 = {
|
|
// Valid pass-through options
|
|
theme: defined2,
|
|
container: defined2,
|
|
animation: defined2,
|
|
background: defined2,
|
|
contextMenu: defined2,
|
|
context: () => true,
|
|
listeners: defined2,
|
|
locale: defined2,
|
|
width: defined2,
|
|
height: defined2,
|
|
minWidth: defined2,
|
|
minHeight: defined2,
|
|
title: defined2,
|
|
subtitle: defined2,
|
|
footnote: defined2,
|
|
padding: defined2,
|
|
tooltip: {
|
|
...tooltipOptionsDefs2,
|
|
...commonChartOptionsDefs2.tooltip
|
|
}
|
|
};
|
|
commonGaugeOptions2.overrideDevicePixelRatio = undocumented19(positiveNumber10);
|
|
var PriceVolumePresetModule = {
|
|
type: "preset",
|
|
name: "price-volume",
|
|
enterprise: true,
|
|
dependencies: [ChartToolbarModule, StatusBarModule],
|
|
version: VERSION51,
|
|
options: priceVolumeOptionsDef,
|
|
create: priceVolume
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/module-bundles/financial.ts
|
|
var FinancialChartModule = [
|
|
PriceVolumePresetModule,
|
|
BarSeriesModule2,
|
|
LineSeriesModule2,
|
|
CandlestickSeriesModule,
|
|
OhlcSeriesModule,
|
|
RangeBarSeriesModule,
|
|
RangeAreaSeriesModule,
|
|
AnimationModule,
|
|
AnnotationsModule,
|
|
BandHighlightModule,
|
|
ChartToolbarModule,
|
|
ContextMenuModule,
|
|
CrosshairModule,
|
|
DataSourceModule,
|
|
ErrorBarsModule,
|
|
GradientLegendModule,
|
|
NavigatorModule,
|
|
RangesModule,
|
|
SyncModule,
|
|
ZoomModule,
|
|
OrdinalTimeAxisModule,
|
|
TimeAxisModule,
|
|
NumberAxisModule
|
|
];
|
|
|
|
// packages/ag-charts-enterprise/src/module-bundles/gauge.ts
|
|
var AllGaugeModule = [LinearGaugeModule, RadialGaugeModule];
|
|
|
|
// packages/ag-charts-enterprise/src/module-bundles/polar.ts
|
|
import { AllPolarModule as AllCommunityPolarModule } from "ag-charts-community";
|
|
var AllPolarModule = [
|
|
AllCommunityPolarModule,
|
|
AngleNumberAxisModule,
|
|
AngleCategoryAxisModule,
|
|
RadiusNumberAxisModule,
|
|
RadiusCategoryAxisModule,
|
|
NightingaleSeriesModule,
|
|
RadarAreaSeriesModule,
|
|
RadarLineSeriesModule,
|
|
RadialBarSeriesModule,
|
|
RadialColumnSeriesModule,
|
|
AnimationModule,
|
|
ContextMenuModule,
|
|
DataSourceModule,
|
|
GradientLegendModule
|
|
].flat();
|
|
|
|
// packages/ag-charts-enterprise/src/module-bundles/topology.ts
|
|
var AllMapSeriesModule = [
|
|
MapLineSeriesModule,
|
|
MapLineBackgroundSeriesModule,
|
|
MapMarkerSeriesModule,
|
|
MapShapeSeriesModule,
|
|
MapShapeBackgroundSeriesModule
|
|
];
|
|
|
|
// packages/ag-charts-enterprise/src/module-bundles/all.ts
|
|
var AllEnterpriseModule = [
|
|
AllCommunityModule,
|
|
AllCartesianModule,
|
|
AllPolarModule,
|
|
AllMapSeriesModule,
|
|
AllGaugeModule,
|
|
FinancialChartModule,
|
|
ChordSeriesModule,
|
|
PyramidSeriesModule,
|
|
SankeySeriesModule,
|
|
SunburstSeriesModule,
|
|
TreemapSeriesModule
|
|
].flat();
|
|
|
|
// packages/ag-charts-enterprise/src/module-bundles/integrated.ts
|
|
import { AgCharts, ModuleRegistry as ModuleRegistry2, VERSION as VERSION52, _Scene, _Theme as _Theme2, _Util } from "ag-charts-community";
|
|
|
|
// packages/ag-charts-enterprise/src/setup.ts
|
|
import "ag-charts-community";
|
|
import { ModuleRegistry, enterpriseRegistry } from "ag-charts-core";
|
|
function setupEnterpriseModules() {
|
|
ModuleRegistry.registerModules(AllEnterpriseModule);
|
|
enterpriseRegistry.styles = styles_default;
|
|
enterpriseRegistry.licenseManager = (options) => new LicenseManager(
|
|
options.container?.ownerDocument ?? (typeof document === "undefined" ? void 0 : document)
|
|
);
|
|
enterpriseRegistry.injectWatermark = injectWatermark;
|
|
enterpriseRegistry.createBackground = (ctx) => new Background(ctx);
|
|
enterpriseRegistry.createForeground = (ctx) => new Foreground(ctx);
|
|
}
|
|
|
|
// packages/ag-charts-enterprise/src/module-bundles/integrated.ts
|
|
var LicenseManager2 = {
|
|
setLicenseKey(key) {
|
|
LicenseManager.setLicenseKey(key);
|
|
}
|
|
};
|
|
var AgChartsEnterpriseModule = {
|
|
VERSION: VERSION52,
|
|
_Scene,
|
|
_Theme: _Theme2,
|
|
_Util,
|
|
create: AgCharts.create.bind(AgCharts),
|
|
createSparkline: AgCharts.__createSparkline.bind(AgCharts),
|
|
setup: () => {
|
|
ModuleRegistry2.setRegistryMode(ModuleRegistry2.RegistryMode.Integrated);
|
|
setupEnterpriseModules();
|
|
},
|
|
setGridContext: LicenseManager.setGridContext.bind(LicenseManager),
|
|
setLicenseKey: LicenseManager.setLicenseKey.bind(LicenseManager),
|
|
isEnterprise: true
|
|
};
|
|
|
|
// packages/ag-charts-enterprise/src/main.ts
|
|
ModuleRegistry3.setRegistryMode(ModuleRegistry3.RegistryMode.Enterprise);
|
|
enterpriseRegistry2.styles = styles_default;
|
|
enterpriseRegistry2.licenseManager = (options) => new LicenseManager(options.container?.ownerDocument ?? (typeof document === "undefined" ? void 0 : document));
|
|
enterpriseRegistry2.injectWatermark = injectWatermark;
|
|
enterpriseRegistry2.createBackground = (ctx) => new Background(ctx);
|
|
enterpriseRegistry2.createForeground = (ctx) => new Foreground(ctx);
|
|
export {
|
|
AgChartsEnterpriseModule,
|
|
AgTooltipAnchorToType,
|
|
AgTooltipPlacementType,
|
|
AllCartesianAxesModule,
|
|
AllCartesianModule,
|
|
AllCartesianSeriesModule,
|
|
AllEnterpriseModule,
|
|
AllGaugeModule,
|
|
AllMapSeriesModule,
|
|
AllPolarModule,
|
|
AngleCategoryAxisModule,
|
|
AngleNumberAxisModule,
|
|
AnimationModule,
|
|
AnnotationsModule,
|
|
BandHighlightModule,
|
|
BoxPlotSeriesModule,
|
|
CandlestickSeriesModule,
|
|
ChartToolbarModule,
|
|
ChordSeriesModule,
|
|
ConeFunnelSeriesModule,
|
|
ContextMenuModule,
|
|
CrosshairModule,
|
|
DataSourceModule,
|
|
ErrorBarsModule,
|
|
FinancialChartModule,
|
|
FlashOnUpdateModule,
|
|
FunnelSeriesModule,
|
|
GradientLegendModule,
|
|
HeatmapSeriesModule,
|
|
LicenseManager2 as LicenseManager,
|
|
LinearGaugeModule,
|
|
MapLineBackgroundSeriesModule,
|
|
MapLineSeriesModule,
|
|
MapMarkerSeriesModule,
|
|
MapShapeBackgroundSeriesModule,
|
|
MapShapeSeriesModule,
|
|
NavigatorModule,
|
|
NightingaleSeriesModule,
|
|
OhlcSeriesModule,
|
|
OrdinalTimeAxisModule,
|
|
PyramidSeriesModule,
|
|
RadarAreaSeriesModule,
|
|
RadarLineSeriesModule,
|
|
RadialBarSeriesModule,
|
|
RadialColumnSeriesModule,
|
|
RadialGaugeModule,
|
|
RadiusCategoryAxisModule,
|
|
RadiusNumberAxisModule,
|
|
RangeAreaSeriesModule,
|
|
RangeBarSeriesModule,
|
|
RangesModule,
|
|
SankeySeriesModule,
|
|
ScrollbarModule,
|
|
StatusBarModule,
|
|
SunburstSeriesModule,
|
|
SyncModule,
|
|
TreemapSeriesModule,
|
|
WaterfallSeriesModule,
|
|
ZoomModule
|
|
};
|