hyperprop-charting-library 0.1.128 → 0.1.130
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 +439 -62
- package/dist/hyperprop-charting-library.d.ts +26 -1
- package/dist/hyperprop-charting-library.js +439 -62
- package/dist/index.cjs +439 -62
- package/dist/index.d.cts +26 -1
- package/dist/index.d.ts +26 -1
- package/dist/index.js +439 -62
- package/docs/API.md +10 -0
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -785,6 +785,40 @@ var fillBetweenSeries = (ctx, renderContext, upper, lower, color, opacity) => {
|
|
|
785
785
|
flushRun(renderContext.endIndex + 1);
|
|
786
786
|
ctx.restore();
|
|
787
787
|
};
|
|
788
|
+
var drawPaneHorizontalGrid = (ctx, renderContext, minValue, maxValue) => {
|
|
789
|
+
const grid = renderContext.grid;
|
|
790
|
+
if (!grid || !grid.horizontalLines) return;
|
|
791
|
+
const range = maxValue - minValue;
|
|
792
|
+
if (!(range > 0) || !Number.isFinite(range)) return;
|
|
793
|
+
const targetCount = Math.max(2, Math.round(renderContext.chartHeight / 42));
|
|
794
|
+
const targetStep = range / targetCount;
|
|
795
|
+
if (!(targetStep > 0) || !Number.isFinite(targetStep)) return;
|
|
796
|
+
const base = Math.pow(10, Math.floor(Math.log10(targetStep)));
|
|
797
|
+
const frac = targetStep / base;
|
|
798
|
+
const step = (frac <= 1 ? 1 : frac <= 2 ? 2 : frac <= 2.5 ? 2.5 : frac <= 5 ? 5 : 10) * base;
|
|
799
|
+
ctx.save();
|
|
800
|
+
ctx.globalAlpha = Math.min(1, Math.max(0, grid.opacity));
|
|
801
|
+
ctx.strokeStyle = grid.color;
|
|
802
|
+
ctx.lineWidth = 1;
|
|
803
|
+
ctx.setLineDash([]);
|
|
804
|
+
ctx.beginPath();
|
|
805
|
+
const firstTick = Math.ceil(minValue / step) * step;
|
|
806
|
+
const edgeInset = renderContext.chartHeight * 0.04;
|
|
807
|
+
for (let i = 0; i < 64; i += 1) {
|
|
808
|
+
const value = firstTick + i * step;
|
|
809
|
+
if (value > maxValue) break;
|
|
810
|
+
const ratio = (value - minValue) / range;
|
|
811
|
+
const y = renderContext.chartBottom - ratio * renderContext.chartHeight;
|
|
812
|
+
if (y > renderContext.chartBottom - edgeInset || y < renderContext.chartBottom - renderContext.chartHeight + edgeInset) {
|
|
813
|
+
continue;
|
|
814
|
+
}
|
|
815
|
+
const crispY = Math.round(y) + 0.5;
|
|
816
|
+
ctx.moveTo(renderContext.chartLeft, crispY);
|
|
817
|
+
ctx.lineTo(renderContext.chartRight, crispY);
|
|
818
|
+
}
|
|
819
|
+
ctx.stroke();
|
|
820
|
+
ctx.restore();
|
|
821
|
+
};
|
|
788
822
|
var drawSeparateSeries = (ctx, renderContext, values, color, width, minOverride, maxOverride, guideLines, options = {}) => {
|
|
789
823
|
const visible = [];
|
|
790
824
|
for (let index = renderContext.startIndex; index <= renderContext.endIndex; index += 1) {
|
|
@@ -796,6 +830,7 @@ var drawSeparateSeries = (ctx, renderContext, values, color, width, minOverride,
|
|
|
796
830
|
if (visible.length === 0) return void 0;
|
|
797
831
|
const minValue = minOverride ?? Math.min(...visible);
|
|
798
832
|
const maxValue = maxOverride ?? Math.max(...visible);
|
|
833
|
+
drawPaneHorizontalGrid(ctx, renderContext, minValue, maxValue);
|
|
799
834
|
const range = maxValue - minValue || 1;
|
|
800
835
|
const yFromValue = (value) => {
|
|
801
836
|
const ratio = (value - minValue) / range;
|
|
@@ -850,6 +885,19 @@ var drawSeparateSeries = (ctx, renderContext, values, color, width, minOverride,
|
|
|
850
885
|
break;
|
|
851
886
|
}
|
|
852
887
|
}
|
|
888
|
+
if (options.valueLine && latestValue !== null && latestValue >= minValue && latestValue <= maxValue) {
|
|
889
|
+
ctx.save();
|
|
890
|
+
ctx.lineWidth = 1;
|
|
891
|
+
ctx.setLineDash([3, 3]);
|
|
892
|
+
ctx.globalAlpha = 0.65;
|
|
893
|
+
ctx.strokeStyle = color;
|
|
894
|
+
const y = yFromValue(latestValue);
|
|
895
|
+
ctx.beginPath();
|
|
896
|
+
ctx.moveTo(renderContext.chartLeft, y);
|
|
897
|
+
ctx.lineTo(renderContext.chartRight, y);
|
|
898
|
+
ctx.stroke();
|
|
899
|
+
ctx.restore();
|
|
900
|
+
}
|
|
853
901
|
const decimals = options.decimals ?? 2;
|
|
854
902
|
const formatValue = (value) => value.toFixed(decimals);
|
|
855
903
|
const axisTicks = options.axisTicks ?? guideLines;
|
|
@@ -1177,7 +1225,7 @@ var BUILTIN_STDDEV_INDICATOR = {
|
|
|
1177
1225
|
name: "StdDev",
|
|
1178
1226
|
pane: "separate",
|
|
1179
1227
|
paneHeightRatio: 0.16,
|
|
1180
|
-
defaultInputs: { length: 20, source: "close", color: "#f97316", width: 2 },
|
|
1228
|
+
defaultInputs: { length: 20, source: "close", color: "#f97316", width: 2, showValueLine: true },
|
|
1181
1229
|
draw: (ctx, renderContext, inputs) => {
|
|
1182
1230
|
const length = clampIndicatorLength(inputs.length, 20);
|
|
1183
1231
|
const values = withCachedSeries(
|
|
@@ -1187,7 +1235,8 @@ var BUILTIN_STDDEV_INDICATOR = {
|
|
|
1187
1235
|
);
|
|
1188
1236
|
return drawSeparateSeries(ctx, renderContext, values, inputs.color ?? "#f97316", Number(inputs.width) || 2, void 0, void 0, void 0, {
|
|
1189
1237
|
title: `StdDev ${length}`,
|
|
1190
|
-
decimals: 2
|
|
1238
|
+
decimals: 2,
|
|
1239
|
+
valueLine: inputs.showValueLine !== false
|
|
1191
1240
|
});
|
|
1192
1241
|
}
|
|
1193
1242
|
};
|
|
@@ -1196,13 +1245,14 @@ var BUILTIN_ATR_INDICATOR = {
|
|
|
1196
1245
|
name: "ATR",
|
|
1197
1246
|
pane: "separate",
|
|
1198
1247
|
paneHeightRatio: 0.16,
|
|
1199
|
-
defaultInputs: { length: 14, color: "#eab308", width: 2 },
|
|
1248
|
+
defaultInputs: { length: 14, color: "#eab308", width: 2, showValueLine: true },
|
|
1200
1249
|
draw: (ctx, renderContext, inputs) => {
|
|
1201
1250
|
const length = clampIndicatorLength(inputs.length, 14);
|
|
1202
1251
|
const values = withCachedSeries(`atr|${length}`, renderContext.data, () => computeAtrSeries(renderContext.data, length));
|
|
1203
1252
|
return drawSeparateSeries(ctx, renderContext, values, inputs.color ?? "#eab308", Number(inputs.width) || 2, void 0, void 0, void 0, {
|
|
1204
1253
|
title: `ATR ${length}`,
|
|
1205
|
-
decimals: 2
|
|
1254
|
+
decimals: 2,
|
|
1255
|
+
valueLine: inputs.showValueLine !== false
|
|
1206
1256
|
});
|
|
1207
1257
|
}
|
|
1208
1258
|
};
|
|
@@ -1218,7 +1268,8 @@ var BUILTIN_RSI_INDICATOR = {
|
|
|
1218
1268
|
showLegend: true,
|
|
1219
1269
|
showValueLabel: true,
|
|
1220
1270
|
showGuideLines: true,
|
|
1221
|
-
showScaleLabels: true
|
|
1271
|
+
showScaleLabels: true,
|
|
1272
|
+
showValueLine: true
|
|
1222
1273
|
},
|
|
1223
1274
|
draw: (ctx, renderContext, inputs) => {
|
|
1224
1275
|
const length = clampIndicatorLength(inputs.length, 14);
|
|
@@ -1241,7 +1292,8 @@ var BUILTIN_RSI_INDICATOR = {
|
|
|
1241
1292
|
valueLabelColor: "#9E9E9E",
|
|
1242
1293
|
valueLabelBackgroundColor: "#9E9E9E",
|
|
1243
1294
|
valueLabelTextColor: "#0f172a",
|
|
1244
|
-
showLegend: inputs.showLegend !== false
|
|
1295
|
+
showLegend: inputs.showLegend !== false,
|
|
1296
|
+
valueLine: inputs.showValueLine !== false
|
|
1245
1297
|
}
|
|
1246
1298
|
);
|
|
1247
1299
|
}
|
|
@@ -1298,6 +1350,7 @@ var drawSeparateMultiSeries = (ctx, renderContext, seriesList, options = {}) =>
|
|
|
1298
1350
|
const ratio = (value - minValue) / range;
|
|
1299
1351
|
return renderContext.chartBottom - ratio * renderContext.chartHeight;
|
|
1300
1352
|
};
|
|
1353
|
+
drawPaneHorizontalGrid(ctx, renderContext, minValue, maxValue);
|
|
1301
1354
|
if (options.guideLines && options.guideLines.length > 0) {
|
|
1302
1355
|
ctx.save();
|
|
1303
1356
|
ctx.strokeStyle = "rgba(148,163,184,0.35)";
|
|
@@ -1377,6 +1430,24 @@ var drawSeparateMultiSeries = (ctx, renderContext, seriesList, options = {}) =>
|
|
|
1377
1430
|
}
|
|
1378
1431
|
return null;
|
|
1379
1432
|
};
|
|
1433
|
+
if (options.valueLines) {
|
|
1434
|
+
ctx.save();
|
|
1435
|
+
ctx.lineWidth = 1;
|
|
1436
|
+
ctx.setLineDash([3, 3]);
|
|
1437
|
+
ctx.globalAlpha = 0.65;
|
|
1438
|
+
for (const spec of seriesList) {
|
|
1439
|
+
if (spec.histogram) continue;
|
|
1440
|
+
const latest = latestOf(spec.values);
|
|
1441
|
+
if (latest === null || latest < minValue || latest > maxValue) continue;
|
|
1442
|
+
const y = yFromValue(latest);
|
|
1443
|
+
ctx.strokeStyle = spec.color;
|
|
1444
|
+
ctx.beginPath();
|
|
1445
|
+
ctx.moveTo(renderContext.chartLeft, y);
|
|
1446
|
+
ctx.lineTo(renderContext.chartRight, y);
|
|
1447
|
+
ctx.stroke();
|
|
1448
|
+
}
|
|
1449
|
+
ctx.restore();
|
|
1450
|
+
}
|
|
1380
1451
|
const paneInfo = {
|
|
1381
1452
|
...options.title ? { title: options.title } : {},
|
|
1382
1453
|
axis: {
|
|
@@ -1730,7 +1801,8 @@ var BUILTIN_MACD_INDICATOR = {
|
|
|
1730
1801
|
macdColor: "#2962ff",
|
|
1731
1802
|
signalColor: "#ff6d00",
|
|
1732
1803
|
histUpColor: "#26a69a",
|
|
1733
|
-
histDownColor: "#ef5350"
|
|
1804
|
+
histDownColor: "#ef5350",
|
|
1805
|
+
showValueLine: true
|
|
1734
1806
|
},
|
|
1735
1807
|
draw: (ctx, renderContext, inputs) => {
|
|
1736
1808
|
const fast = clampIndicatorLength(inputs.fast, 12);
|
|
@@ -1759,7 +1831,8 @@ var BUILTIN_MACD_INDICATOR = {
|
|
|
1759
1831
|
includeZero: true,
|
|
1760
1832
|
guideLines: [0],
|
|
1761
1833
|
decimals: 2,
|
|
1762
|
-
valueLabelSeriesIndex: 1
|
|
1834
|
+
valueLabelSeriesIndex: 1,
|
|
1835
|
+
valueLines: inputs.showValueLine !== false
|
|
1763
1836
|
}
|
|
1764
1837
|
);
|
|
1765
1838
|
}
|
|
@@ -1769,7 +1842,7 @@ var BUILTIN_STOCHASTIC_INDICATOR = {
|
|
|
1769
1842
|
name: "Stoch",
|
|
1770
1843
|
pane: "separate",
|
|
1771
1844
|
paneHeightRatio: 0.18,
|
|
1772
|
-
defaultInputs: { kLength: 14, kSmoothing: 1, dLength: 3, kColor: "#2962ff", dColor: "#ff6d00" },
|
|
1845
|
+
defaultInputs: { kLength: 14, kSmoothing: 1, dLength: 3, kColor: "#2962ff", dColor: "#ff6d00", showValueLine: true },
|
|
1773
1846
|
draw: (ctx, renderContext, inputs) => {
|
|
1774
1847
|
const kLength = clampIndicatorLength(inputs.kLength, 14);
|
|
1775
1848
|
const kSmoothing = clampIndicatorLength(inputs.kSmoothing, 1);
|
|
@@ -1792,7 +1865,8 @@ var BUILTIN_STOCHASTIC_INDICATOR = {
|
|
|
1792
1865
|
maxOverride: 100,
|
|
1793
1866
|
guideLines: [20, 80],
|
|
1794
1867
|
axisTicks: [0, 20, 50, 80, 100],
|
|
1795
|
-
decimals: 2
|
|
1868
|
+
decimals: 2,
|
|
1869
|
+
valueLines: inputs.showValueLine !== false
|
|
1796
1870
|
}
|
|
1797
1871
|
);
|
|
1798
1872
|
}
|
|
@@ -1802,7 +1876,15 @@ var BUILTIN_STOCHRSI_INDICATOR = {
|
|
|
1802
1876
|
name: "Stoch RSI",
|
|
1803
1877
|
pane: "separate",
|
|
1804
1878
|
paneHeightRatio: 0.18,
|
|
1805
|
-
defaultInputs: {
|
|
1879
|
+
defaultInputs: {
|
|
1880
|
+
rsiLength: 14,
|
|
1881
|
+
stochLength: 14,
|
|
1882
|
+
kSmoothing: 3,
|
|
1883
|
+
dSmoothing: 3,
|
|
1884
|
+
kColor: "#2962ff",
|
|
1885
|
+
dColor: "#ff6d00",
|
|
1886
|
+
showValueLine: true
|
|
1887
|
+
},
|
|
1806
1888
|
draw: (ctx, renderContext, inputs) => {
|
|
1807
1889
|
const rsiLength = clampIndicatorLength(inputs.rsiLength, 14);
|
|
1808
1890
|
const stochLength = clampIndicatorLength(inputs.stochLength, 14);
|
|
@@ -1826,7 +1908,8 @@ var BUILTIN_STOCHRSI_INDICATOR = {
|
|
|
1826
1908
|
maxOverride: 100,
|
|
1827
1909
|
guideLines: [20, 80],
|
|
1828
1910
|
axisTicks: [0, 20, 50, 80, 100],
|
|
1829
|
-
decimals: 2
|
|
1911
|
+
decimals: 2,
|
|
1912
|
+
valueLines: inputs.showValueLine !== false
|
|
1830
1913
|
}
|
|
1831
1914
|
);
|
|
1832
1915
|
}
|
|
@@ -1836,7 +1919,14 @@ var BUILTIN_ADX_INDICATOR = {
|
|
|
1836
1919
|
name: "ADX/DMI",
|
|
1837
1920
|
pane: "separate",
|
|
1838
1921
|
paneHeightRatio: 0.18,
|
|
1839
|
-
defaultInputs: {
|
|
1922
|
+
defaultInputs: {
|
|
1923
|
+
length: 14,
|
|
1924
|
+
adxColor: "#ff6d00",
|
|
1925
|
+
plusDiColor: "#26a69a",
|
|
1926
|
+
minusDiColor: "#ef5350",
|
|
1927
|
+
showDi: true,
|
|
1928
|
+
showValueLine: true
|
|
1929
|
+
},
|
|
1840
1930
|
draw: (ctx, renderContext, inputs) => {
|
|
1841
1931
|
const length = clampIndicatorLength(inputs.length, 14);
|
|
1842
1932
|
const { adx, plusDi, minusDi } = withCachedComputation(
|
|
@@ -1857,7 +1947,8 @@ var BUILTIN_ADX_INDICATOR = {
|
|
|
1857
1947
|
title: `ADX ${length}`,
|
|
1858
1948
|
minOverride: 0,
|
|
1859
1949
|
guideLines: [20],
|
|
1860
|
-
decimals: 2
|
|
1950
|
+
decimals: 2,
|
|
1951
|
+
valueLines: inputs.showValueLine !== false
|
|
1861
1952
|
});
|
|
1862
1953
|
}
|
|
1863
1954
|
};
|
|
@@ -1866,14 +1957,14 @@ var BUILTIN_OBV_INDICATOR = {
|
|
|
1866
1957
|
name: "OBV",
|
|
1867
1958
|
pane: "separate",
|
|
1868
1959
|
paneHeightRatio: 0.16,
|
|
1869
|
-
defaultInputs: { color: "#2962ff", width: 2 },
|
|
1960
|
+
defaultInputs: { color: "#2962ff", width: 2, showValueLine: true },
|
|
1870
1961
|
draw: (ctx, renderContext, inputs) => {
|
|
1871
1962
|
const values = withCachedSeries("obv", renderContext.data, () => computeObvSeries(renderContext.data));
|
|
1872
1963
|
return drawSeparateMultiSeries(
|
|
1873
1964
|
ctx,
|
|
1874
1965
|
renderContext,
|
|
1875
1966
|
[{ values, color: inputs.color ?? "#2962ff", width: Number(inputs.width) || 2, label: "OBV" }],
|
|
1876
|
-
{ title: "OBV", format: formatCompactNumber }
|
|
1967
|
+
{ title: "OBV", format: formatCompactNumber, valueLines: inputs.showValueLine !== false }
|
|
1877
1968
|
);
|
|
1878
1969
|
}
|
|
1879
1970
|
};
|
|
@@ -1882,7 +1973,7 @@ var BUILTIN_MFI_INDICATOR = {
|
|
|
1882
1973
|
name: "MFI",
|
|
1883
1974
|
pane: "separate",
|
|
1884
1975
|
paneHeightRatio: 0.16,
|
|
1885
|
-
defaultInputs: { length: 14, color: "#7e57c2", width: 2 },
|
|
1976
|
+
defaultInputs: { length: 14, color: "#7e57c2", width: 2, showValueLine: true },
|
|
1886
1977
|
draw: (ctx, renderContext, inputs) => {
|
|
1887
1978
|
const length = clampIndicatorLength(inputs.length, 14);
|
|
1888
1979
|
const values = withCachedSeries(
|
|
@@ -1900,7 +1991,8 @@ var BUILTIN_MFI_INDICATOR = {
|
|
|
1900
1991
|
maxOverride: 100,
|
|
1901
1992
|
guideLines: [20, 80],
|
|
1902
1993
|
axisTicks: [0, 20, 50, 80, 100],
|
|
1903
|
-
decimals: 2
|
|
1994
|
+
decimals: 2,
|
|
1995
|
+
valueLines: inputs.showValueLine !== false
|
|
1904
1996
|
}
|
|
1905
1997
|
);
|
|
1906
1998
|
}
|
|
@@ -1910,7 +2002,7 @@ var BUILTIN_CCI_INDICATOR = {
|
|
|
1910
2002
|
name: "CCI",
|
|
1911
2003
|
pane: "separate",
|
|
1912
2004
|
paneHeightRatio: 0.16,
|
|
1913
|
-
defaultInputs: { length: 20, color: "#2962ff", width: 2 },
|
|
2005
|
+
defaultInputs: { length: 20, color: "#2962ff", width: 2, showValueLine: true },
|
|
1914
2006
|
draw: (ctx, renderContext, inputs) => {
|
|
1915
2007
|
const length = clampIndicatorLength(inputs.length, 20);
|
|
1916
2008
|
const values = withCachedSeries(
|
|
@@ -1922,7 +2014,7 @@ var BUILTIN_CCI_INDICATOR = {
|
|
|
1922
2014
|
ctx,
|
|
1923
2015
|
renderContext,
|
|
1924
2016
|
[{ values, color: inputs.color ?? "#2962ff", width: Number(inputs.width) || 2 }],
|
|
1925
|
-
{ title: `CCI ${length}`, guideLines: [-100, 0, 100], decimals: 2 }
|
|
2017
|
+
{ title: `CCI ${length}`, guideLines: [-100, 0, 100], decimals: 2, valueLines: inputs.showValueLine !== false }
|
|
1926
2018
|
);
|
|
1927
2019
|
}
|
|
1928
2020
|
};
|
|
@@ -1931,7 +2023,7 @@ var BUILTIN_WILLIAMSR_INDICATOR = {
|
|
|
1931
2023
|
name: "Williams %R",
|
|
1932
2024
|
pane: "separate",
|
|
1933
2025
|
paneHeightRatio: 0.16,
|
|
1934
|
-
defaultInputs: { length: 14, color: "#7e57c2", width: 2 },
|
|
2026
|
+
defaultInputs: { length: 14, color: "#7e57c2", width: 2, showValueLine: true },
|
|
1935
2027
|
draw: (ctx, renderContext, inputs) => {
|
|
1936
2028
|
const length = clampIndicatorLength(inputs.length, 14);
|
|
1937
2029
|
const values = withCachedSeries(
|
|
@@ -1949,7 +2041,8 @@ var BUILTIN_WILLIAMSR_INDICATOR = {
|
|
|
1949
2041
|
maxOverride: 0,
|
|
1950
2042
|
guideLines: [-80, -20],
|
|
1951
2043
|
axisTicks: [-100, -80, -50, -20, 0],
|
|
1952
|
-
decimals: 2
|
|
2044
|
+
decimals: 2,
|
|
2045
|
+
valueLines: inputs.showValueLine !== false
|
|
1953
2046
|
}
|
|
1954
2047
|
);
|
|
1955
2048
|
}
|
|
@@ -1959,7 +2052,7 @@ var BUILTIN_ROC_INDICATOR = {
|
|
|
1959
2052
|
name: "ROC",
|
|
1960
2053
|
pane: "separate",
|
|
1961
2054
|
paneHeightRatio: 0.16,
|
|
1962
|
-
defaultInputs: { length: 9, color: "#2962ff", width: 2 },
|
|
2055
|
+
defaultInputs: { length: 9, color: "#2962ff", width: 2, showValueLine: true },
|
|
1963
2056
|
draw: (ctx, renderContext, inputs) => {
|
|
1964
2057
|
const length = clampIndicatorLength(inputs.length, 9);
|
|
1965
2058
|
const values = withCachedSeries(
|
|
@@ -1971,7 +2064,7 @@ var BUILTIN_ROC_INDICATOR = {
|
|
|
1971
2064
|
ctx,
|
|
1972
2065
|
renderContext,
|
|
1973
2066
|
[{ values, color: inputs.color ?? "#2962ff", width: Number(inputs.width) || 2 }],
|
|
1974
|
-
{ title: `ROC ${length}`, includeZero: true, guideLines: [0], decimals: 2 }
|
|
2067
|
+
{ title: `ROC ${length}`, includeZero: true, guideLines: [0], decimals: 2, valueLines: inputs.showValueLine !== false }
|
|
1975
2068
|
);
|
|
1976
2069
|
}
|
|
1977
2070
|
};
|
|
@@ -1980,7 +2073,7 @@ var BUILTIN_MOMENTUM_INDICATOR = {
|
|
|
1980
2073
|
name: "Momentum",
|
|
1981
2074
|
pane: "separate",
|
|
1982
2075
|
paneHeightRatio: 0.16,
|
|
1983
|
-
defaultInputs: { length: 10, color: "#2962ff", width: 2 },
|
|
2076
|
+
defaultInputs: { length: 10, color: "#2962ff", width: 2, showValueLine: true },
|
|
1984
2077
|
draw: (ctx, renderContext, inputs) => {
|
|
1985
2078
|
const length = clampIndicatorLength(inputs.length, 10);
|
|
1986
2079
|
const values = withCachedSeries(
|
|
@@ -1992,7 +2085,7 @@ var BUILTIN_MOMENTUM_INDICATOR = {
|
|
|
1992
2085
|
ctx,
|
|
1993
2086
|
renderContext,
|
|
1994
2087
|
[{ values, color: inputs.color ?? "#2962ff", width: Number(inputs.width) || 2 }],
|
|
1995
|
-
{ title: `Mom ${length}`, includeZero: true, guideLines: [0], decimals: 2 }
|
|
2088
|
+
{ title: `Mom ${length}`, includeZero: true, guideLines: [0], decimals: 2, valueLines: inputs.showValueLine !== false }
|
|
1996
2089
|
);
|
|
1997
2090
|
}
|
|
1998
2091
|
};
|
|
@@ -2416,6 +2509,14 @@ function createChart(element, options = {}) {
|
|
|
2416
2509
|
let watermarkImageReady = false;
|
|
2417
2510
|
let drawState = null;
|
|
2418
2511
|
let plotBottomForHit = 0;
|
|
2512
|
+
let paneLayoutFullChartHeight = 0;
|
|
2513
|
+
let paneLayoutInfos = [];
|
|
2514
|
+
let paneButtonRegions = [];
|
|
2515
|
+
let hoveredPaneId = null;
|
|
2516
|
+
let hoveredPaneButton = null;
|
|
2517
|
+
let paneDividerDrag = null;
|
|
2518
|
+
let indicatorPaneActionHandler = null;
|
|
2519
|
+
let indicatorPaneHeightChangeHandler = null;
|
|
2419
2520
|
let orderDragState = null;
|
|
2420
2521
|
let actionDragState = null;
|
|
2421
2522
|
let pointerDownInfo = null;
|
|
@@ -3517,20 +3618,24 @@ function createChart(element, options = {}) {
|
|
|
3517
3618
|
const watermark = { ...DEFAULT_WATERMARK_OPTIONS, ...mergedOptions.watermark ?? {} };
|
|
3518
3619
|
const paneGap = 0;
|
|
3519
3620
|
const separatePaneSpacing = 6;
|
|
3520
|
-
const
|
|
3621
|
+
const collapsedPaneHeight = 26;
|
|
3622
|
+
const activeSeparateIndicators = indicators.map((indicator) => ({ indicator, plugin: indicatorRegistry.get(indicator.type) })).filter(
|
|
3521
3623
|
(value) => value.plugin !== void 0 && (value.indicator.pane ?? value.plugin.pane ?? "overlay") === "separate"
|
|
3522
3624
|
).sort((a, b) => a.indicator.zIndex - b.indicator.zIndex);
|
|
3523
3625
|
const overlayIndicatorsForScale = indicators.filter((indicator) => indicator.visible).map((indicator) => ({ indicator, plugin: indicatorRegistry.get(indicator.type) })).filter(
|
|
3524
3626
|
(value) => value.plugin !== void 0 && (value.indicator.pane ?? value.plugin.pane ?? "overlay") === "overlay"
|
|
3525
3627
|
);
|
|
3526
3628
|
const separatePaneHeightDefaults = activeSeparateIndicators.map(({ indicator, plugin }) => {
|
|
3629
|
+
if (!indicator.visible) return collapsedPaneHeight;
|
|
3527
3630
|
const ratio = Math.min(0.45, Math.max(0.08, indicator.paneHeightRatio ?? plugin.paneHeightRatio ?? 0.22));
|
|
3528
3631
|
return Math.round(fullChartHeight * ratio);
|
|
3529
3632
|
});
|
|
3530
3633
|
const separatePaneDesiredTotal = separatePaneHeightDefaults.reduce((sum, value) => sum + value, 0) + Math.max(0, activeSeparateIndicators.length - 1) * separatePaneSpacing;
|
|
3531
3634
|
const maxSeparatePaneTotal = Math.max(0, fullChartHeight - 140);
|
|
3532
3635
|
const separatePaneScale = separatePaneDesiredTotal > 0 && separatePaneDesiredTotal > maxSeparatePaneTotal ? maxSeparatePaneTotal / separatePaneDesiredTotal : 1;
|
|
3533
|
-
const separatePaneHeights = separatePaneHeightDefaults.map(
|
|
3636
|
+
const separatePaneHeights = separatePaneHeightDefaults.map(
|
|
3637
|
+
(value, index) => activeSeparateIndicators[index].indicator.visible ? Math.max(48, Math.round(value * separatePaneScale)) : collapsedPaneHeight
|
|
3638
|
+
);
|
|
3534
3639
|
const separatePaneTotal = separatePaneHeights.reduce((sum, value) => sum + value, 0) + Math.max(0, activeSeparateIndicators.length - 1) * separatePaneSpacing;
|
|
3535
3640
|
const pricePaneGap = activeSeparateIndicators.length > 0 ? paneGap : 0;
|
|
3536
3641
|
const chartHeight = Math.max(120, fullChartHeight - separatePaneTotal - pricePaneGap);
|
|
@@ -4781,43 +4886,138 @@ function createChart(element, options = {}) {
|
|
|
4781
4886
|
ctx.restore();
|
|
4782
4887
|
}
|
|
4783
4888
|
}
|
|
4889
|
+
paneLayoutFullChartHeight = fullChartHeight;
|
|
4890
|
+
paneLayoutInfos = [];
|
|
4891
|
+
paneButtonRegions = [];
|
|
4784
4892
|
if (activeSeparateIndicators.length > 0) {
|
|
4785
4893
|
const xFromIndex = (index) => chartLeft + (index + 0.5 - xStart) / xSpan * chartWidth;
|
|
4786
4894
|
let paneTopCursor = chartBottom + paneGap;
|
|
4895
|
+
const paneButtonSize = 16;
|
|
4896
|
+
const paneButtonGap = 4;
|
|
4897
|
+
const drawPaneButtons = (indicatorId, indicatorType, indicatorVisible, startX, centerY) => {
|
|
4898
|
+
const actionList = [
|
|
4899
|
+
"visibility",
|
|
4900
|
+
"settings",
|
|
4901
|
+
"source",
|
|
4902
|
+
"remove"
|
|
4903
|
+
];
|
|
4904
|
+
let buttonX = startX;
|
|
4905
|
+
for (const action of actionList) {
|
|
4906
|
+
const buttonY = centerY - paneButtonSize / 2;
|
|
4907
|
+
const hovered = hoveredPaneButton?.id === indicatorId && hoveredPaneButton.action === action;
|
|
4908
|
+
const iconColor = labels.indicatorTextColor;
|
|
4909
|
+
ctx.save();
|
|
4910
|
+
ctx.fillStyle = hovered ? "rgba(148,163,184,0.30)" : "rgba(148,163,184,0.12)";
|
|
4911
|
+
fillRoundedRect(Math.round(buttonX), Math.round(buttonY), paneButtonSize, paneButtonSize, 4);
|
|
4912
|
+
ctx.strokeStyle = iconColor;
|
|
4913
|
+
ctx.fillStyle = iconColor;
|
|
4914
|
+
ctx.globalAlpha = hovered ? 1 : 0.75;
|
|
4915
|
+
ctx.lineWidth = 1.2;
|
|
4916
|
+
ctx.setLineDash([]);
|
|
4917
|
+
const cx = buttonX + paneButtonSize / 2;
|
|
4918
|
+
const cy = centerY;
|
|
4919
|
+
if (action === "visibility") {
|
|
4920
|
+
ctx.beginPath();
|
|
4921
|
+
ctx.ellipse(cx, cy, 4.6, 3, 0, 0, Math.PI * 2);
|
|
4922
|
+
ctx.stroke();
|
|
4923
|
+
ctx.beginPath();
|
|
4924
|
+
ctx.arc(cx, cy, 1.3, 0, Math.PI * 2);
|
|
4925
|
+
ctx.fill();
|
|
4926
|
+
if (!indicatorVisible) {
|
|
4927
|
+
ctx.beginPath();
|
|
4928
|
+
ctx.moveTo(cx - 5.2, cy + 4.6);
|
|
4929
|
+
ctx.lineTo(cx + 5.2, cy - 4.6);
|
|
4930
|
+
ctx.stroke();
|
|
4931
|
+
}
|
|
4932
|
+
} else if (action === "settings") {
|
|
4933
|
+
ctx.beginPath();
|
|
4934
|
+
ctx.arc(cx, cy, 3.4, 0, Math.PI * 2);
|
|
4935
|
+
ctx.stroke();
|
|
4936
|
+
for (let toothIndex = 0; toothIndex < 8; toothIndex += 1) {
|
|
4937
|
+
const angle = Math.PI / 4 * toothIndex;
|
|
4938
|
+
ctx.beginPath();
|
|
4939
|
+
ctx.moveTo(cx + Math.cos(angle) * 3.4, cy + Math.sin(angle) * 3.4);
|
|
4940
|
+
ctx.lineTo(cx + Math.cos(angle) * 5.2, cy + Math.sin(angle) * 5.2);
|
|
4941
|
+
ctx.stroke();
|
|
4942
|
+
}
|
|
4943
|
+
ctx.beginPath();
|
|
4944
|
+
ctx.arc(cx, cy, 1.1, 0, Math.PI * 2);
|
|
4945
|
+
ctx.fill();
|
|
4946
|
+
} else if (action === "source") {
|
|
4947
|
+
const prevSourceFont = ctx.font;
|
|
4948
|
+
ctx.font = `bold 9px ${mergedOptions.fontFamily}`;
|
|
4949
|
+
drawText("{}", cx, cy + 0.5, "center", "middle", iconColor);
|
|
4950
|
+
ctx.font = prevSourceFont;
|
|
4951
|
+
} else {
|
|
4952
|
+
ctx.beginPath();
|
|
4953
|
+
ctx.moveTo(cx - 3.4, cy - 3.4);
|
|
4954
|
+
ctx.lineTo(cx + 3.4, cy + 3.4);
|
|
4955
|
+
ctx.moveTo(cx + 3.4, cy - 3.4);
|
|
4956
|
+
ctx.lineTo(cx - 3.4, cy + 3.4);
|
|
4957
|
+
ctx.stroke();
|
|
4958
|
+
}
|
|
4959
|
+
ctx.restore();
|
|
4960
|
+
paneButtonRegions.push({
|
|
4961
|
+
id: indicatorId,
|
|
4962
|
+
type: indicatorType,
|
|
4963
|
+
action,
|
|
4964
|
+
x: buttonX,
|
|
4965
|
+
y: buttonY,
|
|
4966
|
+
width: paneButtonSize,
|
|
4967
|
+
height: paneButtonSize
|
|
4968
|
+
});
|
|
4969
|
+
buttonX += paneButtonSize + paneButtonGap;
|
|
4970
|
+
}
|
|
4971
|
+
};
|
|
4787
4972
|
activeSeparateIndicators.forEach(({ indicator, plugin }, paneIndex) => {
|
|
4788
4973
|
const paneHeight = separatePaneHeights[paneIndex] ?? 80;
|
|
4789
4974
|
const paneTop = paneTopCursor;
|
|
4790
4975
|
const paneBottom = paneTop + paneHeight;
|
|
4791
4976
|
paneTopCursor = paneBottom + separatePaneSpacing;
|
|
4792
|
-
|
|
4793
|
-
|
|
4794
|
-
|
|
4795
|
-
|
|
4796
|
-
|
|
4797
|
-
|
|
4798
|
-
|
|
4799
|
-
|
|
4800
|
-
|
|
4801
|
-
|
|
4802
|
-
|
|
4803
|
-
|
|
4804
|
-
|
|
4805
|
-
|
|
4806
|
-
|
|
4807
|
-
|
|
4808
|
-
|
|
4809
|
-
|
|
4810
|
-
|
|
4811
|
-
|
|
4812
|
-
|
|
4813
|
-
|
|
4814
|
-
|
|
4815
|
-
|
|
4816
|
-
|
|
4817
|
-
|
|
4818
|
-
|
|
4819
|
-
|
|
4820
|
-
|
|
4977
|
+
paneLayoutInfos.push({
|
|
4978
|
+
id: indicator.id,
|
|
4979
|
+
type: indicator.type,
|
|
4980
|
+
top: paneTop,
|
|
4981
|
+
bottom: paneBottom,
|
|
4982
|
+
visible: indicator.visible
|
|
4983
|
+
});
|
|
4984
|
+
let paneInfo;
|
|
4985
|
+
if (indicator.visible) {
|
|
4986
|
+
ctx.save();
|
|
4987
|
+
ctx.beginPath();
|
|
4988
|
+
ctx.rect(chartLeft + 1, paneTop + 1, Math.max(0, chartWidth - 2), Math.max(0, paneHeight - 2));
|
|
4989
|
+
ctx.clip();
|
|
4990
|
+
paneInfo = plugin.draw(
|
|
4991
|
+
ctx,
|
|
4992
|
+
{
|
|
4993
|
+
data,
|
|
4994
|
+
startIndex,
|
|
4995
|
+
endIndex,
|
|
4996
|
+
xStart,
|
|
4997
|
+
xSpan,
|
|
4998
|
+
chartLeft,
|
|
4999
|
+
chartRight,
|
|
5000
|
+
chartTop: paneTop,
|
|
5001
|
+
chartBottom: paneBottom,
|
|
5002
|
+
chartWidth,
|
|
5003
|
+
chartHeight: paneHeight,
|
|
5004
|
+
xFromIndex,
|
|
5005
|
+
yFromPrice: null,
|
|
5006
|
+
getCandleDirectionByIndex,
|
|
5007
|
+
getVolumeByIndex,
|
|
5008
|
+
candleSpacing,
|
|
5009
|
+
upColor: mergedOptions.upColor,
|
|
5010
|
+
downColor: mergedOptions.downColor,
|
|
5011
|
+
grid: {
|
|
5012
|
+
color: gridColor,
|
|
5013
|
+
opacity: gridOpacity,
|
|
5014
|
+
horizontalLines: grid.horizontalLines !== false
|
|
5015
|
+
}
|
|
5016
|
+
},
|
|
5017
|
+
indicator.inputs
|
|
5018
|
+
) ?? void 0;
|
|
5019
|
+
ctx.restore();
|
|
5020
|
+
}
|
|
4821
5021
|
ctx.save();
|
|
4822
5022
|
ctx.strokeStyle = axis.lineColor;
|
|
4823
5023
|
ctx.lineWidth = Math.max(1, axis.lineWidth);
|
|
@@ -4826,6 +5026,27 @@ function createChart(element, options = {}) {
|
|
|
4826
5026
|
ctx.lineTo(crisp(chartRight), crisp(paneTop));
|
|
4827
5027
|
ctx.stroke();
|
|
4828
5028
|
ctx.restore();
|
|
5029
|
+
if (!indicator.visible) {
|
|
5030
|
+
if (labels.visible) {
|
|
5031
|
+
const prevFont = ctx.font;
|
|
5032
|
+
ctx.font = `${Math.max(8, axis.fontSize)}px ${mergedOptions.fontFamily}`;
|
|
5033
|
+
const hiddenText = `${plugin.name} (hidden)`;
|
|
5034
|
+
const rowCenterY = (paneTop + paneBottom) / 2;
|
|
5035
|
+
ctx.save();
|
|
5036
|
+
ctx.globalAlpha = 0.55;
|
|
5037
|
+
drawText(hiddenText, chartLeft + 10, rowCenterY, "left", "middle", labels.indicatorTextColor);
|
|
5038
|
+
ctx.restore();
|
|
5039
|
+
drawPaneButtons(
|
|
5040
|
+
indicator.id,
|
|
5041
|
+
indicator.type,
|
|
5042
|
+
false,
|
|
5043
|
+
chartLeft + 10 + Math.ceil(measureTextWidth(hiddenText)) + 10,
|
|
5044
|
+
rowCenterY
|
|
5045
|
+
);
|
|
5046
|
+
ctx.font = prevFont;
|
|
5047
|
+
}
|
|
5048
|
+
return;
|
|
5049
|
+
}
|
|
4829
5050
|
const axisInfo = paneInfo?.axis;
|
|
4830
5051
|
if (axisInfo && Number.isFinite(axisInfo.min) && Number.isFinite(axisInfo.max) && axisInfo.max !== axisInfo.min) {
|
|
4831
5052
|
const paneRange = axisInfo.max - axisInfo.min;
|
|
@@ -4855,17 +5076,28 @@ function createChart(element, options = {}) {
|
|
|
4855
5076
|
ctx.restore();
|
|
4856
5077
|
if (labels.visible) {
|
|
4857
5078
|
const prevFont = ctx.font;
|
|
4858
|
-
|
|
4859
|
-
|
|
4860
|
-
const
|
|
5079
|
+
const legendFontSize = Math.max(8, axis.fontSize);
|
|
5080
|
+
ctx.font = `${legendFontSize}px ${mergedOptions.fontFamily}`;
|
|
5081
|
+
const legendTitle = paneInfo?.title ?? plugin.name;
|
|
5082
|
+
const legendValues = paneInfo?.legendValues ?? [];
|
|
4861
5083
|
const legendParts = [
|
|
4862
5084
|
legendTitle,
|
|
4863
5085
|
...legendValues.map((value) => value.text ?? (value.value === void 0 ? "" : formatPaneValue(value.value))).filter(Boolean)
|
|
4864
5086
|
].filter(Boolean);
|
|
5087
|
+
const legendText = legendParts.join(" ");
|
|
4865
5088
|
if (legendParts.length > 0) {
|
|
4866
|
-
drawText(
|
|
5089
|
+
drawText(legendText, chartLeft + 10, paneTop + 8, "left", "top", labels.indicatorTextColor);
|
|
4867
5090
|
}
|
|
4868
|
-
|
|
5091
|
+
if (hoveredPaneId === indicator.id) {
|
|
5092
|
+
drawPaneButtons(
|
|
5093
|
+
indicator.id,
|
|
5094
|
+
indicator.type,
|
|
5095
|
+
true,
|
|
5096
|
+
chartLeft + 10 + Math.ceil(measureTextWidth(legendText)) + 10,
|
|
5097
|
+
paneTop + 8 + legendFontSize / 2
|
|
5098
|
+
);
|
|
5099
|
+
}
|
|
5100
|
+
for (const label of paneInfo?.valueLabels ?? []) {
|
|
4869
5101
|
if (!labels.showIndicatorValueLabels) {
|
|
4870
5102
|
continue;
|
|
4871
5103
|
}
|
|
@@ -6077,6 +6309,54 @@ function createChart(element, options = {}) {
|
|
|
6077
6309
|
}
|
|
6078
6310
|
return "outside";
|
|
6079
6311
|
};
|
|
6312
|
+
const getPaneButtonHit = (x, y) => {
|
|
6313
|
+
for (const region of paneButtonRegions) {
|
|
6314
|
+
if (x >= region.x && x <= region.x + region.width && y >= region.y && y <= region.y + region.height) {
|
|
6315
|
+
return { id: region.id, type: region.type, action: region.action };
|
|
6316
|
+
}
|
|
6317
|
+
}
|
|
6318
|
+
return null;
|
|
6319
|
+
};
|
|
6320
|
+
const getPaneAt = (x, y) => {
|
|
6321
|
+
if (!drawState || x < drawState.chartLeft || x > drawState.chartRight) {
|
|
6322
|
+
return null;
|
|
6323
|
+
}
|
|
6324
|
+
for (const pane of paneLayoutInfos) {
|
|
6325
|
+
if (y >= pane.top && y <= pane.bottom) {
|
|
6326
|
+
return pane;
|
|
6327
|
+
}
|
|
6328
|
+
}
|
|
6329
|
+
return null;
|
|
6330
|
+
};
|
|
6331
|
+
const getPaneDividerHit = (x, y) => {
|
|
6332
|
+
if (!drawState || x < drawState.chartLeft || x > drawState.chartRight) {
|
|
6333
|
+
return null;
|
|
6334
|
+
}
|
|
6335
|
+
for (const pane of paneLayoutInfos) {
|
|
6336
|
+
if (pane.visible && Math.abs(y - pane.top) <= 4) {
|
|
6337
|
+
return { id: pane.id, heightPx: pane.bottom - pane.top };
|
|
6338
|
+
}
|
|
6339
|
+
}
|
|
6340
|
+
return null;
|
|
6341
|
+
};
|
|
6342
|
+
const handlePaneButtonAction = (hit) => {
|
|
6343
|
+
const indicator = indicators.find((entry) => entry.id === hit.id);
|
|
6344
|
+
if (!indicator) {
|
|
6345
|
+
return;
|
|
6346
|
+
}
|
|
6347
|
+
if (hit.action === "visibility") {
|
|
6348
|
+
indicator.visible = !indicator.visible;
|
|
6349
|
+
scheduleDraw();
|
|
6350
|
+
indicatorPaneActionHandler?.({ id: hit.id, type: hit.type, action: "visibility", visible: indicator.visible });
|
|
6351
|
+
return;
|
|
6352
|
+
}
|
|
6353
|
+
if (hit.action === "remove" && !indicatorPaneActionHandler) {
|
|
6354
|
+
indicators = indicators.filter((entry) => entry.id !== hit.id);
|
|
6355
|
+
scheduleDraw();
|
|
6356
|
+
return;
|
|
6357
|
+
}
|
|
6358
|
+
indicatorPaneActionHandler?.({ id: hit.id, type: hit.type, action: hit.action });
|
|
6359
|
+
};
|
|
6080
6360
|
const handleDrawingToolPointerDown = (x, y) => {
|
|
6081
6361
|
if (!activeDrawingTool || !drawState) {
|
|
6082
6362
|
return false;
|
|
@@ -6556,6 +6836,26 @@ function createChart(element, options = {}) {
|
|
|
6556
6836
|
setCrosshairPoint(null);
|
|
6557
6837
|
return;
|
|
6558
6838
|
}
|
|
6839
|
+
const paneButtonHit = getPaneButtonHit(point.x, point.y);
|
|
6840
|
+
if (paneButtonHit) {
|
|
6841
|
+
setCrosshairPoint(null);
|
|
6842
|
+
handlePaneButtonAction(paneButtonHit);
|
|
6843
|
+
return;
|
|
6844
|
+
}
|
|
6845
|
+
const paneDividerHit = getPaneDividerHit(point.x, point.y);
|
|
6846
|
+
if (paneDividerHit) {
|
|
6847
|
+
activePointerId = event.pointerId;
|
|
6848
|
+
paneDividerDrag = {
|
|
6849
|
+
id: paneDividerHit.id,
|
|
6850
|
+
startY: point.y,
|
|
6851
|
+
startHeightPx: paneDividerHit.heightPx,
|
|
6852
|
+
lastRatio: paneLayoutFullChartHeight > 0 ? paneDividerHit.heightPx / paneLayoutFullChartHeight : 0.2
|
|
6853
|
+
};
|
|
6854
|
+
capturePointer(event.pointerId);
|
|
6855
|
+
canvas.style.cursor = "row-resize";
|
|
6856
|
+
setCrosshairPoint(null);
|
|
6857
|
+
return;
|
|
6858
|
+
}
|
|
6559
6859
|
}
|
|
6560
6860
|
const region = getHitRegion(point.x, point.y);
|
|
6561
6861
|
if (region === "outside") {
|
|
@@ -6680,6 +6980,32 @@ function createChart(element, options = {}) {
|
|
|
6680
6980
|
return;
|
|
6681
6981
|
}
|
|
6682
6982
|
}
|
|
6983
|
+
if (paneDividerDrag) {
|
|
6984
|
+
if (activePointerId !== null && event.pointerId !== activePointerId) {
|
|
6985
|
+
return;
|
|
6986
|
+
}
|
|
6987
|
+
const fullHeight = paneLayoutFullChartHeight;
|
|
6988
|
+
if (fullHeight > 0) {
|
|
6989
|
+
const nextHeightPx = clamp(
|
|
6990
|
+
paneDividerDrag.startHeightPx + (paneDividerDrag.startY - point.y),
|
|
6991
|
+
48,
|
|
6992
|
+
Math.round(fullHeight * 0.45)
|
|
6993
|
+
);
|
|
6994
|
+
const nextRatio = nextHeightPx / fullHeight;
|
|
6995
|
+
if (Math.abs(nextRatio - paneDividerDrag.lastRatio) > 5e-4) {
|
|
6996
|
+
paneDividerDrag.lastRatio = nextRatio;
|
|
6997
|
+
const targetIndicator = indicators.find((entry) => entry.id === paneDividerDrag?.id);
|
|
6998
|
+
if (targetIndicator) {
|
|
6999
|
+
targetIndicator.paneHeightRatio = nextRatio;
|
|
7000
|
+
indicatorPaneHeightChangeHandler?.({ id: paneDividerDrag.id, paneHeightRatio: nextRatio, dragging: true });
|
|
7001
|
+
scheduleDraw();
|
|
7002
|
+
}
|
|
7003
|
+
}
|
|
7004
|
+
}
|
|
7005
|
+
canvas.style.cursor = "row-resize";
|
|
7006
|
+
setCrosshairPoint(null);
|
|
7007
|
+
return;
|
|
7008
|
+
}
|
|
6683
7009
|
if (orderDragState) {
|
|
6684
7010
|
if (activePointerId !== null && event.pointerId !== activePointerId) {
|
|
6685
7011
|
return;
|
|
@@ -6752,6 +7078,33 @@ function createChart(element, options = {}) {
|
|
|
6752
7078
|
setCrosshairPoint(null);
|
|
6753
7079
|
return;
|
|
6754
7080
|
}
|
|
7081
|
+
const hoveredPane = getPaneAt(point.x, point.y);
|
|
7082
|
+
const nextHoveredPaneId = hoveredPane?.id ?? null;
|
|
7083
|
+
if (nextHoveredPaneId !== hoveredPaneId) {
|
|
7084
|
+
hoveredPaneId = nextHoveredPaneId;
|
|
7085
|
+
scheduleDraw();
|
|
7086
|
+
}
|
|
7087
|
+
const paneButtonHover = getPaneButtonHit(point.x, point.y);
|
|
7088
|
+
const nextHoveredButton = paneButtonHover ? { id: paneButtonHover.id, action: paneButtonHover.action } : null;
|
|
7089
|
+
if ((nextHoveredButton?.id ?? null) !== (hoveredPaneButton?.id ?? null) || nextHoveredButton?.action !== hoveredPaneButton?.action) {
|
|
7090
|
+
hoveredPaneButton = nextHoveredButton;
|
|
7091
|
+
scheduleDraw();
|
|
7092
|
+
}
|
|
7093
|
+
if (paneButtonHover) {
|
|
7094
|
+
const indicatorForTitle = indicators.find((entry) => entry.id === paneButtonHover.id);
|
|
7095
|
+
canvas.title = paneButtonHover.action === "visibility" ? indicatorForTitle?.visible === false ? "Show" : "Hide" : paneButtonHover.action === "settings" ? "Settings" : paneButtonHover.action === "source" ? "View source" : "Remove";
|
|
7096
|
+
canvas.style.cursor = "pointer";
|
|
7097
|
+
setCrosshairPoint(null);
|
|
7098
|
+
return;
|
|
7099
|
+
}
|
|
7100
|
+
if (canvas.title) {
|
|
7101
|
+
canvas.title = "";
|
|
7102
|
+
}
|
|
7103
|
+
if (getPaneDividerHit(point.x, point.y)) {
|
|
7104
|
+
canvas.style.cursor = "row-resize";
|
|
7105
|
+
setCrosshairPoint(null);
|
|
7106
|
+
return;
|
|
7107
|
+
}
|
|
6755
7108
|
}
|
|
6756
7109
|
if (!activeDrawingTool && getDrawingHit(point.x, point.y)) {
|
|
6757
7110
|
const drawingHit = getDrawingHit(point.x, point.y);
|
|
@@ -6871,6 +7224,22 @@ function createChart(element, options = {}) {
|
|
|
6871
7224
|
drawingDragState = null;
|
|
6872
7225
|
emitDrawingsChange();
|
|
6873
7226
|
}
|
|
7227
|
+
if (paneDividerDrag) {
|
|
7228
|
+
indicatorPaneHeightChangeHandler?.({
|
|
7229
|
+
id: paneDividerDrag.id,
|
|
7230
|
+
paneHeightRatio: paneDividerDrag.lastRatio,
|
|
7231
|
+
dragging: false
|
|
7232
|
+
});
|
|
7233
|
+
paneDividerDrag = null;
|
|
7234
|
+
}
|
|
7235
|
+
if (event?.type === "pointerleave" && (hoveredPaneId !== null || hoveredPaneButton !== null)) {
|
|
7236
|
+
hoveredPaneId = null;
|
|
7237
|
+
hoveredPaneButton = null;
|
|
7238
|
+
if (canvas.title) {
|
|
7239
|
+
canvas.title = "";
|
|
7240
|
+
}
|
|
7241
|
+
scheduleDraw();
|
|
7242
|
+
}
|
|
6874
7243
|
const endedPlotDrag = isDragging && dragMode === "plot";
|
|
6875
7244
|
isDragging = false;
|
|
6876
7245
|
dragMode = null;
|
|
@@ -7216,6 +7585,12 @@ function createChart(element, options = {}) {
|
|
|
7216
7585
|
const onCrosshairPriceAction = (handler) => {
|
|
7217
7586
|
crosshairPriceActionHandler = handler;
|
|
7218
7587
|
};
|
|
7588
|
+
const onIndicatorPaneAction = (handler) => {
|
|
7589
|
+
indicatorPaneActionHandler = handler;
|
|
7590
|
+
};
|
|
7591
|
+
const onIndicatorPaneHeightChange = (handler) => {
|
|
7592
|
+
indicatorPaneHeightChangeHandler = handler;
|
|
7593
|
+
};
|
|
7219
7594
|
const setDoubleClickEnabled = (enabled) => {
|
|
7220
7595
|
doubleClickEnabled = enabled;
|
|
7221
7596
|
};
|
|
@@ -7421,6 +7796,8 @@ function createChart(element, options = {}) {
|
|
|
7421
7796
|
onChartClick,
|
|
7422
7797
|
onCrosshairMove,
|
|
7423
7798
|
onCrosshairPriceAction,
|
|
7799
|
+
onIndicatorPaneAction,
|
|
7800
|
+
onIndicatorPaneHeightChange,
|
|
7424
7801
|
zoomInX,
|
|
7425
7802
|
zoomOutX,
|
|
7426
7803
|
zoomInY,
|