hyperprop-charting-library 0.1.62 → 0.1.64
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/hyperprop-charting-library.cjs +101 -10
- package/dist/hyperprop-charting-library.js +101 -10
- package/dist/index.cjs +101 -10
- package/dist/index.js +101 -10
- package/package.json +1 -1
|
@@ -1065,9 +1065,14 @@ function createChart(element, options = {}) {
|
|
|
1065
1065
|
}
|
|
1066
1066
|
canvas.style.display = "block";
|
|
1067
1067
|
canvas.style.touchAction = "none";
|
|
1068
|
+
canvas.style.userSelect = "none";
|
|
1069
|
+
canvas.style.setProperty("-webkit-user-select", "none");
|
|
1070
|
+
canvas.style.setProperty("-webkit-touch-callout", "none");
|
|
1071
|
+
canvas.setAttribute("draggable", "false");
|
|
1068
1072
|
element.innerHTML = "";
|
|
1069
1073
|
element.appendChild(canvas);
|
|
1070
1074
|
const margin = { top: 16, right: 72, bottom: 34, left: 12 };
|
|
1075
|
+
let cachedRightMargin = margin.right;
|
|
1071
1076
|
const minVisibleBars = Math.max(1, Math.floor(mergedOptions.minVisibleBars));
|
|
1072
1077
|
const maxVisibleBars = Math.max(minVisibleBars, Math.floor(mergedOptions.maxVisibleBars));
|
|
1073
1078
|
const maxPanBars = Math.max(0, Math.floor(mergedOptions.maxPanBars));
|
|
@@ -1289,14 +1294,34 @@ function createChart(element, options = {}) {
|
|
|
1289
1294
|
const decimalPart = decimals > 0 ? `.${"8".repeat(decimals)}` : "";
|
|
1290
1295
|
return `${integerPart}${decimalPart}`;
|
|
1291
1296
|
};
|
|
1297
|
+
const getMeasuredLabelWidth = (text, paddingX) => {
|
|
1298
|
+
return Math.ceil(ctx.measureText(text).width) + paddingX * 2;
|
|
1299
|
+
};
|
|
1300
|
+
const getStabilizedNumericLabelWidth = (text, paddingX) => {
|
|
1301
|
+
const measured = getMeasuredLabelWidth(text, paddingX);
|
|
1302
|
+
if (!mergedOptions.stabilizePriceLabels || !/\d/.test(text)) {
|
|
1303
|
+
return measured;
|
|
1304
|
+
}
|
|
1305
|
+
let stableWidth = measured;
|
|
1306
|
+
for (const digit of ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]) {
|
|
1307
|
+
stableWidth = Math.max(stableWidth, getMeasuredLabelWidth(text.replace(/\d/g, digit), paddingX));
|
|
1308
|
+
}
|
|
1309
|
+
return stableWidth;
|
|
1310
|
+
};
|
|
1292
1311
|
const getPriceLabelWidth = (priceText, paddingX) => {
|
|
1293
|
-
const measured =
|
|
1312
|
+
const measured = getStabilizedNumericLabelWidth(priceText, paddingX);
|
|
1294
1313
|
if (!mergedOptions.stabilizePriceLabels) {
|
|
1295
1314
|
return measured;
|
|
1296
1315
|
}
|
|
1297
|
-
const templateWidth =
|
|
1316
|
+
const templateWidth = getStabilizedNumericLabelWidth(getStabilizedPriceTemplate(), paddingX);
|
|
1298
1317
|
return Math.max(measured, templateWidth);
|
|
1299
1318
|
};
|
|
1319
|
+
const getStableLabelWidth = (text, paddingX) => {
|
|
1320
|
+
return getStabilizedNumericLabelWidth(text, paddingX);
|
|
1321
|
+
};
|
|
1322
|
+
const resetRightMarginCache = () => {
|
|
1323
|
+
cachedRightMargin = margin.right;
|
|
1324
|
+
};
|
|
1300
1325
|
const parseData = (nextData) => {
|
|
1301
1326
|
const dedupedByTime = /* @__PURE__ */ new Map();
|
|
1302
1327
|
for (const point of nextData) {
|
|
@@ -1822,22 +1847,33 @@ function createChart(element, options = {}) {
|
|
|
1822
1847
|
const labels = { ...DEFAULT_LABELS_OPTIONS, ...mergedOptions.labels ?? {} };
|
|
1823
1848
|
const estimateRightMargin = () => {
|
|
1824
1849
|
const paddingX = Math.max(4, labels.labelPaddingX);
|
|
1825
|
-
const measure = (text) => Math.ceil(ctx.measureText(text).width) + paddingX * 2;
|
|
1826
1850
|
let required = margin.right - 1;
|
|
1851
|
+
const includeWidth = (contentWidth) => {
|
|
1852
|
+
if (Number.isFinite(contentWidth)) {
|
|
1853
|
+
required = Math.max(required, contentWidth);
|
|
1854
|
+
}
|
|
1855
|
+
};
|
|
1827
1856
|
const include = (text) => {
|
|
1828
1857
|
const normalized = text?.trim();
|
|
1829
1858
|
if (normalized) {
|
|
1830
|
-
|
|
1859
|
+
includeWidth(getStableLabelWidth(normalized, paddingX));
|
|
1860
|
+
}
|
|
1861
|
+
};
|
|
1862
|
+
const includePrice = (price) => {
|
|
1863
|
+
if (Number.isFinite(price)) {
|
|
1864
|
+
includeWidth(getPriceLabelWidth(formatPrice(price), paddingX));
|
|
1831
1865
|
}
|
|
1832
1866
|
};
|
|
1833
1867
|
const ticker2 = mergedOptions.tickerLine ?? DEFAULT_OPTIONS.tickerLine;
|
|
1834
1868
|
const lastPoint2 = data[data.length - 1];
|
|
1835
1869
|
if ((ticker2.visible ?? true) && labels.showLastPrice && lastPoint2) {
|
|
1836
|
-
|
|
1870
|
+
const tickerPrice2 = ticker2.smoothing && smoothedTickerPrice !== null ? smoothedTickerPrice : lastPoint2.c;
|
|
1871
|
+
includePrice(tickerPrice2);
|
|
1837
1872
|
if (ticker2.labelSubtext) include(String(ticker2.labelSubtext));
|
|
1838
1873
|
for (const subtext of ticker2.labelSubtexts ?? []) {
|
|
1839
1874
|
include(String(subtext));
|
|
1840
1875
|
}
|
|
1876
|
+
if (ticker2.showCountdownInLabel) include("88:88");
|
|
1841
1877
|
}
|
|
1842
1878
|
if (labels.showSymbolName) {
|
|
1843
1879
|
include(labels.symbolName);
|
|
@@ -1859,18 +1895,24 @@ function createChart(element, options = {}) {
|
|
|
1859
1895
|
for (const line of priceLines) {
|
|
1860
1896
|
const mergedLine = { ...DEFAULT_PRICE_LINE_OPTIONS, ...line };
|
|
1861
1897
|
if (mergedLine.visible && Number.isFinite(mergedLine.price)) {
|
|
1862
|
-
|
|
1898
|
+
if (mergedLine.label) {
|
|
1899
|
+
include(mergedLine.label);
|
|
1900
|
+
} else {
|
|
1901
|
+
includePrice(mergedLine.price);
|
|
1902
|
+
}
|
|
1863
1903
|
}
|
|
1864
1904
|
}
|
|
1865
1905
|
for (const line of orderLines) {
|
|
1866
1906
|
const mergedLine = { ...DEFAULT_ORDER_LINE_OPTIONS, ...line };
|
|
1867
1907
|
const renderPrice = mergedLine.behavior === "follow" && Number.isFinite(mergedLine.followPrice) ? mergedLine.followPrice : mergedLine.price;
|
|
1868
1908
|
if (mergedLine.visible && Number.isFinite(renderPrice)) {
|
|
1869
|
-
|
|
1909
|
+
includePrice(renderPrice);
|
|
1870
1910
|
}
|
|
1871
1911
|
}
|
|
1872
1912
|
const maxRightMargin = Math.max(margin.right, width - margin.left - 160);
|
|
1873
|
-
|
|
1913
|
+
const nextRightMargin = Math.min(maxRightMargin, Math.max(margin.right, Math.ceil(required + 1)));
|
|
1914
|
+
cachedRightMargin = Math.max(cachedRightMargin, nextRightMargin);
|
|
1915
|
+
return Math.min(maxRightMargin, cachedRightMargin);
|
|
1874
1916
|
};
|
|
1875
1917
|
const rightMargin = estimateRightMargin();
|
|
1876
1918
|
const chartLeft = margin.left;
|
|
@@ -3517,6 +3559,9 @@ function createChart(element, options = {}) {
|
|
|
3517
3559
|
draw();
|
|
3518
3560
|
};
|
|
3519
3561
|
const onPointerDown = (event) => {
|
|
3562
|
+
if (event.pointerType === "touch" || event.pointerType === "pen") {
|
|
3563
|
+
event.preventDefault();
|
|
3564
|
+
}
|
|
3520
3565
|
const point = getCanvasPoint(event);
|
|
3521
3566
|
if (event.pointerType === "touch") {
|
|
3522
3567
|
touchPointers.set(event.pointerId, point);
|
|
@@ -3615,12 +3660,29 @@ function createChart(element, options = {}) {
|
|
|
3615
3660
|
isDragging = true;
|
|
3616
3661
|
dragMode = region;
|
|
3617
3662
|
activePointerId = event.pointerId;
|
|
3618
|
-
|
|
3663
|
+
const crosshairDrag = (event.pointerType === "touch" || event.pointerType === "pen") && region === "plot";
|
|
3664
|
+
pointerDownInfo = {
|
|
3665
|
+
pointerId: event.pointerId,
|
|
3666
|
+
pointerType: event.pointerType,
|
|
3667
|
+
x: point.x,
|
|
3668
|
+
y: point.y,
|
|
3669
|
+
region,
|
|
3670
|
+
moved: false,
|
|
3671
|
+
crosshairDrag
|
|
3672
|
+
};
|
|
3619
3673
|
lastPointerX = point.x;
|
|
3620
3674
|
lastPointerY = point.y;
|
|
3621
3675
|
canvas.setPointerCapture(event.pointerId);
|
|
3676
|
+
if (crosshairDrag) {
|
|
3677
|
+
canvas.style.cursor = "crosshair";
|
|
3678
|
+
setCrosshairPoint(point);
|
|
3679
|
+
emitCrosshairMove(point.x, point.y, "plot");
|
|
3680
|
+
}
|
|
3622
3681
|
};
|
|
3623
3682
|
const onPointerMove = (event) => {
|
|
3683
|
+
if (event.pointerType === "touch" || event.pointerType === "pen") {
|
|
3684
|
+
event.preventDefault();
|
|
3685
|
+
}
|
|
3624
3686
|
const point = getCanvasPoint(event);
|
|
3625
3687
|
if (event.pointerType === "touch" && touchPointers.has(event.pointerId)) {
|
|
3626
3688
|
touchPointers.set(event.pointerId, point);
|
|
@@ -3643,6 +3705,16 @@ function createChart(element, options = {}) {
|
|
|
3643
3705
|
pointerDownInfo.moved = true;
|
|
3644
3706
|
}
|
|
3645
3707
|
}
|
|
3708
|
+
if (pointerDownInfo?.crosshairDrag && pointerDownInfo.pointerId === event.pointerId) {
|
|
3709
|
+
if (getHitRegion(point.x, point.y) === "plot") {
|
|
3710
|
+
canvas.style.cursor = "crosshair";
|
|
3711
|
+
setCrosshairPoint(point);
|
|
3712
|
+
emitCrosshairMove(point.x, point.y, "plot");
|
|
3713
|
+
lastPointerX = point.x;
|
|
3714
|
+
lastPointerY = point.y;
|
|
3715
|
+
}
|
|
3716
|
+
return;
|
|
3717
|
+
}
|
|
3646
3718
|
if (drawingDragState) {
|
|
3647
3719
|
if (activePointerId !== null && event.pointerId !== activePointerId) {
|
|
3648
3720
|
return;
|
|
@@ -3856,7 +3928,13 @@ function createChart(element, options = {}) {
|
|
|
3856
3928
|
activePointerId = null;
|
|
3857
3929
|
canvas.style.cursor = "default";
|
|
3858
3930
|
if (event && pointerDownInfo && event.pointerId === pointerDownInfo.pointerId) {
|
|
3859
|
-
if (
|
|
3931
|
+
if (pointerDownInfo.crosshairDrag) {
|
|
3932
|
+
const point = getCanvasPoint(event);
|
|
3933
|
+
if (getHitRegion(point.x, point.y) === "plot") {
|
|
3934
|
+
setCrosshairPoint(point);
|
|
3935
|
+
emitCrosshairMove(point.x, point.y, "plot");
|
|
3936
|
+
}
|
|
3937
|
+
} else if (!pointerDownInfo.moved) {
|
|
3860
3938
|
const clickPrice = pointerDownInfo.region === "plot" ? roundToPricePrecision(priceFromCanvasY(pointerDownInfo.y)) : void 0;
|
|
3861
3939
|
chartClickHandler?.({
|
|
3862
3940
|
x: pointerDownInfo.x,
|
|
@@ -3903,6 +3981,7 @@ function createChart(element, options = {}) {
|
|
|
3903
3981
|
zoomX(factor, point.x);
|
|
3904
3982
|
};
|
|
3905
3983
|
const onDoubleClick = (event) => {
|
|
3984
|
+
event.preventDefault();
|
|
3906
3985
|
if (!doubleClickEnabled) {
|
|
3907
3986
|
return;
|
|
3908
3987
|
}
|
|
@@ -3928,6 +4007,9 @@ function createChart(element, options = {}) {
|
|
|
3928
4007
|
}
|
|
3929
4008
|
resetViewport();
|
|
3930
4009
|
};
|
|
4010
|
+
const onContextMenu = (event) => {
|
|
4011
|
+
event.preventDefault();
|
|
4012
|
+
};
|
|
3931
4013
|
canvas.addEventListener("pointerdown", onPointerDown);
|
|
3932
4014
|
canvas.addEventListener("pointermove", onPointerMove);
|
|
3933
4015
|
canvas.addEventListener("pointerup", endPointerDrag);
|
|
@@ -3935,6 +4017,7 @@ function createChart(element, options = {}) {
|
|
|
3935
4017
|
canvas.addEventListener("pointerleave", endPointerDrag);
|
|
3936
4018
|
canvas.addEventListener("wheel", onWheel, { passive: false });
|
|
3937
4019
|
canvas.addEventListener("dblclick", onDoubleClick);
|
|
4020
|
+
canvas.addEventListener("contextmenu", onContextMenu);
|
|
3938
4021
|
const updateOptions = (nextOptions) => {
|
|
3939
4022
|
const wasTickerSmoothingEnabled = mergedOptions.tickerLine?.smoothing ?? false;
|
|
3940
4023
|
const previousWidth = width;
|
|
@@ -3943,6 +4026,7 @@ function createChart(element, options = {}) {
|
|
|
3943
4026
|
width = nextOptions.width !== void 0 && nextOptions.width > 0 ? mergedOptions.width : previousWidth;
|
|
3944
4027
|
height = nextOptions.height !== void 0 && nextOptions.height > 0 ? mergedOptions.height : previousHeight;
|
|
3945
4028
|
mergedOptions = { ...mergedOptions, width, height };
|
|
4029
|
+
resetRightMarginCache();
|
|
3946
4030
|
doubleClickEnabled = mergedOptions.doubleClickEnabled;
|
|
3947
4031
|
doubleClickAction = mergedOptions.doubleClickAction;
|
|
3948
4032
|
const isTickerSmoothingEnabled = mergedOptions.tickerLine?.smoothing ?? false;
|
|
@@ -3969,6 +4053,7 @@ function createChart(element, options = {}) {
|
|
|
3969
4053
|
height = nextHeight;
|
|
3970
4054
|
}
|
|
3971
4055
|
mergedOptions = { ...mergedOptions, width, height };
|
|
4056
|
+
resetRightMarginCache();
|
|
3972
4057
|
draw();
|
|
3973
4058
|
};
|
|
3974
4059
|
const setData = (nextData) => {
|
|
@@ -3985,6 +4070,7 @@ function createChart(element, options = {}) {
|
|
|
3985
4070
|
tickerPriceTarget = null;
|
|
3986
4071
|
smoothedTickerVolume = null;
|
|
3987
4072
|
tickerVolumeTarget = null;
|
|
4073
|
+
resetRightMarginCache();
|
|
3988
4074
|
resetYViewport();
|
|
3989
4075
|
draw();
|
|
3990
4076
|
return;
|
|
@@ -4018,6 +4104,7 @@ function createChart(element, options = {}) {
|
|
|
4018
4104
|
...line,
|
|
4019
4105
|
id: line.id ?? `line-${index + 1}`
|
|
4020
4106
|
}));
|
|
4107
|
+
resetRightMarginCache();
|
|
4021
4108
|
draw();
|
|
4022
4109
|
};
|
|
4023
4110
|
const addPriceLine = (line) => {
|
|
@@ -4028,6 +4115,7 @@ function createChart(element, options = {}) {
|
|
|
4028
4115
|
};
|
|
4029
4116
|
const removePriceLine = (id) => {
|
|
4030
4117
|
priceLines = priceLines.filter((line) => line.id !== id);
|
|
4118
|
+
resetRightMarginCache();
|
|
4031
4119
|
draw();
|
|
4032
4120
|
};
|
|
4033
4121
|
const setOrderLines = (lines) => {
|
|
@@ -4035,6 +4123,7 @@ function createChart(element, options = {}) {
|
|
|
4035
4123
|
...line,
|
|
4036
4124
|
id: line.id ?? `order-${index + 1}`
|
|
4037
4125
|
}));
|
|
4126
|
+
resetRightMarginCache();
|
|
4038
4127
|
const activeIds = new Set(orderLines.map((line) => line.id));
|
|
4039
4128
|
for (const id of Array.from(orderWidgetWidthById.keys())) {
|
|
4040
4129
|
if (!activeIds.has(id)) {
|
|
@@ -4062,6 +4151,7 @@ function createChart(element, options = {}) {
|
|
|
4062
4151
|
orderLines = orderLines.filter((line) => line.id !== id);
|
|
4063
4152
|
orderWidgetWidthById.delete(id);
|
|
4064
4153
|
orderPriceTagWidthById.delete(id);
|
|
4154
|
+
resetRightMarginCache();
|
|
4065
4155
|
draw();
|
|
4066
4156
|
};
|
|
4067
4157
|
const onOrderAction = (handler) => {
|
|
@@ -4225,6 +4315,7 @@ function createChart(element, options = {}) {
|
|
|
4225
4315
|
canvas.removeEventListener("pointerleave", endPointerDrag);
|
|
4226
4316
|
canvas.removeEventListener("wheel", onWheel);
|
|
4227
4317
|
canvas.removeEventListener("dblclick", onDoubleClick);
|
|
4318
|
+
canvas.removeEventListener("contextmenu", onContextMenu);
|
|
4228
4319
|
element.innerHTML = "";
|
|
4229
4320
|
};
|
|
4230
4321
|
draw();
|
|
@@ -1041,9 +1041,14 @@ function createChart(element, options = {}) {
|
|
|
1041
1041
|
}
|
|
1042
1042
|
canvas.style.display = "block";
|
|
1043
1043
|
canvas.style.touchAction = "none";
|
|
1044
|
+
canvas.style.userSelect = "none";
|
|
1045
|
+
canvas.style.setProperty("-webkit-user-select", "none");
|
|
1046
|
+
canvas.style.setProperty("-webkit-touch-callout", "none");
|
|
1047
|
+
canvas.setAttribute("draggable", "false");
|
|
1044
1048
|
element.innerHTML = "";
|
|
1045
1049
|
element.appendChild(canvas);
|
|
1046
1050
|
const margin = { top: 16, right: 72, bottom: 34, left: 12 };
|
|
1051
|
+
let cachedRightMargin = margin.right;
|
|
1047
1052
|
const minVisibleBars = Math.max(1, Math.floor(mergedOptions.minVisibleBars));
|
|
1048
1053
|
const maxVisibleBars = Math.max(minVisibleBars, Math.floor(mergedOptions.maxVisibleBars));
|
|
1049
1054
|
const maxPanBars = Math.max(0, Math.floor(mergedOptions.maxPanBars));
|
|
@@ -1265,14 +1270,34 @@ function createChart(element, options = {}) {
|
|
|
1265
1270
|
const decimalPart = decimals > 0 ? `.${"8".repeat(decimals)}` : "";
|
|
1266
1271
|
return `${integerPart}${decimalPart}`;
|
|
1267
1272
|
};
|
|
1273
|
+
const getMeasuredLabelWidth = (text, paddingX) => {
|
|
1274
|
+
return Math.ceil(ctx.measureText(text).width) + paddingX * 2;
|
|
1275
|
+
};
|
|
1276
|
+
const getStabilizedNumericLabelWidth = (text, paddingX) => {
|
|
1277
|
+
const measured = getMeasuredLabelWidth(text, paddingX);
|
|
1278
|
+
if (!mergedOptions.stabilizePriceLabels || !/\d/.test(text)) {
|
|
1279
|
+
return measured;
|
|
1280
|
+
}
|
|
1281
|
+
let stableWidth = measured;
|
|
1282
|
+
for (const digit of ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]) {
|
|
1283
|
+
stableWidth = Math.max(stableWidth, getMeasuredLabelWidth(text.replace(/\d/g, digit), paddingX));
|
|
1284
|
+
}
|
|
1285
|
+
return stableWidth;
|
|
1286
|
+
};
|
|
1268
1287
|
const getPriceLabelWidth = (priceText, paddingX) => {
|
|
1269
|
-
const measured =
|
|
1288
|
+
const measured = getStabilizedNumericLabelWidth(priceText, paddingX);
|
|
1270
1289
|
if (!mergedOptions.stabilizePriceLabels) {
|
|
1271
1290
|
return measured;
|
|
1272
1291
|
}
|
|
1273
|
-
const templateWidth =
|
|
1292
|
+
const templateWidth = getStabilizedNumericLabelWidth(getStabilizedPriceTemplate(), paddingX);
|
|
1274
1293
|
return Math.max(measured, templateWidth);
|
|
1275
1294
|
};
|
|
1295
|
+
const getStableLabelWidth = (text, paddingX) => {
|
|
1296
|
+
return getStabilizedNumericLabelWidth(text, paddingX);
|
|
1297
|
+
};
|
|
1298
|
+
const resetRightMarginCache = () => {
|
|
1299
|
+
cachedRightMargin = margin.right;
|
|
1300
|
+
};
|
|
1276
1301
|
const parseData = (nextData) => {
|
|
1277
1302
|
const dedupedByTime = /* @__PURE__ */ new Map();
|
|
1278
1303
|
for (const point of nextData) {
|
|
@@ -1798,22 +1823,33 @@ function createChart(element, options = {}) {
|
|
|
1798
1823
|
const labels = { ...DEFAULT_LABELS_OPTIONS, ...mergedOptions.labels ?? {} };
|
|
1799
1824
|
const estimateRightMargin = () => {
|
|
1800
1825
|
const paddingX = Math.max(4, labels.labelPaddingX);
|
|
1801
|
-
const measure = (text) => Math.ceil(ctx.measureText(text).width) + paddingX * 2;
|
|
1802
1826
|
let required = margin.right - 1;
|
|
1827
|
+
const includeWidth = (contentWidth) => {
|
|
1828
|
+
if (Number.isFinite(contentWidth)) {
|
|
1829
|
+
required = Math.max(required, contentWidth);
|
|
1830
|
+
}
|
|
1831
|
+
};
|
|
1803
1832
|
const include = (text) => {
|
|
1804
1833
|
const normalized = text?.trim();
|
|
1805
1834
|
if (normalized) {
|
|
1806
|
-
|
|
1835
|
+
includeWidth(getStableLabelWidth(normalized, paddingX));
|
|
1836
|
+
}
|
|
1837
|
+
};
|
|
1838
|
+
const includePrice = (price) => {
|
|
1839
|
+
if (Number.isFinite(price)) {
|
|
1840
|
+
includeWidth(getPriceLabelWidth(formatPrice(price), paddingX));
|
|
1807
1841
|
}
|
|
1808
1842
|
};
|
|
1809
1843
|
const ticker2 = mergedOptions.tickerLine ?? DEFAULT_OPTIONS.tickerLine;
|
|
1810
1844
|
const lastPoint2 = data[data.length - 1];
|
|
1811
1845
|
if ((ticker2.visible ?? true) && labels.showLastPrice && lastPoint2) {
|
|
1812
|
-
|
|
1846
|
+
const tickerPrice2 = ticker2.smoothing && smoothedTickerPrice !== null ? smoothedTickerPrice : lastPoint2.c;
|
|
1847
|
+
includePrice(tickerPrice2);
|
|
1813
1848
|
if (ticker2.labelSubtext) include(String(ticker2.labelSubtext));
|
|
1814
1849
|
for (const subtext of ticker2.labelSubtexts ?? []) {
|
|
1815
1850
|
include(String(subtext));
|
|
1816
1851
|
}
|
|
1852
|
+
if (ticker2.showCountdownInLabel) include("88:88");
|
|
1817
1853
|
}
|
|
1818
1854
|
if (labels.showSymbolName) {
|
|
1819
1855
|
include(labels.symbolName);
|
|
@@ -1835,18 +1871,24 @@ function createChart(element, options = {}) {
|
|
|
1835
1871
|
for (const line of priceLines) {
|
|
1836
1872
|
const mergedLine = { ...DEFAULT_PRICE_LINE_OPTIONS, ...line };
|
|
1837
1873
|
if (mergedLine.visible && Number.isFinite(mergedLine.price)) {
|
|
1838
|
-
|
|
1874
|
+
if (mergedLine.label) {
|
|
1875
|
+
include(mergedLine.label);
|
|
1876
|
+
} else {
|
|
1877
|
+
includePrice(mergedLine.price);
|
|
1878
|
+
}
|
|
1839
1879
|
}
|
|
1840
1880
|
}
|
|
1841
1881
|
for (const line of orderLines) {
|
|
1842
1882
|
const mergedLine = { ...DEFAULT_ORDER_LINE_OPTIONS, ...line };
|
|
1843
1883
|
const renderPrice = mergedLine.behavior === "follow" && Number.isFinite(mergedLine.followPrice) ? mergedLine.followPrice : mergedLine.price;
|
|
1844
1884
|
if (mergedLine.visible && Number.isFinite(renderPrice)) {
|
|
1845
|
-
|
|
1885
|
+
includePrice(renderPrice);
|
|
1846
1886
|
}
|
|
1847
1887
|
}
|
|
1848
1888
|
const maxRightMargin = Math.max(margin.right, width - margin.left - 160);
|
|
1849
|
-
|
|
1889
|
+
const nextRightMargin = Math.min(maxRightMargin, Math.max(margin.right, Math.ceil(required + 1)));
|
|
1890
|
+
cachedRightMargin = Math.max(cachedRightMargin, nextRightMargin);
|
|
1891
|
+
return Math.min(maxRightMargin, cachedRightMargin);
|
|
1850
1892
|
};
|
|
1851
1893
|
const rightMargin = estimateRightMargin();
|
|
1852
1894
|
const chartLeft = margin.left;
|
|
@@ -3493,6 +3535,9 @@ function createChart(element, options = {}) {
|
|
|
3493
3535
|
draw();
|
|
3494
3536
|
};
|
|
3495
3537
|
const onPointerDown = (event) => {
|
|
3538
|
+
if (event.pointerType === "touch" || event.pointerType === "pen") {
|
|
3539
|
+
event.preventDefault();
|
|
3540
|
+
}
|
|
3496
3541
|
const point = getCanvasPoint(event);
|
|
3497
3542
|
if (event.pointerType === "touch") {
|
|
3498
3543
|
touchPointers.set(event.pointerId, point);
|
|
@@ -3591,12 +3636,29 @@ function createChart(element, options = {}) {
|
|
|
3591
3636
|
isDragging = true;
|
|
3592
3637
|
dragMode = region;
|
|
3593
3638
|
activePointerId = event.pointerId;
|
|
3594
|
-
|
|
3639
|
+
const crosshairDrag = (event.pointerType === "touch" || event.pointerType === "pen") && region === "plot";
|
|
3640
|
+
pointerDownInfo = {
|
|
3641
|
+
pointerId: event.pointerId,
|
|
3642
|
+
pointerType: event.pointerType,
|
|
3643
|
+
x: point.x,
|
|
3644
|
+
y: point.y,
|
|
3645
|
+
region,
|
|
3646
|
+
moved: false,
|
|
3647
|
+
crosshairDrag
|
|
3648
|
+
};
|
|
3595
3649
|
lastPointerX = point.x;
|
|
3596
3650
|
lastPointerY = point.y;
|
|
3597
3651
|
canvas.setPointerCapture(event.pointerId);
|
|
3652
|
+
if (crosshairDrag) {
|
|
3653
|
+
canvas.style.cursor = "crosshair";
|
|
3654
|
+
setCrosshairPoint(point);
|
|
3655
|
+
emitCrosshairMove(point.x, point.y, "plot");
|
|
3656
|
+
}
|
|
3598
3657
|
};
|
|
3599
3658
|
const onPointerMove = (event) => {
|
|
3659
|
+
if (event.pointerType === "touch" || event.pointerType === "pen") {
|
|
3660
|
+
event.preventDefault();
|
|
3661
|
+
}
|
|
3600
3662
|
const point = getCanvasPoint(event);
|
|
3601
3663
|
if (event.pointerType === "touch" && touchPointers.has(event.pointerId)) {
|
|
3602
3664
|
touchPointers.set(event.pointerId, point);
|
|
@@ -3619,6 +3681,16 @@ function createChart(element, options = {}) {
|
|
|
3619
3681
|
pointerDownInfo.moved = true;
|
|
3620
3682
|
}
|
|
3621
3683
|
}
|
|
3684
|
+
if (pointerDownInfo?.crosshairDrag && pointerDownInfo.pointerId === event.pointerId) {
|
|
3685
|
+
if (getHitRegion(point.x, point.y) === "plot") {
|
|
3686
|
+
canvas.style.cursor = "crosshair";
|
|
3687
|
+
setCrosshairPoint(point);
|
|
3688
|
+
emitCrosshairMove(point.x, point.y, "plot");
|
|
3689
|
+
lastPointerX = point.x;
|
|
3690
|
+
lastPointerY = point.y;
|
|
3691
|
+
}
|
|
3692
|
+
return;
|
|
3693
|
+
}
|
|
3622
3694
|
if (drawingDragState) {
|
|
3623
3695
|
if (activePointerId !== null && event.pointerId !== activePointerId) {
|
|
3624
3696
|
return;
|
|
@@ -3832,7 +3904,13 @@ function createChart(element, options = {}) {
|
|
|
3832
3904
|
activePointerId = null;
|
|
3833
3905
|
canvas.style.cursor = "default";
|
|
3834
3906
|
if (event && pointerDownInfo && event.pointerId === pointerDownInfo.pointerId) {
|
|
3835
|
-
if (
|
|
3907
|
+
if (pointerDownInfo.crosshairDrag) {
|
|
3908
|
+
const point = getCanvasPoint(event);
|
|
3909
|
+
if (getHitRegion(point.x, point.y) === "plot") {
|
|
3910
|
+
setCrosshairPoint(point);
|
|
3911
|
+
emitCrosshairMove(point.x, point.y, "plot");
|
|
3912
|
+
}
|
|
3913
|
+
} else if (!pointerDownInfo.moved) {
|
|
3836
3914
|
const clickPrice = pointerDownInfo.region === "plot" ? roundToPricePrecision(priceFromCanvasY(pointerDownInfo.y)) : void 0;
|
|
3837
3915
|
chartClickHandler?.({
|
|
3838
3916
|
x: pointerDownInfo.x,
|
|
@@ -3879,6 +3957,7 @@ function createChart(element, options = {}) {
|
|
|
3879
3957
|
zoomX(factor, point.x);
|
|
3880
3958
|
};
|
|
3881
3959
|
const onDoubleClick = (event) => {
|
|
3960
|
+
event.preventDefault();
|
|
3882
3961
|
if (!doubleClickEnabled) {
|
|
3883
3962
|
return;
|
|
3884
3963
|
}
|
|
@@ -3904,6 +3983,9 @@ function createChart(element, options = {}) {
|
|
|
3904
3983
|
}
|
|
3905
3984
|
resetViewport();
|
|
3906
3985
|
};
|
|
3986
|
+
const onContextMenu = (event) => {
|
|
3987
|
+
event.preventDefault();
|
|
3988
|
+
};
|
|
3907
3989
|
canvas.addEventListener("pointerdown", onPointerDown);
|
|
3908
3990
|
canvas.addEventListener("pointermove", onPointerMove);
|
|
3909
3991
|
canvas.addEventListener("pointerup", endPointerDrag);
|
|
@@ -3911,6 +3993,7 @@ function createChart(element, options = {}) {
|
|
|
3911
3993
|
canvas.addEventListener("pointerleave", endPointerDrag);
|
|
3912
3994
|
canvas.addEventListener("wheel", onWheel, { passive: false });
|
|
3913
3995
|
canvas.addEventListener("dblclick", onDoubleClick);
|
|
3996
|
+
canvas.addEventListener("contextmenu", onContextMenu);
|
|
3914
3997
|
const updateOptions = (nextOptions) => {
|
|
3915
3998
|
const wasTickerSmoothingEnabled = mergedOptions.tickerLine?.smoothing ?? false;
|
|
3916
3999
|
const previousWidth = width;
|
|
@@ -3919,6 +4002,7 @@ function createChart(element, options = {}) {
|
|
|
3919
4002
|
width = nextOptions.width !== void 0 && nextOptions.width > 0 ? mergedOptions.width : previousWidth;
|
|
3920
4003
|
height = nextOptions.height !== void 0 && nextOptions.height > 0 ? mergedOptions.height : previousHeight;
|
|
3921
4004
|
mergedOptions = { ...mergedOptions, width, height };
|
|
4005
|
+
resetRightMarginCache();
|
|
3922
4006
|
doubleClickEnabled = mergedOptions.doubleClickEnabled;
|
|
3923
4007
|
doubleClickAction = mergedOptions.doubleClickAction;
|
|
3924
4008
|
const isTickerSmoothingEnabled = mergedOptions.tickerLine?.smoothing ?? false;
|
|
@@ -3945,6 +4029,7 @@ function createChart(element, options = {}) {
|
|
|
3945
4029
|
height = nextHeight;
|
|
3946
4030
|
}
|
|
3947
4031
|
mergedOptions = { ...mergedOptions, width, height };
|
|
4032
|
+
resetRightMarginCache();
|
|
3948
4033
|
draw();
|
|
3949
4034
|
};
|
|
3950
4035
|
const setData = (nextData) => {
|
|
@@ -3961,6 +4046,7 @@ function createChart(element, options = {}) {
|
|
|
3961
4046
|
tickerPriceTarget = null;
|
|
3962
4047
|
smoothedTickerVolume = null;
|
|
3963
4048
|
tickerVolumeTarget = null;
|
|
4049
|
+
resetRightMarginCache();
|
|
3964
4050
|
resetYViewport();
|
|
3965
4051
|
draw();
|
|
3966
4052
|
return;
|
|
@@ -3994,6 +4080,7 @@ function createChart(element, options = {}) {
|
|
|
3994
4080
|
...line,
|
|
3995
4081
|
id: line.id ?? `line-${index + 1}`
|
|
3996
4082
|
}));
|
|
4083
|
+
resetRightMarginCache();
|
|
3997
4084
|
draw();
|
|
3998
4085
|
};
|
|
3999
4086
|
const addPriceLine = (line) => {
|
|
@@ -4004,6 +4091,7 @@ function createChart(element, options = {}) {
|
|
|
4004
4091
|
};
|
|
4005
4092
|
const removePriceLine = (id) => {
|
|
4006
4093
|
priceLines = priceLines.filter((line) => line.id !== id);
|
|
4094
|
+
resetRightMarginCache();
|
|
4007
4095
|
draw();
|
|
4008
4096
|
};
|
|
4009
4097
|
const setOrderLines = (lines) => {
|
|
@@ -4011,6 +4099,7 @@ function createChart(element, options = {}) {
|
|
|
4011
4099
|
...line,
|
|
4012
4100
|
id: line.id ?? `order-${index + 1}`
|
|
4013
4101
|
}));
|
|
4102
|
+
resetRightMarginCache();
|
|
4014
4103
|
const activeIds = new Set(orderLines.map((line) => line.id));
|
|
4015
4104
|
for (const id of Array.from(orderWidgetWidthById.keys())) {
|
|
4016
4105
|
if (!activeIds.has(id)) {
|
|
@@ -4038,6 +4127,7 @@ function createChart(element, options = {}) {
|
|
|
4038
4127
|
orderLines = orderLines.filter((line) => line.id !== id);
|
|
4039
4128
|
orderWidgetWidthById.delete(id);
|
|
4040
4129
|
orderPriceTagWidthById.delete(id);
|
|
4130
|
+
resetRightMarginCache();
|
|
4041
4131
|
draw();
|
|
4042
4132
|
};
|
|
4043
4133
|
const onOrderAction = (handler) => {
|
|
@@ -4201,6 +4291,7 @@ function createChart(element, options = {}) {
|
|
|
4201
4291
|
canvas.removeEventListener("pointerleave", endPointerDrag);
|
|
4202
4292
|
canvas.removeEventListener("wheel", onWheel);
|
|
4203
4293
|
canvas.removeEventListener("dblclick", onDoubleClick);
|
|
4294
|
+
canvas.removeEventListener("contextmenu", onContextMenu);
|
|
4204
4295
|
element.innerHTML = "";
|
|
4205
4296
|
};
|
|
4206
4297
|
draw();
|
package/dist/index.cjs
CHANGED
|
@@ -1065,9 +1065,14 @@ function createChart(element, options = {}) {
|
|
|
1065
1065
|
}
|
|
1066
1066
|
canvas.style.display = "block";
|
|
1067
1067
|
canvas.style.touchAction = "none";
|
|
1068
|
+
canvas.style.userSelect = "none";
|
|
1069
|
+
canvas.style.setProperty("-webkit-user-select", "none");
|
|
1070
|
+
canvas.style.setProperty("-webkit-touch-callout", "none");
|
|
1071
|
+
canvas.setAttribute("draggable", "false");
|
|
1068
1072
|
element.innerHTML = "";
|
|
1069
1073
|
element.appendChild(canvas);
|
|
1070
1074
|
const margin = { top: 16, right: 72, bottom: 34, left: 12 };
|
|
1075
|
+
let cachedRightMargin = margin.right;
|
|
1071
1076
|
const minVisibleBars = Math.max(1, Math.floor(mergedOptions.minVisibleBars));
|
|
1072
1077
|
const maxVisibleBars = Math.max(minVisibleBars, Math.floor(mergedOptions.maxVisibleBars));
|
|
1073
1078
|
const maxPanBars = Math.max(0, Math.floor(mergedOptions.maxPanBars));
|
|
@@ -1289,14 +1294,34 @@ function createChart(element, options = {}) {
|
|
|
1289
1294
|
const decimalPart = decimals > 0 ? `.${"8".repeat(decimals)}` : "";
|
|
1290
1295
|
return `${integerPart}${decimalPart}`;
|
|
1291
1296
|
};
|
|
1297
|
+
const getMeasuredLabelWidth = (text, paddingX) => {
|
|
1298
|
+
return Math.ceil(ctx.measureText(text).width) + paddingX * 2;
|
|
1299
|
+
};
|
|
1300
|
+
const getStabilizedNumericLabelWidth = (text, paddingX) => {
|
|
1301
|
+
const measured = getMeasuredLabelWidth(text, paddingX);
|
|
1302
|
+
if (!mergedOptions.stabilizePriceLabels || !/\d/.test(text)) {
|
|
1303
|
+
return measured;
|
|
1304
|
+
}
|
|
1305
|
+
let stableWidth = measured;
|
|
1306
|
+
for (const digit of ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]) {
|
|
1307
|
+
stableWidth = Math.max(stableWidth, getMeasuredLabelWidth(text.replace(/\d/g, digit), paddingX));
|
|
1308
|
+
}
|
|
1309
|
+
return stableWidth;
|
|
1310
|
+
};
|
|
1292
1311
|
const getPriceLabelWidth = (priceText, paddingX) => {
|
|
1293
|
-
const measured =
|
|
1312
|
+
const measured = getStabilizedNumericLabelWidth(priceText, paddingX);
|
|
1294
1313
|
if (!mergedOptions.stabilizePriceLabels) {
|
|
1295
1314
|
return measured;
|
|
1296
1315
|
}
|
|
1297
|
-
const templateWidth =
|
|
1316
|
+
const templateWidth = getStabilizedNumericLabelWidth(getStabilizedPriceTemplate(), paddingX);
|
|
1298
1317
|
return Math.max(measured, templateWidth);
|
|
1299
1318
|
};
|
|
1319
|
+
const getStableLabelWidth = (text, paddingX) => {
|
|
1320
|
+
return getStabilizedNumericLabelWidth(text, paddingX);
|
|
1321
|
+
};
|
|
1322
|
+
const resetRightMarginCache = () => {
|
|
1323
|
+
cachedRightMargin = margin.right;
|
|
1324
|
+
};
|
|
1300
1325
|
const parseData = (nextData) => {
|
|
1301
1326
|
const dedupedByTime = /* @__PURE__ */ new Map();
|
|
1302
1327
|
for (const point of nextData) {
|
|
@@ -1822,22 +1847,33 @@ function createChart(element, options = {}) {
|
|
|
1822
1847
|
const labels = { ...DEFAULT_LABELS_OPTIONS, ...mergedOptions.labels ?? {} };
|
|
1823
1848
|
const estimateRightMargin = () => {
|
|
1824
1849
|
const paddingX = Math.max(4, labels.labelPaddingX);
|
|
1825
|
-
const measure = (text) => Math.ceil(ctx.measureText(text).width) + paddingX * 2;
|
|
1826
1850
|
let required = margin.right - 1;
|
|
1851
|
+
const includeWidth = (contentWidth) => {
|
|
1852
|
+
if (Number.isFinite(contentWidth)) {
|
|
1853
|
+
required = Math.max(required, contentWidth);
|
|
1854
|
+
}
|
|
1855
|
+
};
|
|
1827
1856
|
const include = (text) => {
|
|
1828
1857
|
const normalized = text?.trim();
|
|
1829
1858
|
if (normalized) {
|
|
1830
|
-
|
|
1859
|
+
includeWidth(getStableLabelWidth(normalized, paddingX));
|
|
1860
|
+
}
|
|
1861
|
+
};
|
|
1862
|
+
const includePrice = (price) => {
|
|
1863
|
+
if (Number.isFinite(price)) {
|
|
1864
|
+
includeWidth(getPriceLabelWidth(formatPrice(price), paddingX));
|
|
1831
1865
|
}
|
|
1832
1866
|
};
|
|
1833
1867
|
const ticker2 = mergedOptions.tickerLine ?? DEFAULT_OPTIONS.tickerLine;
|
|
1834
1868
|
const lastPoint2 = data[data.length - 1];
|
|
1835
1869
|
if ((ticker2.visible ?? true) && labels.showLastPrice && lastPoint2) {
|
|
1836
|
-
|
|
1870
|
+
const tickerPrice2 = ticker2.smoothing && smoothedTickerPrice !== null ? smoothedTickerPrice : lastPoint2.c;
|
|
1871
|
+
includePrice(tickerPrice2);
|
|
1837
1872
|
if (ticker2.labelSubtext) include(String(ticker2.labelSubtext));
|
|
1838
1873
|
for (const subtext of ticker2.labelSubtexts ?? []) {
|
|
1839
1874
|
include(String(subtext));
|
|
1840
1875
|
}
|
|
1876
|
+
if (ticker2.showCountdownInLabel) include("88:88");
|
|
1841
1877
|
}
|
|
1842
1878
|
if (labels.showSymbolName) {
|
|
1843
1879
|
include(labels.symbolName);
|
|
@@ -1859,18 +1895,24 @@ function createChart(element, options = {}) {
|
|
|
1859
1895
|
for (const line of priceLines) {
|
|
1860
1896
|
const mergedLine = { ...DEFAULT_PRICE_LINE_OPTIONS, ...line };
|
|
1861
1897
|
if (mergedLine.visible && Number.isFinite(mergedLine.price)) {
|
|
1862
|
-
|
|
1898
|
+
if (mergedLine.label) {
|
|
1899
|
+
include(mergedLine.label);
|
|
1900
|
+
} else {
|
|
1901
|
+
includePrice(mergedLine.price);
|
|
1902
|
+
}
|
|
1863
1903
|
}
|
|
1864
1904
|
}
|
|
1865
1905
|
for (const line of orderLines) {
|
|
1866
1906
|
const mergedLine = { ...DEFAULT_ORDER_LINE_OPTIONS, ...line };
|
|
1867
1907
|
const renderPrice = mergedLine.behavior === "follow" && Number.isFinite(mergedLine.followPrice) ? mergedLine.followPrice : mergedLine.price;
|
|
1868
1908
|
if (mergedLine.visible && Number.isFinite(renderPrice)) {
|
|
1869
|
-
|
|
1909
|
+
includePrice(renderPrice);
|
|
1870
1910
|
}
|
|
1871
1911
|
}
|
|
1872
1912
|
const maxRightMargin = Math.max(margin.right, width - margin.left - 160);
|
|
1873
|
-
|
|
1913
|
+
const nextRightMargin = Math.min(maxRightMargin, Math.max(margin.right, Math.ceil(required + 1)));
|
|
1914
|
+
cachedRightMargin = Math.max(cachedRightMargin, nextRightMargin);
|
|
1915
|
+
return Math.min(maxRightMargin, cachedRightMargin);
|
|
1874
1916
|
};
|
|
1875
1917
|
const rightMargin = estimateRightMargin();
|
|
1876
1918
|
const chartLeft = margin.left;
|
|
@@ -3517,6 +3559,9 @@ function createChart(element, options = {}) {
|
|
|
3517
3559
|
draw();
|
|
3518
3560
|
};
|
|
3519
3561
|
const onPointerDown = (event) => {
|
|
3562
|
+
if (event.pointerType === "touch" || event.pointerType === "pen") {
|
|
3563
|
+
event.preventDefault();
|
|
3564
|
+
}
|
|
3520
3565
|
const point = getCanvasPoint(event);
|
|
3521
3566
|
if (event.pointerType === "touch") {
|
|
3522
3567
|
touchPointers.set(event.pointerId, point);
|
|
@@ -3615,12 +3660,29 @@ function createChart(element, options = {}) {
|
|
|
3615
3660
|
isDragging = true;
|
|
3616
3661
|
dragMode = region;
|
|
3617
3662
|
activePointerId = event.pointerId;
|
|
3618
|
-
|
|
3663
|
+
const crosshairDrag = (event.pointerType === "touch" || event.pointerType === "pen") && region === "plot";
|
|
3664
|
+
pointerDownInfo = {
|
|
3665
|
+
pointerId: event.pointerId,
|
|
3666
|
+
pointerType: event.pointerType,
|
|
3667
|
+
x: point.x,
|
|
3668
|
+
y: point.y,
|
|
3669
|
+
region,
|
|
3670
|
+
moved: false,
|
|
3671
|
+
crosshairDrag
|
|
3672
|
+
};
|
|
3619
3673
|
lastPointerX = point.x;
|
|
3620
3674
|
lastPointerY = point.y;
|
|
3621
3675
|
canvas.setPointerCapture(event.pointerId);
|
|
3676
|
+
if (crosshairDrag) {
|
|
3677
|
+
canvas.style.cursor = "crosshair";
|
|
3678
|
+
setCrosshairPoint(point);
|
|
3679
|
+
emitCrosshairMove(point.x, point.y, "plot");
|
|
3680
|
+
}
|
|
3622
3681
|
};
|
|
3623
3682
|
const onPointerMove = (event) => {
|
|
3683
|
+
if (event.pointerType === "touch" || event.pointerType === "pen") {
|
|
3684
|
+
event.preventDefault();
|
|
3685
|
+
}
|
|
3624
3686
|
const point = getCanvasPoint(event);
|
|
3625
3687
|
if (event.pointerType === "touch" && touchPointers.has(event.pointerId)) {
|
|
3626
3688
|
touchPointers.set(event.pointerId, point);
|
|
@@ -3643,6 +3705,16 @@ function createChart(element, options = {}) {
|
|
|
3643
3705
|
pointerDownInfo.moved = true;
|
|
3644
3706
|
}
|
|
3645
3707
|
}
|
|
3708
|
+
if (pointerDownInfo?.crosshairDrag && pointerDownInfo.pointerId === event.pointerId) {
|
|
3709
|
+
if (getHitRegion(point.x, point.y) === "plot") {
|
|
3710
|
+
canvas.style.cursor = "crosshair";
|
|
3711
|
+
setCrosshairPoint(point);
|
|
3712
|
+
emitCrosshairMove(point.x, point.y, "plot");
|
|
3713
|
+
lastPointerX = point.x;
|
|
3714
|
+
lastPointerY = point.y;
|
|
3715
|
+
}
|
|
3716
|
+
return;
|
|
3717
|
+
}
|
|
3646
3718
|
if (drawingDragState) {
|
|
3647
3719
|
if (activePointerId !== null && event.pointerId !== activePointerId) {
|
|
3648
3720
|
return;
|
|
@@ -3856,7 +3928,13 @@ function createChart(element, options = {}) {
|
|
|
3856
3928
|
activePointerId = null;
|
|
3857
3929
|
canvas.style.cursor = "default";
|
|
3858
3930
|
if (event && pointerDownInfo && event.pointerId === pointerDownInfo.pointerId) {
|
|
3859
|
-
if (
|
|
3931
|
+
if (pointerDownInfo.crosshairDrag) {
|
|
3932
|
+
const point = getCanvasPoint(event);
|
|
3933
|
+
if (getHitRegion(point.x, point.y) === "plot") {
|
|
3934
|
+
setCrosshairPoint(point);
|
|
3935
|
+
emitCrosshairMove(point.x, point.y, "plot");
|
|
3936
|
+
}
|
|
3937
|
+
} else if (!pointerDownInfo.moved) {
|
|
3860
3938
|
const clickPrice = pointerDownInfo.region === "plot" ? roundToPricePrecision(priceFromCanvasY(pointerDownInfo.y)) : void 0;
|
|
3861
3939
|
chartClickHandler?.({
|
|
3862
3940
|
x: pointerDownInfo.x,
|
|
@@ -3903,6 +3981,7 @@ function createChart(element, options = {}) {
|
|
|
3903
3981
|
zoomX(factor, point.x);
|
|
3904
3982
|
};
|
|
3905
3983
|
const onDoubleClick = (event) => {
|
|
3984
|
+
event.preventDefault();
|
|
3906
3985
|
if (!doubleClickEnabled) {
|
|
3907
3986
|
return;
|
|
3908
3987
|
}
|
|
@@ -3928,6 +4007,9 @@ function createChart(element, options = {}) {
|
|
|
3928
4007
|
}
|
|
3929
4008
|
resetViewport();
|
|
3930
4009
|
};
|
|
4010
|
+
const onContextMenu = (event) => {
|
|
4011
|
+
event.preventDefault();
|
|
4012
|
+
};
|
|
3931
4013
|
canvas.addEventListener("pointerdown", onPointerDown);
|
|
3932
4014
|
canvas.addEventListener("pointermove", onPointerMove);
|
|
3933
4015
|
canvas.addEventListener("pointerup", endPointerDrag);
|
|
@@ -3935,6 +4017,7 @@ function createChart(element, options = {}) {
|
|
|
3935
4017
|
canvas.addEventListener("pointerleave", endPointerDrag);
|
|
3936
4018
|
canvas.addEventListener("wheel", onWheel, { passive: false });
|
|
3937
4019
|
canvas.addEventListener("dblclick", onDoubleClick);
|
|
4020
|
+
canvas.addEventListener("contextmenu", onContextMenu);
|
|
3938
4021
|
const updateOptions = (nextOptions) => {
|
|
3939
4022
|
const wasTickerSmoothingEnabled = mergedOptions.tickerLine?.smoothing ?? false;
|
|
3940
4023
|
const previousWidth = width;
|
|
@@ -3943,6 +4026,7 @@ function createChart(element, options = {}) {
|
|
|
3943
4026
|
width = nextOptions.width !== void 0 && nextOptions.width > 0 ? mergedOptions.width : previousWidth;
|
|
3944
4027
|
height = nextOptions.height !== void 0 && nextOptions.height > 0 ? mergedOptions.height : previousHeight;
|
|
3945
4028
|
mergedOptions = { ...mergedOptions, width, height };
|
|
4029
|
+
resetRightMarginCache();
|
|
3946
4030
|
doubleClickEnabled = mergedOptions.doubleClickEnabled;
|
|
3947
4031
|
doubleClickAction = mergedOptions.doubleClickAction;
|
|
3948
4032
|
const isTickerSmoothingEnabled = mergedOptions.tickerLine?.smoothing ?? false;
|
|
@@ -3969,6 +4053,7 @@ function createChart(element, options = {}) {
|
|
|
3969
4053
|
height = nextHeight;
|
|
3970
4054
|
}
|
|
3971
4055
|
mergedOptions = { ...mergedOptions, width, height };
|
|
4056
|
+
resetRightMarginCache();
|
|
3972
4057
|
draw();
|
|
3973
4058
|
};
|
|
3974
4059
|
const setData = (nextData) => {
|
|
@@ -3985,6 +4070,7 @@ function createChart(element, options = {}) {
|
|
|
3985
4070
|
tickerPriceTarget = null;
|
|
3986
4071
|
smoothedTickerVolume = null;
|
|
3987
4072
|
tickerVolumeTarget = null;
|
|
4073
|
+
resetRightMarginCache();
|
|
3988
4074
|
resetYViewport();
|
|
3989
4075
|
draw();
|
|
3990
4076
|
return;
|
|
@@ -4018,6 +4104,7 @@ function createChart(element, options = {}) {
|
|
|
4018
4104
|
...line,
|
|
4019
4105
|
id: line.id ?? `line-${index + 1}`
|
|
4020
4106
|
}));
|
|
4107
|
+
resetRightMarginCache();
|
|
4021
4108
|
draw();
|
|
4022
4109
|
};
|
|
4023
4110
|
const addPriceLine = (line) => {
|
|
@@ -4028,6 +4115,7 @@ function createChart(element, options = {}) {
|
|
|
4028
4115
|
};
|
|
4029
4116
|
const removePriceLine = (id) => {
|
|
4030
4117
|
priceLines = priceLines.filter((line) => line.id !== id);
|
|
4118
|
+
resetRightMarginCache();
|
|
4031
4119
|
draw();
|
|
4032
4120
|
};
|
|
4033
4121
|
const setOrderLines = (lines) => {
|
|
@@ -4035,6 +4123,7 @@ function createChart(element, options = {}) {
|
|
|
4035
4123
|
...line,
|
|
4036
4124
|
id: line.id ?? `order-${index + 1}`
|
|
4037
4125
|
}));
|
|
4126
|
+
resetRightMarginCache();
|
|
4038
4127
|
const activeIds = new Set(orderLines.map((line) => line.id));
|
|
4039
4128
|
for (const id of Array.from(orderWidgetWidthById.keys())) {
|
|
4040
4129
|
if (!activeIds.has(id)) {
|
|
@@ -4062,6 +4151,7 @@ function createChart(element, options = {}) {
|
|
|
4062
4151
|
orderLines = orderLines.filter((line) => line.id !== id);
|
|
4063
4152
|
orderWidgetWidthById.delete(id);
|
|
4064
4153
|
orderPriceTagWidthById.delete(id);
|
|
4154
|
+
resetRightMarginCache();
|
|
4065
4155
|
draw();
|
|
4066
4156
|
};
|
|
4067
4157
|
const onOrderAction = (handler) => {
|
|
@@ -4225,6 +4315,7 @@ function createChart(element, options = {}) {
|
|
|
4225
4315
|
canvas.removeEventListener("pointerleave", endPointerDrag);
|
|
4226
4316
|
canvas.removeEventListener("wheel", onWheel);
|
|
4227
4317
|
canvas.removeEventListener("dblclick", onDoubleClick);
|
|
4318
|
+
canvas.removeEventListener("contextmenu", onContextMenu);
|
|
4228
4319
|
element.innerHTML = "";
|
|
4229
4320
|
};
|
|
4230
4321
|
draw();
|
package/dist/index.js
CHANGED
|
@@ -1041,9 +1041,14 @@ function createChart(element, options = {}) {
|
|
|
1041
1041
|
}
|
|
1042
1042
|
canvas.style.display = "block";
|
|
1043
1043
|
canvas.style.touchAction = "none";
|
|
1044
|
+
canvas.style.userSelect = "none";
|
|
1045
|
+
canvas.style.setProperty("-webkit-user-select", "none");
|
|
1046
|
+
canvas.style.setProperty("-webkit-touch-callout", "none");
|
|
1047
|
+
canvas.setAttribute("draggable", "false");
|
|
1044
1048
|
element.innerHTML = "";
|
|
1045
1049
|
element.appendChild(canvas);
|
|
1046
1050
|
const margin = { top: 16, right: 72, bottom: 34, left: 12 };
|
|
1051
|
+
let cachedRightMargin = margin.right;
|
|
1047
1052
|
const minVisibleBars = Math.max(1, Math.floor(mergedOptions.minVisibleBars));
|
|
1048
1053
|
const maxVisibleBars = Math.max(minVisibleBars, Math.floor(mergedOptions.maxVisibleBars));
|
|
1049
1054
|
const maxPanBars = Math.max(0, Math.floor(mergedOptions.maxPanBars));
|
|
@@ -1265,14 +1270,34 @@ function createChart(element, options = {}) {
|
|
|
1265
1270
|
const decimalPart = decimals > 0 ? `.${"8".repeat(decimals)}` : "";
|
|
1266
1271
|
return `${integerPart}${decimalPart}`;
|
|
1267
1272
|
};
|
|
1273
|
+
const getMeasuredLabelWidth = (text, paddingX) => {
|
|
1274
|
+
return Math.ceil(ctx.measureText(text).width) + paddingX * 2;
|
|
1275
|
+
};
|
|
1276
|
+
const getStabilizedNumericLabelWidth = (text, paddingX) => {
|
|
1277
|
+
const measured = getMeasuredLabelWidth(text, paddingX);
|
|
1278
|
+
if (!mergedOptions.stabilizePriceLabels || !/\d/.test(text)) {
|
|
1279
|
+
return measured;
|
|
1280
|
+
}
|
|
1281
|
+
let stableWidth = measured;
|
|
1282
|
+
for (const digit of ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]) {
|
|
1283
|
+
stableWidth = Math.max(stableWidth, getMeasuredLabelWidth(text.replace(/\d/g, digit), paddingX));
|
|
1284
|
+
}
|
|
1285
|
+
return stableWidth;
|
|
1286
|
+
};
|
|
1268
1287
|
const getPriceLabelWidth = (priceText, paddingX) => {
|
|
1269
|
-
const measured =
|
|
1288
|
+
const measured = getStabilizedNumericLabelWidth(priceText, paddingX);
|
|
1270
1289
|
if (!mergedOptions.stabilizePriceLabels) {
|
|
1271
1290
|
return measured;
|
|
1272
1291
|
}
|
|
1273
|
-
const templateWidth =
|
|
1292
|
+
const templateWidth = getStabilizedNumericLabelWidth(getStabilizedPriceTemplate(), paddingX);
|
|
1274
1293
|
return Math.max(measured, templateWidth);
|
|
1275
1294
|
};
|
|
1295
|
+
const getStableLabelWidth = (text, paddingX) => {
|
|
1296
|
+
return getStabilizedNumericLabelWidth(text, paddingX);
|
|
1297
|
+
};
|
|
1298
|
+
const resetRightMarginCache = () => {
|
|
1299
|
+
cachedRightMargin = margin.right;
|
|
1300
|
+
};
|
|
1276
1301
|
const parseData = (nextData) => {
|
|
1277
1302
|
const dedupedByTime = /* @__PURE__ */ new Map();
|
|
1278
1303
|
for (const point of nextData) {
|
|
@@ -1798,22 +1823,33 @@ function createChart(element, options = {}) {
|
|
|
1798
1823
|
const labels = { ...DEFAULT_LABELS_OPTIONS, ...mergedOptions.labels ?? {} };
|
|
1799
1824
|
const estimateRightMargin = () => {
|
|
1800
1825
|
const paddingX = Math.max(4, labels.labelPaddingX);
|
|
1801
|
-
const measure = (text) => Math.ceil(ctx.measureText(text).width) + paddingX * 2;
|
|
1802
1826
|
let required = margin.right - 1;
|
|
1827
|
+
const includeWidth = (contentWidth) => {
|
|
1828
|
+
if (Number.isFinite(contentWidth)) {
|
|
1829
|
+
required = Math.max(required, contentWidth);
|
|
1830
|
+
}
|
|
1831
|
+
};
|
|
1803
1832
|
const include = (text) => {
|
|
1804
1833
|
const normalized = text?.trim();
|
|
1805
1834
|
if (normalized) {
|
|
1806
|
-
|
|
1835
|
+
includeWidth(getStableLabelWidth(normalized, paddingX));
|
|
1836
|
+
}
|
|
1837
|
+
};
|
|
1838
|
+
const includePrice = (price) => {
|
|
1839
|
+
if (Number.isFinite(price)) {
|
|
1840
|
+
includeWidth(getPriceLabelWidth(formatPrice(price), paddingX));
|
|
1807
1841
|
}
|
|
1808
1842
|
};
|
|
1809
1843
|
const ticker2 = mergedOptions.tickerLine ?? DEFAULT_OPTIONS.tickerLine;
|
|
1810
1844
|
const lastPoint2 = data[data.length - 1];
|
|
1811
1845
|
if ((ticker2.visible ?? true) && labels.showLastPrice && lastPoint2) {
|
|
1812
|
-
|
|
1846
|
+
const tickerPrice2 = ticker2.smoothing && smoothedTickerPrice !== null ? smoothedTickerPrice : lastPoint2.c;
|
|
1847
|
+
includePrice(tickerPrice2);
|
|
1813
1848
|
if (ticker2.labelSubtext) include(String(ticker2.labelSubtext));
|
|
1814
1849
|
for (const subtext of ticker2.labelSubtexts ?? []) {
|
|
1815
1850
|
include(String(subtext));
|
|
1816
1851
|
}
|
|
1852
|
+
if (ticker2.showCountdownInLabel) include("88:88");
|
|
1817
1853
|
}
|
|
1818
1854
|
if (labels.showSymbolName) {
|
|
1819
1855
|
include(labels.symbolName);
|
|
@@ -1835,18 +1871,24 @@ function createChart(element, options = {}) {
|
|
|
1835
1871
|
for (const line of priceLines) {
|
|
1836
1872
|
const mergedLine = { ...DEFAULT_PRICE_LINE_OPTIONS, ...line };
|
|
1837
1873
|
if (mergedLine.visible && Number.isFinite(mergedLine.price)) {
|
|
1838
|
-
|
|
1874
|
+
if (mergedLine.label) {
|
|
1875
|
+
include(mergedLine.label);
|
|
1876
|
+
} else {
|
|
1877
|
+
includePrice(mergedLine.price);
|
|
1878
|
+
}
|
|
1839
1879
|
}
|
|
1840
1880
|
}
|
|
1841
1881
|
for (const line of orderLines) {
|
|
1842
1882
|
const mergedLine = { ...DEFAULT_ORDER_LINE_OPTIONS, ...line };
|
|
1843
1883
|
const renderPrice = mergedLine.behavior === "follow" && Number.isFinite(mergedLine.followPrice) ? mergedLine.followPrice : mergedLine.price;
|
|
1844
1884
|
if (mergedLine.visible && Number.isFinite(renderPrice)) {
|
|
1845
|
-
|
|
1885
|
+
includePrice(renderPrice);
|
|
1846
1886
|
}
|
|
1847
1887
|
}
|
|
1848
1888
|
const maxRightMargin = Math.max(margin.right, width - margin.left - 160);
|
|
1849
|
-
|
|
1889
|
+
const nextRightMargin = Math.min(maxRightMargin, Math.max(margin.right, Math.ceil(required + 1)));
|
|
1890
|
+
cachedRightMargin = Math.max(cachedRightMargin, nextRightMargin);
|
|
1891
|
+
return Math.min(maxRightMargin, cachedRightMargin);
|
|
1850
1892
|
};
|
|
1851
1893
|
const rightMargin = estimateRightMargin();
|
|
1852
1894
|
const chartLeft = margin.left;
|
|
@@ -3493,6 +3535,9 @@ function createChart(element, options = {}) {
|
|
|
3493
3535
|
draw();
|
|
3494
3536
|
};
|
|
3495
3537
|
const onPointerDown = (event) => {
|
|
3538
|
+
if (event.pointerType === "touch" || event.pointerType === "pen") {
|
|
3539
|
+
event.preventDefault();
|
|
3540
|
+
}
|
|
3496
3541
|
const point = getCanvasPoint(event);
|
|
3497
3542
|
if (event.pointerType === "touch") {
|
|
3498
3543
|
touchPointers.set(event.pointerId, point);
|
|
@@ -3591,12 +3636,29 @@ function createChart(element, options = {}) {
|
|
|
3591
3636
|
isDragging = true;
|
|
3592
3637
|
dragMode = region;
|
|
3593
3638
|
activePointerId = event.pointerId;
|
|
3594
|
-
|
|
3639
|
+
const crosshairDrag = (event.pointerType === "touch" || event.pointerType === "pen") && region === "plot";
|
|
3640
|
+
pointerDownInfo = {
|
|
3641
|
+
pointerId: event.pointerId,
|
|
3642
|
+
pointerType: event.pointerType,
|
|
3643
|
+
x: point.x,
|
|
3644
|
+
y: point.y,
|
|
3645
|
+
region,
|
|
3646
|
+
moved: false,
|
|
3647
|
+
crosshairDrag
|
|
3648
|
+
};
|
|
3595
3649
|
lastPointerX = point.x;
|
|
3596
3650
|
lastPointerY = point.y;
|
|
3597
3651
|
canvas.setPointerCapture(event.pointerId);
|
|
3652
|
+
if (crosshairDrag) {
|
|
3653
|
+
canvas.style.cursor = "crosshair";
|
|
3654
|
+
setCrosshairPoint(point);
|
|
3655
|
+
emitCrosshairMove(point.x, point.y, "plot");
|
|
3656
|
+
}
|
|
3598
3657
|
};
|
|
3599
3658
|
const onPointerMove = (event) => {
|
|
3659
|
+
if (event.pointerType === "touch" || event.pointerType === "pen") {
|
|
3660
|
+
event.preventDefault();
|
|
3661
|
+
}
|
|
3600
3662
|
const point = getCanvasPoint(event);
|
|
3601
3663
|
if (event.pointerType === "touch" && touchPointers.has(event.pointerId)) {
|
|
3602
3664
|
touchPointers.set(event.pointerId, point);
|
|
@@ -3619,6 +3681,16 @@ function createChart(element, options = {}) {
|
|
|
3619
3681
|
pointerDownInfo.moved = true;
|
|
3620
3682
|
}
|
|
3621
3683
|
}
|
|
3684
|
+
if (pointerDownInfo?.crosshairDrag && pointerDownInfo.pointerId === event.pointerId) {
|
|
3685
|
+
if (getHitRegion(point.x, point.y) === "plot") {
|
|
3686
|
+
canvas.style.cursor = "crosshair";
|
|
3687
|
+
setCrosshairPoint(point);
|
|
3688
|
+
emitCrosshairMove(point.x, point.y, "plot");
|
|
3689
|
+
lastPointerX = point.x;
|
|
3690
|
+
lastPointerY = point.y;
|
|
3691
|
+
}
|
|
3692
|
+
return;
|
|
3693
|
+
}
|
|
3622
3694
|
if (drawingDragState) {
|
|
3623
3695
|
if (activePointerId !== null && event.pointerId !== activePointerId) {
|
|
3624
3696
|
return;
|
|
@@ -3832,7 +3904,13 @@ function createChart(element, options = {}) {
|
|
|
3832
3904
|
activePointerId = null;
|
|
3833
3905
|
canvas.style.cursor = "default";
|
|
3834
3906
|
if (event && pointerDownInfo && event.pointerId === pointerDownInfo.pointerId) {
|
|
3835
|
-
if (
|
|
3907
|
+
if (pointerDownInfo.crosshairDrag) {
|
|
3908
|
+
const point = getCanvasPoint(event);
|
|
3909
|
+
if (getHitRegion(point.x, point.y) === "plot") {
|
|
3910
|
+
setCrosshairPoint(point);
|
|
3911
|
+
emitCrosshairMove(point.x, point.y, "plot");
|
|
3912
|
+
}
|
|
3913
|
+
} else if (!pointerDownInfo.moved) {
|
|
3836
3914
|
const clickPrice = pointerDownInfo.region === "plot" ? roundToPricePrecision(priceFromCanvasY(pointerDownInfo.y)) : void 0;
|
|
3837
3915
|
chartClickHandler?.({
|
|
3838
3916
|
x: pointerDownInfo.x,
|
|
@@ -3879,6 +3957,7 @@ function createChart(element, options = {}) {
|
|
|
3879
3957
|
zoomX(factor, point.x);
|
|
3880
3958
|
};
|
|
3881
3959
|
const onDoubleClick = (event) => {
|
|
3960
|
+
event.preventDefault();
|
|
3882
3961
|
if (!doubleClickEnabled) {
|
|
3883
3962
|
return;
|
|
3884
3963
|
}
|
|
@@ -3904,6 +3983,9 @@ function createChart(element, options = {}) {
|
|
|
3904
3983
|
}
|
|
3905
3984
|
resetViewport();
|
|
3906
3985
|
};
|
|
3986
|
+
const onContextMenu = (event) => {
|
|
3987
|
+
event.preventDefault();
|
|
3988
|
+
};
|
|
3907
3989
|
canvas.addEventListener("pointerdown", onPointerDown);
|
|
3908
3990
|
canvas.addEventListener("pointermove", onPointerMove);
|
|
3909
3991
|
canvas.addEventListener("pointerup", endPointerDrag);
|
|
@@ -3911,6 +3993,7 @@ function createChart(element, options = {}) {
|
|
|
3911
3993
|
canvas.addEventListener("pointerleave", endPointerDrag);
|
|
3912
3994
|
canvas.addEventListener("wheel", onWheel, { passive: false });
|
|
3913
3995
|
canvas.addEventListener("dblclick", onDoubleClick);
|
|
3996
|
+
canvas.addEventListener("contextmenu", onContextMenu);
|
|
3914
3997
|
const updateOptions = (nextOptions) => {
|
|
3915
3998
|
const wasTickerSmoothingEnabled = mergedOptions.tickerLine?.smoothing ?? false;
|
|
3916
3999
|
const previousWidth = width;
|
|
@@ -3919,6 +4002,7 @@ function createChart(element, options = {}) {
|
|
|
3919
4002
|
width = nextOptions.width !== void 0 && nextOptions.width > 0 ? mergedOptions.width : previousWidth;
|
|
3920
4003
|
height = nextOptions.height !== void 0 && nextOptions.height > 0 ? mergedOptions.height : previousHeight;
|
|
3921
4004
|
mergedOptions = { ...mergedOptions, width, height };
|
|
4005
|
+
resetRightMarginCache();
|
|
3922
4006
|
doubleClickEnabled = mergedOptions.doubleClickEnabled;
|
|
3923
4007
|
doubleClickAction = mergedOptions.doubleClickAction;
|
|
3924
4008
|
const isTickerSmoothingEnabled = mergedOptions.tickerLine?.smoothing ?? false;
|
|
@@ -3945,6 +4029,7 @@ function createChart(element, options = {}) {
|
|
|
3945
4029
|
height = nextHeight;
|
|
3946
4030
|
}
|
|
3947
4031
|
mergedOptions = { ...mergedOptions, width, height };
|
|
4032
|
+
resetRightMarginCache();
|
|
3948
4033
|
draw();
|
|
3949
4034
|
};
|
|
3950
4035
|
const setData = (nextData) => {
|
|
@@ -3961,6 +4046,7 @@ function createChart(element, options = {}) {
|
|
|
3961
4046
|
tickerPriceTarget = null;
|
|
3962
4047
|
smoothedTickerVolume = null;
|
|
3963
4048
|
tickerVolumeTarget = null;
|
|
4049
|
+
resetRightMarginCache();
|
|
3964
4050
|
resetYViewport();
|
|
3965
4051
|
draw();
|
|
3966
4052
|
return;
|
|
@@ -3994,6 +4080,7 @@ function createChart(element, options = {}) {
|
|
|
3994
4080
|
...line,
|
|
3995
4081
|
id: line.id ?? `line-${index + 1}`
|
|
3996
4082
|
}));
|
|
4083
|
+
resetRightMarginCache();
|
|
3997
4084
|
draw();
|
|
3998
4085
|
};
|
|
3999
4086
|
const addPriceLine = (line) => {
|
|
@@ -4004,6 +4091,7 @@ function createChart(element, options = {}) {
|
|
|
4004
4091
|
};
|
|
4005
4092
|
const removePriceLine = (id) => {
|
|
4006
4093
|
priceLines = priceLines.filter((line) => line.id !== id);
|
|
4094
|
+
resetRightMarginCache();
|
|
4007
4095
|
draw();
|
|
4008
4096
|
};
|
|
4009
4097
|
const setOrderLines = (lines) => {
|
|
@@ -4011,6 +4099,7 @@ function createChart(element, options = {}) {
|
|
|
4011
4099
|
...line,
|
|
4012
4100
|
id: line.id ?? `order-${index + 1}`
|
|
4013
4101
|
}));
|
|
4102
|
+
resetRightMarginCache();
|
|
4014
4103
|
const activeIds = new Set(orderLines.map((line) => line.id));
|
|
4015
4104
|
for (const id of Array.from(orderWidgetWidthById.keys())) {
|
|
4016
4105
|
if (!activeIds.has(id)) {
|
|
@@ -4038,6 +4127,7 @@ function createChart(element, options = {}) {
|
|
|
4038
4127
|
orderLines = orderLines.filter((line) => line.id !== id);
|
|
4039
4128
|
orderWidgetWidthById.delete(id);
|
|
4040
4129
|
orderPriceTagWidthById.delete(id);
|
|
4130
|
+
resetRightMarginCache();
|
|
4041
4131
|
draw();
|
|
4042
4132
|
};
|
|
4043
4133
|
const onOrderAction = (handler) => {
|
|
@@ -4201,6 +4291,7 @@ function createChart(element, options = {}) {
|
|
|
4201
4291
|
canvas.removeEventListener("pointerleave", endPointerDrag);
|
|
4202
4292
|
canvas.removeEventListener("wheel", onWheel);
|
|
4203
4293
|
canvas.removeEventListener("dblclick", onDoubleClick);
|
|
4294
|
+
canvas.removeEventListener("contextmenu", onContextMenu);
|
|
4204
4295
|
element.innerHTML = "";
|
|
4205
4296
|
};
|
|
4206
4297
|
draw();
|