hyperprop-charting-library 0.1.129 → 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 +382 -62
- package/dist/hyperprop-charting-library.d.ts +26 -1
- package/dist/hyperprop-charting-library.js +382 -62
- package/dist/index.cjs +382 -62
- package/dist/index.d.cts +26 -1
- package/dist/index.d.ts +26 -1
- package/dist/index.js +382 -62
- package/docs/API.md +9 -1
- package/package.json +1 -1
|
@@ -759,6 +759,40 @@ var fillBetweenSeries = (ctx, renderContext, upper, lower, color, opacity) => {
|
|
|
759
759
|
flushRun(renderContext.endIndex + 1);
|
|
760
760
|
ctx.restore();
|
|
761
761
|
};
|
|
762
|
+
var drawPaneHorizontalGrid = (ctx, renderContext, minValue, maxValue) => {
|
|
763
|
+
const grid = renderContext.grid;
|
|
764
|
+
if (!grid || !grid.horizontalLines) return;
|
|
765
|
+
const range = maxValue - minValue;
|
|
766
|
+
if (!(range > 0) || !Number.isFinite(range)) return;
|
|
767
|
+
const targetCount = Math.max(2, Math.round(renderContext.chartHeight / 42));
|
|
768
|
+
const targetStep = range / targetCount;
|
|
769
|
+
if (!(targetStep > 0) || !Number.isFinite(targetStep)) return;
|
|
770
|
+
const base = Math.pow(10, Math.floor(Math.log10(targetStep)));
|
|
771
|
+
const frac = targetStep / base;
|
|
772
|
+
const step = (frac <= 1 ? 1 : frac <= 2 ? 2 : frac <= 2.5 ? 2.5 : frac <= 5 ? 5 : 10) * base;
|
|
773
|
+
ctx.save();
|
|
774
|
+
ctx.globalAlpha = Math.min(1, Math.max(0, grid.opacity));
|
|
775
|
+
ctx.strokeStyle = grid.color;
|
|
776
|
+
ctx.lineWidth = 1;
|
|
777
|
+
ctx.setLineDash([]);
|
|
778
|
+
ctx.beginPath();
|
|
779
|
+
const firstTick = Math.ceil(minValue / step) * step;
|
|
780
|
+
const edgeInset = renderContext.chartHeight * 0.04;
|
|
781
|
+
for (let i = 0; i < 64; i += 1) {
|
|
782
|
+
const value = firstTick + i * step;
|
|
783
|
+
if (value > maxValue) break;
|
|
784
|
+
const ratio = (value - minValue) / range;
|
|
785
|
+
const y = renderContext.chartBottom - ratio * renderContext.chartHeight;
|
|
786
|
+
if (y > renderContext.chartBottom - edgeInset || y < renderContext.chartBottom - renderContext.chartHeight + edgeInset) {
|
|
787
|
+
continue;
|
|
788
|
+
}
|
|
789
|
+
const crispY = Math.round(y) + 0.5;
|
|
790
|
+
ctx.moveTo(renderContext.chartLeft, crispY);
|
|
791
|
+
ctx.lineTo(renderContext.chartRight, crispY);
|
|
792
|
+
}
|
|
793
|
+
ctx.stroke();
|
|
794
|
+
ctx.restore();
|
|
795
|
+
};
|
|
762
796
|
var drawSeparateSeries = (ctx, renderContext, values, color, width, minOverride, maxOverride, guideLines, options = {}) => {
|
|
763
797
|
const visible = [];
|
|
764
798
|
for (let index = renderContext.startIndex; index <= renderContext.endIndex; index += 1) {
|
|
@@ -770,6 +804,7 @@ var drawSeparateSeries = (ctx, renderContext, values, color, width, minOverride,
|
|
|
770
804
|
if (visible.length === 0) return void 0;
|
|
771
805
|
const minValue = minOverride ?? Math.min(...visible);
|
|
772
806
|
const maxValue = maxOverride ?? Math.max(...visible);
|
|
807
|
+
drawPaneHorizontalGrid(ctx, renderContext, minValue, maxValue);
|
|
773
808
|
const range = maxValue - minValue || 1;
|
|
774
809
|
const yFromValue = (value) => {
|
|
775
810
|
const ratio = (value - minValue) / range;
|
|
@@ -1164,7 +1199,7 @@ var BUILTIN_STDDEV_INDICATOR = {
|
|
|
1164
1199
|
name: "StdDev",
|
|
1165
1200
|
pane: "separate",
|
|
1166
1201
|
paneHeightRatio: 0.16,
|
|
1167
|
-
defaultInputs: { length: 20, source: "close", color: "#f97316", width: 2, showValueLine:
|
|
1202
|
+
defaultInputs: { length: 20, source: "close", color: "#f97316", width: 2, showValueLine: true },
|
|
1168
1203
|
draw: (ctx, renderContext, inputs) => {
|
|
1169
1204
|
const length = clampIndicatorLength(inputs.length, 20);
|
|
1170
1205
|
const values = withCachedSeries(
|
|
@@ -1175,7 +1210,7 @@ var BUILTIN_STDDEV_INDICATOR = {
|
|
|
1175
1210
|
return drawSeparateSeries(ctx, renderContext, values, inputs.color ?? "#f97316", Number(inputs.width) || 2, void 0, void 0, void 0, {
|
|
1176
1211
|
title: `StdDev ${length}`,
|
|
1177
1212
|
decimals: 2,
|
|
1178
|
-
valueLine: inputs.showValueLine
|
|
1213
|
+
valueLine: inputs.showValueLine !== false
|
|
1179
1214
|
});
|
|
1180
1215
|
}
|
|
1181
1216
|
};
|
|
@@ -1184,14 +1219,14 @@ var BUILTIN_ATR_INDICATOR = {
|
|
|
1184
1219
|
name: "ATR",
|
|
1185
1220
|
pane: "separate",
|
|
1186
1221
|
paneHeightRatio: 0.16,
|
|
1187
|
-
defaultInputs: { length: 14, color: "#eab308", width: 2, showValueLine:
|
|
1222
|
+
defaultInputs: { length: 14, color: "#eab308", width: 2, showValueLine: true },
|
|
1188
1223
|
draw: (ctx, renderContext, inputs) => {
|
|
1189
1224
|
const length = clampIndicatorLength(inputs.length, 14);
|
|
1190
1225
|
const values = withCachedSeries(`atr|${length}`, renderContext.data, () => computeAtrSeries(renderContext.data, length));
|
|
1191
1226
|
return drawSeparateSeries(ctx, renderContext, values, inputs.color ?? "#eab308", Number(inputs.width) || 2, void 0, void 0, void 0, {
|
|
1192
1227
|
title: `ATR ${length}`,
|
|
1193
1228
|
decimals: 2,
|
|
1194
|
-
valueLine: inputs.showValueLine
|
|
1229
|
+
valueLine: inputs.showValueLine !== false
|
|
1195
1230
|
});
|
|
1196
1231
|
}
|
|
1197
1232
|
};
|
|
@@ -1208,7 +1243,7 @@ var BUILTIN_RSI_INDICATOR = {
|
|
|
1208
1243
|
showValueLabel: true,
|
|
1209
1244
|
showGuideLines: true,
|
|
1210
1245
|
showScaleLabels: true,
|
|
1211
|
-
showValueLine:
|
|
1246
|
+
showValueLine: true
|
|
1212
1247
|
},
|
|
1213
1248
|
draw: (ctx, renderContext, inputs) => {
|
|
1214
1249
|
const length = clampIndicatorLength(inputs.length, 14);
|
|
@@ -1232,7 +1267,7 @@ var BUILTIN_RSI_INDICATOR = {
|
|
|
1232
1267
|
valueLabelBackgroundColor: "#9E9E9E",
|
|
1233
1268
|
valueLabelTextColor: "#0f172a",
|
|
1234
1269
|
showLegend: inputs.showLegend !== false,
|
|
1235
|
-
valueLine: inputs.showValueLine
|
|
1270
|
+
valueLine: inputs.showValueLine !== false
|
|
1236
1271
|
}
|
|
1237
1272
|
);
|
|
1238
1273
|
}
|
|
@@ -1289,6 +1324,7 @@ var drawSeparateMultiSeries = (ctx, renderContext, seriesList, options = {}) =>
|
|
|
1289
1324
|
const ratio = (value - minValue) / range;
|
|
1290
1325
|
return renderContext.chartBottom - ratio * renderContext.chartHeight;
|
|
1291
1326
|
};
|
|
1327
|
+
drawPaneHorizontalGrid(ctx, renderContext, minValue, maxValue);
|
|
1292
1328
|
if (options.guideLines && options.guideLines.length > 0) {
|
|
1293
1329
|
ctx.save();
|
|
1294
1330
|
ctx.strokeStyle = "rgba(148,163,184,0.35)";
|
|
@@ -1740,7 +1776,7 @@ var BUILTIN_MACD_INDICATOR = {
|
|
|
1740
1776
|
signalColor: "#ff6d00",
|
|
1741
1777
|
histUpColor: "#26a69a",
|
|
1742
1778
|
histDownColor: "#ef5350",
|
|
1743
|
-
showValueLine:
|
|
1779
|
+
showValueLine: true
|
|
1744
1780
|
},
|
|
1745
1781
|
draw: (ctx, renderContext, inputs) => {
|
|
1746
1782
|
const fast = clampIndicatorLength(inputs.fast, 12);
|
|
@@ -1770,7 +1806,7 @@ var BUILTIN_MACD_INDICATOR = {
|
|
|
1770
1806
|
guideLines: [0],
|
|
1771
1807
|
decimals: 2,
|
|
1772
1808
|
valueLabelSeriesIndex: 1,
|
|
1773
|
-
valueLines: inputs.showValueLine
|
|
1809
|
+
valueLines: inputs.showValueLine !== false
|
|
1774
1810
|
}
|
|
1775
1811
|
);
|
|
1776
1812
|
}
|
|
@@ -1780,7 +1816,7 @@ var BUILTIN_STOCHASTIC_INDICATOR = {
|
|
|
1780
1816
|
name: "Stoch",
|
|
1781
1817
|
pane: "separate",
|
|
1782
1818
|
paneHeightRatio: 0.18,
|
|
1783
|
-
defaultInputs: { kLength: 14, kSmoothing: 1, dLength: 3, kColor: "#2962ff", dColor: "#ff6d00", showValueLine:
|
|
1819
|
+
defaultInputs: { kLength: 14, kSmoothing: 1, dLength: 3, kColor: "#2962ff", dColor: "#ff6d00", showValueLine: true },
|
|
1784
1820
|
draw: (ctx, renderContext, inputs) => {
|
|
1785
1821
|
const kLength = clampIndicatorLength(inputs.kLength, 14);
|
|
1786
1822
|
const kSmoothing = clampIndicatorLength(inputs.kSmoothing, 1);
|
|
@@ -1804,7 +1840,7 @@ var BUILTIN_STOCHASTIC_INDICATOR = {
|
|
|
1804
1840
|
guideLines: [20, 80],
|
|
1805
1841
|
axisTicks: [0, 20, 50, 80, 100],
|
|
1806
1842
|
decimals: 2,
|
|
1807
|
-
valueLines: inputs.showValueLine
|
|
1843
|
+
valueLines: inputs.showValueLine !== false
|
|
1808
1844
|
}
|
|
1809
1845
|
);
|
|
1810
1846
|
}
|
|
@@ -1821,7 +1857,7 @@ var BUILTIN_STOCHRSI_INDICATOR = {
|
|
|
1821
1857
|
dSmoothing: 3,
|
|
1822
1858
|
kColor: "#2962ff",
|
|
1823
1859
|
dColor: "#ff6d00",
|
|
1824
|
-
showValueLine:
|
|
1860
|
+
showValueLine: true
|
|
1825
1861
|
},
|
|
1826
1862
|
draw: (ctx, renderContext, inputs) => {
|
|
1827
1863
|
const rsiLength = clampIndicatorLength(inputs.rsiLength, 14);
|
|
@@ -1847,7 +1883,7 @@ var BUILTIN_STOCHRSI_INDICATOR = {
|
|
|
1847
1883
|
guideLines: [20, 80],
|
|
1848
1884
|
axisTicks: [0, 20, 50, 80, 100],
|
|
1849
1885
|
decimals: 2,
|
|
1850
|
-
valueLines: inputs.showValueLine
|
|
1886
|
+
valueLines: inputs.showValueLine !== false
|
|
1851
1887
|
}
|
|
1852
1888
|
);
|
|
1853
1889
|
}
|
|
@@ -1863,7 +1899,7 @@ var BUILTIN_ADX_INDICATOR = {
|
|
|
1863
1899
|
plusDiColor: "#26a69a",
|
|
1864
1900
|
minusDiColor: "#ef5350",
|
|
1865
1901
|
showDi: true,
|
|
1866
|
-
showValueLine:
|
|
1902
|
+
showValueLine: true
|
|
1867
1903
|
},
|
|
1868
1904
|
draw: (ctx, renderContext, inputs) => {
|
|
1869
1905
|
const length = clampIndicatorLength(inputs.length, 14);
|
|
@@ -1886,7 +1922,7 @@ var BUILTIN_ADX_INDICATOR = {
|
|
|
1886
1922
|
minOverride: 0,
|
|
1887
1923
|
guideLines: [20],
|
|
1888
1924
|
decimals: 2,
|
|
1889
|
-
valueLines: inputs.showValueLine
|
|
1925
|
+
valueLines: inputs.showValueLine !== false
|
|
1890
1926
|
});
|
|
1891
1927
|
}
|
|
1892
1928
|
};
|
|
@@ -1895,14 +1931,14 @@ var BUILTIN_OBV_INDICATOR = {
|
|
|
1895
1931
|
name: "OBV",
|
|
1896
1932
|
pane: "separate",
|
|
1897
1933
|
paneHeightRatio: 0.16,
|
|
1898
|
-
defaultInputs: { color: "#2962ff", width: 2, showValueLine:
|
|
1934
|
+
defaultInputs: { color: "#2962ff", width: 2, showValueLine: true },
|
|
1899
1935
|
draw: (ctx, renderContext, inputs) => {
|
|
1900
1936
|
const values = withCachedSeries("obv", renderContext.data, () => computeObvSeries(renderContext.data));
|
|
1901
1937
|
return drawSeparateMultiSeries(
|
|
1902
1938
|
ctx,
|
|
1903
1939
|
renderContext,
|
|
1904
1940
|
[{ values, color: inputs.color ?? "#2962ff", width: Number(inputs.width) || 2, label: "OBV" }],
|
|
1905
|
-
{ title: "OBV", format: formatCompactNumber, valueLines: inputs.showValueLine
|
|
1941
|
+
{ title: "OBV", format: formatCompactNumber, valueLines: inputs.showValueLine !== false }
|
|
1906
1942
|
);
|
|
1907
1943
|
}
|
|
1908
1944
|
};
|
|
@@ -1911,7 +1947,7 @@ var BUILTIN_MFI_INDICATOR = {
|
|
|
1911
1947
|
name: "MFI",
|
|
1912
1948
|
pane: "separate",
|
|
1913
1949
|
paneHeightRatio: 0.16,
|
|
1914
|
-
defaultInputs: { length: 14, color: "#7e57c2", width: 2, showValueLine:
|
|
1950
|
+
defaultInputs: { length: 14, color: "#7e57c2", width: 2, showValueLine: true },
|
|
1915
1951
|
draw: (ctx, renderContext, inputs) => {
|
|
1916
1952
|
const length = clampIndicatorLength(inputs.length, 14);
|
|
1917
1953
|
const values = withCachedSeries(
|
|
@@ -1930,7 +1966,7 @@ var BUILTIN_MFI_INDICATOR = {
|
|
|
1930
1966
|
guideLines: [20, 80],
|
|
1931
1967
|
axisTicks: [0, 20, 50, 80, 100],
|
|
1932
1968
|
decimals: 2,
|
|
1933
|
-
valueLines: inputs.showValueLine
|
|
1969
|
+
valueLines: inputs.showValueLine !== false
|
|
1934
1970
|
}
|
|
1935
1971
|
);
|
|
1936
1972
|
}
|
|
@@ -1940,7 +1976,7 @@ var BUILTIN_CCI_INDICATOR = {
|
|
|
1940
1976
|
name: "CCI",
|
|
1941
1977
|
pane: "separate",
|
|
1942
1978
|
paneHeightRatio: 0.16,
|
|
1943
|
-
defaultInputs: { length: 20, color: "#2962ff", width: 2, showValueLine:
|
|
1979
|
+
defaultInputs: { length: 20, color: "#2962ff", width: 2, showValueLine: true },
|
|
1944
1980
|
draw: (ctx, renderContext, inputs) => {
|
|
1945
1981
|
const length = clampIndicatorLength(inputs.length, 20);
|
|
1946
1982
|
const values = withCachedSeries(
|
|
@@ -1952,7 +1988,7 @@ var BUILTIN_CCI_INDICATOR = {
|
|
|
1952
1988
|
ctx,
|
|
1953
1989
|
renderContext,
|
|
1954
1990
|
[{ values, color: inputs.color ?? "#2962ff", width: Number(inputs.width) || 2 }],
|
|
1955
|
-
{ title: `CCI ${length}`, guideLines: [-100, 0, 100], decimals: 2, valueLines: inputs.showValueLine
|
|
1991
|
+
{ title: `CCI ${length}`, guideLines: [-100, 0, 100], decimals: 2, valueLines: inputs.showValueLine !== false }
|
|
1956
1992
|
);
|
|
1957
1993
|
}
|
|
1958
1994
|
};
|
|
@@ -1961,7 +1997,7 @@ var BUILTIN_WILLIAMSR_INDICATOR = {
|
|
|
1961
1997
|
name: "Williams %R",
|
|
1962
1998
|
pane: "separate",
|
|
1963
1999
|
paneHeightRatio: 0.16,
|
|
1964
|
-
defaultInputs: { length: 14, color: "#7e57c2", width: 2, showValueLine:
|
|
2000
|
+
defaultInputs: { length: 14, color: "#7e57c2", width: 2, showValueLine: true },
|
|
1965
2001
|
draw: (ctx, renderContext, inputs) => {
|
|
1966
2002
|
const length = clampIndicatorLength(inputs.length, 14);
|
|
1967
2003
|
const values = withCachedSeries(
|
|
@@ -1980,7 +2016,7 @@ var BUILTIN_WILLIAMSR_INDICATOR = {
|
|
|
1980
2016
|
guideLines: [-80, -20],
|
|
1981
2017
|
axisTicks: [-100, -80, -50, -20, 0],
|
|
1982
2018
|
decimals: 2,
|
|
1983
|
-
valueLines: inputs.showValueLine
|
|
2019
|
+
valueLines: inputs.showValueLine !== false
|
|
1984
2020
|
}
|
|
1985
2021
|
);
|
|
1986
2022
|
}
|
|
@@ -1990,7 +2026,7 @@ var BUILTIN_ROC_INDICATOR = {
|
|
|
1990
2026
|
name: "ROC",
|
|
1991
2027
|
pane: "separate",
|
|
1992
2028
|
paneHeightRatio: 0.16,
|
|
1993
|
-
defaultInputs: { length: 9, color: "#2962ff", width: 2, showValueLine:
|
|
2029
|
+
defaultInputs: { length: 9, color: "#2962ff", width: 2, showValueLine: true },
|
|
1994
2030
|
draw: (ctx, renderContext, inputs) => {
|
|
1995
2031
|
const length = clampIndicatorLength(inputs.length, 9);
|
|
1996
2032
|
const values = withCachedSeries(
|
|
@@ -2002,7 +2038,7 @@ var BUILTIN_ROC_INDICATOR = {
|
|
|
2002
2038
|
ctx,
|
|
2003
2039
|
renderContext,
|
|
2004
2040
|
[{ values, color: inputs.color ?? "#2962ff", width: Number(inputs.width) || 2 }],
|
|
2005
|
-
{ title: `ROC ${length}`, includeZero: true, guideLines: [0], decimals: 2, valueLines: inputs.showValueLine
|
|
2041
|
+
{ title: `ROC ${length}`, includeZero: true, guideLines: [0], decimals: 2, valueLines: inputs.showValueLine !== false }
|
|
2006
2042
|
);
|
|
2007
2043
|
}
|
|
2008
2044
|
};
|
|
@@ -2011,7 +2047,7 @@ var BUILTIN_MOMENTUM_INDICATOR = {
|
|
|
2011
2047
|
name: "Momentum",
|
|
2012
2048
|
pane: "separate",
|
|
2013
2049
|
paneHeightRatio: 0.16,
|
|
2014
|
-
defaultInputs: { length: 10, color: "#2962ff", width: 2, showValueLine:
|
|
2050
|
+
defaultInputs: { length: 10, color: "#2962ff", width: 2, showValueLine: true },
|
|
2015
2051
|
draw: (ctx, renderContext, inputs) => {
|
|
2016
2052
|
const length = clampIndicatorLength(inputs.length, 10);
|
|
2017
2053
|
const values = withCachedSeries(
|
|
@@ -2023,7 +2059,7 @@ var BUILTIN_MOMENTUM_INDICATOR = {
|
|
|
2023
2059
|
ctx,
|
|
2024
2060
|
renderContext,
|
|
2025
2061
|
[{ values, color: inputs.color ?? "#2962ff", width: Number(inputs.width) || 2 }],
|
|
2026
|
-
{ title: `Mom ${length}`, includeZero: true, guideLines: [0], decimals: 2, valueLines: inputs.showValueLine
|
|
2062
|
+
{ title: `Mom ${length}`, includeZero: true, guideLines: [0], decimals: 2, valueLines: inputs.showValueLine !== false }
|
|
2027
2063
|
);
|
|
2028
2064
|
}
|
|
2029
2065
|
};
|
|
@@ -2447,6 +2483,14 @@ function createChart(element, options = {}) {
|
|
|
2447
2483
|
let watermarkImageReady = false;
|
|
2448
2484
|
let drawState = null;
|
|
2449
2485
|
let plotBottomForHit = 0;
|
|
2486
|
+
let paneLayoutFullChartHeight = 0;
|
|
2487
|
+
let paneLayoutInfos = [];
|
|
2488
|
+
let paneButtonRegions = [];
|
|
2489
|
+
let hoveredPaneId = null;
|
|
2490
|
+
let hoveredPaneButton = null;
|
|
2491
|
+
let paneDividerDrag = null;
|
|
2492
|
+
let indicatorPaneActionHandler = null;
|
|
2493
|
+
let indicatorPaneHeightChangeHandler = null;
|
|
2450
2494
|
let orderDragState = null;
|
|
2451
2495
|
let actionDragState = null;
|
|
2452
2496
|
let pointerDownInfo = null;
|
|
@@ -3548,20 +3592,24 @@ function createChart(element, options = {}) {
|
|
|
3548
3592
|
const watermark = { ...DEFAULT_WATERMARK_OPTIONS, ...mergedOptions.watermark ?? {} };
|
|
3549
3593
|
const paneGap = 0;
|
|
3550
3594
|
const separatePaneSpacing = 6;
|
|
3551
|
-
const
|
|
3595
|
+
const collapsedPaneHeight = 26;
|
|
3596
|
+
const activeSeparateIndicators = indicators.map((indicator) => ({ indicator, plugin: indicatorRegistry.get(indicator.type) })).filter(
|
|
3552
3597
|
(value) => value.plugin !== void 0 && (value.indicator.pane ?? value.plugin.pane ?? "overlay") === "separate"
|
|
3553
3598
|
).sort((a, b) => a.indicator.zIndex - b.indicator.zIndex);
|
|
3554
3599
|
const overlayIndicatorsForScale = indicators.filter((indicator) => indicator.visible).map((indicator) => ({ indicator, plugin: indicatorRegistry.get(indicator.type) })).filter(
|
|
3555
3600
|
(value) => value.plugin !== void 0 && (value.indicator.pane ?? value.plugin.pane ?? "overlay") === "overlay"
|
|
3556
3601
|
);
|
|
3557
3602
|
const separatePaneHeightDefaults = activeSeparateIndicators.map(({ indicator, plugin }) => {
|
|
3603
|
+
if (!indicator.visible) return collapsedPaneHeight;
|
|
3558
3604
|
const ratio = Math.min(0.45, Math.max(0.08, indicator.paneHeightRatio ?? plugin.paneHeightRatio ?? 0.22));
|
|
3559
3605
|
return Math.round(fullChartHeight * ratio);
|
|
3560
3606
|
});
|
|
3561
3607
|
const separatePaneDesiredTotal = separatePaneHeightDefaults.reduce((sum, value) => sum + value, 0) + Math.max(0, activeSeparateIndicators.length - 1) * separatePaneSpacing;
|
|
3562
3608
|
const maxSeparatePaneTotal = Math.max(0, fullChartHeight - 140);
|
|
3563
3609
|
const separatePaneScale = separatePaneDesiredTotal > 0 && separatePaneDesiredTotal > maxSeparatePaneTotal ? maxSeparatePaneTotal / separatePaneDesiredTotal : 1;
|
|
3564
|
-
const separatePaneHeights = separatePaneHeightDefaults.map(
|
|
3610
|
+
const separatePaneHeights = separatePaneHeightDefaults.map(
|
|
3611
|
+
(value, index) => activeSeparateIndicators[index].indicator.visible ? Math.max(48, Math.round(value * separatePaneScale)) : collapsedPaneHeight
|
|
3612
|
+
);
|
|
3565
3613
|
const separatePaneTotal = separatePaneHeights.reduce((sum, value) => sum + value, 0) + Math.max(0, activeSeparateIndicators.length - 1) * separatePaneSpacing;
|
|
3566
3614
|
const pricePaneGap = activeSeparateIndicators.length > 0 ? paneGap : 0;
|
|
3567
3615
|
const chartHeight = Math.max(120, fullChartHeight - separatePaneTotal - pricePaneGap);
|
|
@@ -4812,43 +4860,138 @@ function createChart(element, options = {}) {
|
|
|
4812
4860
|
ctx.restore();
|
|
4813
4861
|
}
|
|
4814
4862
|
}
|
|
4863
|
+
paneLayoutFullChartHeight = fullChartHeight;
|
|
4864
|
+
paneLayoutInfos = [];
|
|
4865
|
+
paneButtonRegions = [];
|
|
4815
4866
|
if (activeSeparateIndicators.length > 0) {
|
|
4816
4867
|
const xFromIndex = (index) => chartLeft + (index + 0.5 - xStart) / xSpan * chartWidth;
|
|
4817
4868
|
let paneTopCursor = chartBottom + paneGap;
|
|
4869
|
+
const paneButtonSize = 16;
|
|
4870
|
+
const paneButtonGap = 4;
|
|
4871
|
+
const drawPaneButtons = (indicatorId, indicatorType, indicatorVisible, startX, centerY) => {
|
|
4872
|
+
const actionList = [
|
|
4873
|
+
"visibility",
|
|
4874
|
+
"settings",
|
|
4875
|
+
"source",
|
|
4876
|
+
"remove"
|
|
4877
|
+
];
|
|
4878
|
+
let buttonX = startX;
|
|
4879
|
+
for (const action of actionList) {
|
|
4880
|
+
const buttonY = centerY - paneButtonSize / 2;
|
|
4881
|
+
const hovered = hoveredPaneButton?.id === indicatorId && hoveredPaneButton.action === action;
|
|
4882
|
+
const iconColor = labels.indicatorTextColor;
|
|
4883
|
+
ctx.save();
|
|
4884
|
+
ctx.fillStyle = hovered ? "rgba(148,163,184,0.30)" : "rgba(148,163,184,0.12)";
|
|
4885
|
+
fillRoundedRect(Math.round(buttonX), Math.round(buttonY), paneButtonSize, paneButtonSize, 4);
|
|
4886
|
+
ctx.strokeStyle = iconColor;
|
|
4887
|
+
ctx.fillStyle = iconColor;
|
|
4888
|
+
ctx.globalAlpha = hovered ? 1 : 0.75;
|
|
4889
|
+
ctx.lineWidth = 1.2;
|
|
4890
|
+
ctx.setLineDash([]);
|
|
4891
|
+
const cx = buttonX + paneButtonSize / 2;
|
|
4892
|
+
const cy = centerY;
|
|
4893
|
+
if (action === "visibility") {
|
|
4894
|
+
ctx.beginPath();
|
|
4895
|
+
ctx.ellipse(cx, cy, 4.6, 3, 0, 0, Math.PI * 2);
|
|
4896
|
+
ctx.stroke();
|
|
4897
|
+
ctx.beginPath();
|
|
4898
|
+
ctx.arc(cx, cy, 1.3, 0, Math.PI * 2);
|
|
4899
|
+
ctx.fill();
|
|
4900
|
+
if (!indicatorVisible) {
|
|
4901
|
+
ctx.beginPath();
|
|
4902
|
+
ctx.moveTo(cx - 5.2, cy + 4.6);
|
|
4903
|
+
ctx.lineTo(cx + 5.2, cy - 4.6);
|
|
4904
|
+
ctx.stroke();
|
|
4905
|
+
}
|
|
4906
|
+
} else if (action === "settings") {
|
|
4907
|
+
ctx.beginPath();
|
|
4908
|
+
ctx.arc(cx, cy, 3.4, 0, Math.PI * 2);
|
|
4909
|
+
ctx.stroke();
|
|
4910
|
+
for (let toothIndex = 0; toothIndex < 8; toothIndex += 1) {
|
|
4911
|
+
const angle = Math.PI / 4 * toothIndex;
|
|
4912
|
+
ctx.beginPath();
|
|
4913
|
+
ctx.moveTo(cx + Math.cos(angle) * 3.4, cy + Math.sin(angle) * 3.4);
|
|
4914
|
+
ctx.lineTo(cx + Math.cos(angle) * 5.2, cy + Math.sin(angle) * 5.2);
|
|
4915
|
+
ctx.stroke();
|
|
4916
|
+
}
|
|
4917
|
+
ctx.beginPath();
|
|
4918
|
+
ctx.arc(cx, cy, 1.1, 0, Math.PI * 2);
|
|
4919
|
+
ctx.fill();
|
|
4920
|
+
} else if (action === "source") {
|
|
4921
|
+
const prevSourceFont = ctx.font;
|
|
4922
|
+
ctx.font = `bold 9px ${mergedOptions.fontFamily}`;
|
|
4923
|
+
drawText("{}", cx, cy + 0.5, "center", "middle", iconColor);
|
|
4924
|
+
ctx.font = prevSourceFont;
|
|
4925
|
+
} else {
|
|
4926
|
+
ctx.beginPath();
|
|
4927
|
+
ctx.moveTo(cx - 3.4, cy - 3.4);
|
|
4928
|
+
ctx.lineTo(cx + 3.4, cy + 3.4);
|
|
4929
|
+
ctx.moveTo(cx + 3.4, cy - 3.4);
|
|
4930
|
+
ctx.lineTo(cx - 3.4, cy + 3.4);
|
|
4931
|
+
ctx.stroke();
|
|
4932
|
+
}
|
|
4933
|
+
ctx.restore();
|
|
4934
|
+
paneButtonRegions.push({
|
|
4935
|
+
id: indicatorId,
|
|
4936
|
+
type: indicatorType,
|
|
4937
|
+
action,
|
|
4938
|
+
x: buttonX,
|
|
4939
|
+
y: buttonY,
|
|
4940
|
+
width: paneButtonSize,
|
|
4941
|
+
height: paneButtonSize
|
|
4942
|
+
});
|
|
4943
|
+
buttonX += paneButtonSize + paneButtonGap;
|
|
4944
|
+
}
|
|
4945
|
+
};
|
|
4818
4946
|
activeSeparateIndicators.forEach(({ indicator, plugin }, paneIndex) => {
|
|
4819
4947
|
const paneHeight = separatePaneHeights[paneIndex] ?? 80;
|
|
4820
4948
|
const paneTop = paneTopCursor;
|
|
4821
4949
|
const paneBottom = paneTop + paneHeight;
|
|
4822
4950
|
paneTopCursor = paneBottom + separatePaneSpacing;
|
|
4823
|
-
|
|
4824
|
-
|
|
4825
|
-
|
|
4826
|
-
|
|
4827
|
-
|
|
4828
|
-
|
|
4829
|
-
|
|
4830
|
-
|
|
4831
|
-
|
|
4832
|
-
|
|
4833
|
-
|
|
4834
|
-
|
|
4835
|
-
|
|
4836
|
-
|
|
4837
|
-
|
|
4838
|
-
|
|
4839
|
-
|
|
4840
|
-
|
|
4841
|
-
|
|
4842
|
-
|
|
4843
|
-
|
|
4844
|
-
|
|
4845
|
-
|
|
4846
|
-
|
|
4847
|
-
|
|
4848
|
-
|
|
4849
|
-
|
|
4850
|
-
|
|
4851
|
-
|
|
4951
|
+
paneLayoutInfos.push({
|
|
4952
|
+
id: indicator.id,
|
|
4953
|
+
type: indicator.type,
|
|
4954
|
+
top: paneTop,
|
|
4955
|
+
bottom: paneBottom,
|
|
4956
|
+
visible: indicator.visible
|
|
4957
|
+
});
|
|
4958
|
+
let paneInfo;
|
|
4959
|
+
if (indicator.visible) {
|
|
4960
|
+
ctx.save();
|
|
4961
|
+
ctx.beginPath();
|
|
4962
|
+
ctx.rect(chartLeft + 1, paneTop + 1, Math.max(0, chartWidth - 2), Math.max(0, paneHeight - 2));
|
|
4963
|
+
ctx.clip();
|
|
4964
|
+
paneInfo = plugin.draw(
|
|
4965
|
+
ctx,
|
|
4966
|
+
{
|
|
4967
|
+
data,
|
|
4968
|
+
startIndex,
|
|
4969
|
+
endIndex,
|
|
4970
|
+
xStart,
|
|
4971
|
+
xSpan,
|
|
4972
|
+
chartLeft,
|
|
4973
|
+
chartRight,
|
|
4974
|
+
chartTop: paneTop,
|
|
4975
|
+
chartBottom: paneBottom,
|
|
4976
|
+
chartWidth,
|
|
4977
|
+
chartHeight: paneHeight,
|
|
4978
|
+
xFromIndex,
|
|
4979
|
+
yFromPrice: null,
|
|
4980
|
+
getCandleDirectionByIndex,
|
|
4981
|
+
getVolumeByIndex,
|
|
4982
|
+
candleSpacing,
|
|
4983
|
+
upColor: mergedOptions.upColor,
|
|
4984
|
+
downColor: mergedOptions.downColor,
|
|
4985
|
+
grid: {
|
|
4986
|
+
color: gridColor,
|
|
4987
|
+
opacity: gridOpacity,
|
|
4988
|
+
horizontalLines: grid.horizontalLines !== false
|
|
4989
|
+
}
|
|
4990
|
+
},
|
|
4991
|
+
indicator.inputs
|
|
4992
|
+
) ?? void 0;
|
|
4993
|
+
ctx.restore();
|
|
4994
|
+
}
|
|
4852
4995
|
ctx.save();
|
|
4853
4996
|
ctx.strokeStyle = axis.lineColor;
|
|
4854
4997
|
ctx.lineWidth = Math.max(1, axis.lineWidth);
|
|
@@ -4857,6 +5000,27 @@ function createChart(element, options = {}) {
|
|
|
4857
5000
|
ctx.lineTo(crisp(chartRight), crisp(paneTop));
|
|
4858
5001
|
ctx.stroke();
|
|
4859
5002
|
ctx.restore();
|
|
5003
|
+
if (!indicator.visible) {
|
|
5004
|
+
if (labels.visible) {
|
|
5005
|
+
const prevFont = ctx.font;
|
|
5006
|
+
ctx.font = `${Math.max(8, axis.fontSize)}px ${mergedOptions.fontFamily}`;
|
|
5007
|
+
const hiddenText = `${plugin.name} (hidden)`;
|
|
5008
|
+
const rowCenterY = (paneTop + paneBottom) / 2;
|
|
5009
|
+
ctx.save();
|
|
5010
|
+
ctx.globalAlpha = 0.55;
|
|
5011
|
+
drawText(hiddenText, chartLeft + 10, rowCenterY, "left", "middle", labels.indicatorTextColor);
|
|
5012
|
+
ctx.restore();
|
|
5013
|
+
drawPaneButtons(
|
|
5014
|
+
indicator.id,
|
|
5015
|
+
indicator.type,
|
|
5016
|
+
false,
|
|
5017
|
+
chartLeft + 10 + Math.ceil(measureTextWidth(hiddenText)) + 10,
|
|
5018
|
+
rowCenterY
|
|
5019
|
+
);
|
|
5020
|
+
ctx.font = prevFont;
|
|
5021
|
+
}
|
|
5022
|
+
return;
|
|
5023
|
+
}
|
|
4860
5024
|
const axisInfo = paneInfo?.axis;
|
|
4861
5025
|
if (axisInfo && Number.isFinite(axisInfo.min) && Number.isFinite(axisInfo.max) && axisInfo.max !== axisInfo.min) {
|
|
4862
5026
|
const paneRange = axisInfo.max - axisInfo.min;
|
|
@@ -4886,17 +5050,28 @@ function createChart(element, options = {}) {
|
|
|
4886
5050
|
ctx.restore();
|
|
4887
5051
|
if (labels.visible) {
|
|
4888
5052
|
const prevFont = ctx.font;
|
|
4889
|
-
|
|
4890
|
-
|
|
4891
|
-
const
|
|
5053
|
+
const legendFontSize = Math.max(8, axis.fontSize);
|
|
5054
|
+
ctx.font = `${legendFontSize}px ${mergedOptions.fontFamily}`;
|
|
5055
|
+
const legendTitle = paneInfo?.title ?? plugin.name;
|
|
5056
|
+
const legendValues = paneInfo?.legendValues ?? [];
|
|
4892
5057
|
const legendParts = [
|
|
4893
5058
|
legendTitle,
|
|
4894
5059
|
...legendValues.map((value) => value.text ?? (value.value === void 0 ? "" : formatPaneValue(value.value))).filter(Boolean)
|
|
4895
5060
|
].filter(Boolean);
|
|
5061
|
+
const legendText = legendParts.join(" ");
|
|
4896
5062
|
if (legendParts.length > 0) {
|
|
4897
|
-
drawText(
|
|
5063
|
+
drawText(legendText, chartLeft + 10, paneTop + 8, "left", "top", labels.indicatorTextColor);
|
|
4898
5064
|
}
|
|
4899
|
-
|
|
5065
|
+
if (hoveredPaneId === indicator.id) {
|
|
5066
|
+
drawPaneButtons(
|
|
5067
|
+
indicator.id,
|
|
5068
|
+
indicator.type,
|
|
5069
|
+
true,
|
|
5070
|
+
chartLeft + 10 + Math.ceil(measureTextWidth(legendText)) + 10,
|
|
5071
|
+
paneTop + 8 + legendFontSize / 2
|
|
5072
|
+
);
|
|
5073
|
+
}
|
|
5074
|
+
for (const label of paneInfo?.valueLabels ?? []) {
|
|
4900
5075
|
if (!labels.showIndicatorValueLabels) {
|
|
4901
5076
|
continue;
|
|
4902
5077
|
}
|
|
@@ -6108,6 +6283,54 @@ function createChart(element, options = {}) {
|
|
|
6108
6283
|
}
|
|
6109
6284
|
return "outside";
|
|
6110
6285
|
};
|
|
6286
|
+
const getPaneButtonHit = (x, y) => {
|
|
6287
|
+
for (const region of paneButtonRegions) {
|
|
6288
|
+
if (x >= region.x && x <= region.x + region.width && y >= region.y && y <= region.y + region.height) {
|
|
6289
|
+
return { id: region.id, type: region.type, action: region.action };
|
|
6290
|
+
}
|
|
6291
|
+
}
|
|
6292
|
+
return null;
|
|
6293
|
+
};
|
|
6294
|
+
const getPaneAt = (x, y) => {
|
|
6295
|
+
if (!drawState || x < drawState.chartLeft || x > drawState.chartRight) {
|
|
6296
|
+
return null;
|
|
6297
|
+
}
|
|
6298
|
+
for (const pane of paneLayoutInfos) {
|
|
6299
|
+
if (y >= pane.top && y <= pane.bottom) {
|
|
6300
|
+
return pane;
|
|
6301
|
+
}
|
|
6302
|
+
}
|
|
6303
|
+
return null;
|
|
6304
|
+
};
|
|
6305
|
+
const getPaneDividerHit = (x, y) => {
|
|
6306
|
+
if (!drawState || x < drawState.chartLeft || x > drawState.chartRight) {
|
|
6307
|
+
return null;
|
|
6308
|
+
}
|
|
6309
|
+
for (const pane of paneLayoutInfos) {
|
|
6310
|
+
if (pane.visible && Math.abs(y - pane.top) <= 4) {
|
|
6311
|
+
return { id: pane.id, heightPx: pane.bottom - pane.top };
|
|
6312
|
+
}
|
|
6313
|
+
}
|
|
6314
|
+
return null;
|
|
6315
|
+
};
|
|
6316
|
+
const handlePaneButtonAction = (hit) => {
|
|
6317
|
+
const indicator = indicators.find((entry) => entry.id === hit.id);
|
|
6318
|
+
if (!indicator) {
|
|
6319
|
+
return;
|
|
6320
|
+
}
|
|
6321
|
+
if (hit.action === "visibility") {
|
|
6322
|
+
indicator.visible = !indicator.visible;
|
|
6323
|
+
scheduleDraw();
|
|
6324
|
+
indicatorPaneActionHandler?.({ id: hit.id, type: hit.type, action: "visibility", visible: indicator.visible });
|
|
6325
|
+
return;
|
|
6326
|
+
}
|
|
6327
|
+
if (hit.action === "remove" && !indicatorPaneActionHandler) {
|
|
6328
|
+
indicators = indicators.filter((entry) => entry.id !== hit.id);
|
|
6329
|
+
scheduleDraw();
|
|
6330
|
+
return;
|
|
6331
|
+
}
|
|
6332
|
+
indicatorPaneActionHandler?.({ id: hit.id, type: hit.type, action: hit.action });
|
|
6333
|
+
};
|
|
6111
6334
|
const handleDrawingToolPointerDown = (x, y) => {
|
|
6112
6335
|
if (!activeDrawingTool || !drawState) {
|
|
6113
6336
|
return false;
|
|
@@ -6587,6 +6810,26 @@ function createChart(element, options = {}) {
|
|
|
6587
6810
|
setCrosshairPoint(null);
|
|
6588
6811
|
return;
|
|
6589
6812
|
}
|
|
6813
|
+
const paneButtonHit = getPaneButtonHit(point.x, point.y);
|
|
6814
|
+
if (paneButtonHit) {
|
|
6815
|
+
setCrosshairPoint(null);
|
|
6816
|
+
handlePaneButtonAction(paneButtonHit);
|
|
6817
|
+
return;
|
|
6818
|
+
}
|
|
6819
|
+
const paneDividerHit = getPaneDividerHit(point.x, point.y);
|
|
6820
|
+
if (paneDividerHit) {
|
|
6821
|
+
activePointerId = event.pointerId;
|
|
6822
|
+
paneDividerDrag = {
|
|
6823
|
+
id: paneDividerHit.id,
|
|
6824
|
+
startY: point.y,
|
|
6825
|
+
startHeightPx: paneDividerHit.heightPx,
|
|
6826
|
+
lastRatio: paneLayoutFullChartHeight > 0 ? paneDividerHit.heightPx / paneLayoutFullChartHeight : 0.2
|
|
6827
|
+
};
|
|
6828
|
+
capturePointer(event.pointerId);
|
|
6829
|
+
canvas.style.cursor = "row-resize";
|
|
6830
|
+
setCrosshairPoint(null);
|
|
6831
|
+
return;
|
|
6832
|
+
}
|
|
6590
6833
|
}
|
|
6591
6834
|
const region = getHitRegion(point.x, point.y);
|
|
6592
6835
|
if (region === "outside") {
|
|
@@ -6711,6 +6954,32 @@ function createChart(element, options = {}) {
|
|
|
6711
6954
|
return;
|
|
6712
6955
|
}
|
|
6713
6956
|
}
|
|
6957
|
+
if (paneDividerDrag) {
|
|
6958
|
+
if (activePointerId !== null && event.pointerId !== activePointerId) {
|
|
6959
|
+
return;
|
|
6960
|
+
}
|
|
6961
|
+
const fullHeight = paneLayoutFullChartHeight;
|
|
6962
|
+
if (fullHeight > 0) {
|
|
6963
|
+
const nextHeightPx = clamp(
|
|
6964
|
+
paneDividerDrag.startHeightPx + (paneDividerDrag.startY - point.y),
|
|
6965
|
+
48,
|
|
6966
|
+
Math.round(fullHeight * 0.45)
|
|
6967
|
+
);
|
|
6968
|
+
const nextRatio = nextHeightPx / fullHeight;
|
|
6969
|
+
if (Math.abs(nextRatio - paneDividerDrag.lastRatio) > 5e-4) {
|
|
6970
|
+
paneDividerDrag.lastRatio = nextRatio;
|
|
6971
|
+
const targetIndicator = indicators.find((entry) => entry.id === paneDividerDrag?.id);
|
|
6972
|
+
if (targetIndicator) {
|
|
6973
|
+
targetIndicator.paneHeightRatio = nextRatio;
|
|
6974
|
+
indicatorPaneHeightChangeHandler?.({ id: paneDividerDrag.id, paneHeightRatio: nextRatio, dragging: true });
|
|
6975
|
+
scheduleDraw();
|
|
6976
|
+
}
|
|
6977
|
+
}
|
|
6978
|
+
}
|
|
6979
|
+
canvas.style.cursor = "row-resize";
|
|
6980
|
+
setCrosshairPoint(null);
|
|
6981
|
+
return;
|
|
6982
|
+
}
|
|
6714
6983
|
if (orderDragState) {
|
|
6715
6984
|
if (activePointerId !== null && event.pointerId !== activePointerId) {
|
|
6716
6985
|
return;
|
|
@@ -6783,6 +7052,33 @@ function createChart(element, options = {}) {
|
|
|
6783
7052
|
setCrosshairPoint(null);
|
|
6784
7053
|
return;
|
|
6785
7054
|
}
|
|
7055
|
+
const hoveredPane = getPaneAt(point.x, point.y);
|
|
7056
|
+
const nextHoveredPaneId = hoveredPane?.id ?? null;
|
|
7057
|
+
if (nextHoveredPaneId !== hoveredPaneId) {
|
|
7058
|
+
hoveredPaneId = nextHoveredPaneId;
|
|
7059
|
+
scheduleDraw();
|
|
7060
|
+
}
|
|
7061
|
+
const paneButtonHover = getPaneButtonHit(point.x, point.y);
|
|
7062
|
+
const nextHoveredButton = paneButtonHover ? { id: paneButtonHover.id, action: paneButtonHover.action } : null;
|
|
7063
|
+
if ((nextHoveredButton?.id ?? null) !== (hoveredPaneButton?.id ?? null) || nextHoveredButton?.action !== hoveredPaneButton?.action) {
|
|
7064
|
+
hoveredPaneButton = nextHoveredButton;
|
|
7065
|
+
scheduleDraw();
|
|
7066
|
+
}
|
|
7067
|
+
if (paneButtonHover) {
|
|
7068
|
+
const indicatorForTitle = indicators.find((entry) => entry.id === paneButtonHover.id);
|
|
7069
|
+
canvas.title = paneButtonHover.action === "visibility" ? indicatorForTitle?.visible === false ? "Show" : "Hide" : paneButtonHover.action === "settings" ? "Settings" : paneButtonHover.action === "source" ? "View source" : "Remove";
|
|
7070
|
+
canvas.style.cursor = "pointer";
|
|
7071
|
+
setCrosshairPoint(null);
|
|
7072
|
+
return;
|
|
7073
|
+
}
|
|
7074
|
+
if (canvas.title) {
|
|
7075
|
+
canvas.title = "";
|
|
7076
|
+
}
|
|
7077
|
+
if (getPaneDividerHit(point.x, point.y)) {
|
|
7078
|
+
canvas.style.cursor = "row-resize";
|
|
7079
|
+
setCrosshairPoint(null);
|
|
7080
|
+
return;
|
|
7081
|
+
}
|
|
6786
7082
|
}
|
|
6787
7083
|
if (!activeDrawingTool && getDrawingHit(point.x, point.y)) {
|
|
6788
7084
|
const drawingHit = getDrawingHit(point.x, point.y);
|
|
@@ -6902,6 +7198,22 @@ function createChart(element, options = {}) {
|
|
|
6902
7198
|
drawingDragState = null;
|
|
6903
7199
|
emitDrawingsChange();
|
|
6904
7200
|
}
|
|
7201
|
+
if (paneDividerDrag) {
|
|
7202
|
+
indicatorPaneHeightChangeHandler?.({
|
|
7203
|
+
id: paneDividerDrag.id,
|
|
7204
|
+
paneHeightRatio: paneDividerDrag.lastRatio,
|
|
7205
|
+
dragging: false
|
|
7206
|
+
});
|
|
7207
|
+
paneDividerDrag = null;
|
|
7208
|
+
}
|
|
7209
|
+
if (event?.type === "pointerleave" && (hoveredPaneId !== null || hoveredPaneButton !== null)) {
|
|
7210
|
+
hoveredPaneId = null;
|
|
7211
|
+
hoveredPaneButton = null;
|
|
7212
|
+
if (canvas.title) {
|
|
7213
|
+
canvas.title = "";
|
|
7214
|
+
}
|
|
7215
|
+
scheduleDraw();
|
|
7216
|
+
}
|
|
6905
7217
|
const endedPlotDrag = isDragging && dragMode === "plot";
|
|
6906
7218
|
isDragging = false;
|
|
6907
7219
|
dragMode = null;
|
|
@@ -7247,6 +7559,12 @@ function createChart(element, options = {}) {
|
|
|
7247
7559
|
const onCrosshairPriceAction = (handler) => {
|
|
7248
7560
|
crosshairPriceActionHandler = handler;
|
|
7249
7561
|
};
|
|
7562
|
+
const onIndicatorPaneAction = (handler) => {
|
|
7563
|
+
indicatorPaneActionHandler = handler;
|
|
7564
|
+
};
|
|
7565
|
+
const onIndicatorPaneHeightChange = (handler) => {
|
|
7566
|
+
indicatorPaneHeightChangeHandler = handler;
|
|
7567
|
+
};
|
|
7250
7568
|
const setDoubleClickEnabled = (enabled) => {
|
|
7251
7569
|
doubleClickEnabled = enabled;
|
|
7252
7570
|
};
|
|
@@ -7452,6 +7770,8 @@ function createChart(element, options = {}) {
|
|
|
7452
7770
|
onChartClick,
|
|
7453
7771
|
onCrosshairMove,
|
|
7454
7772
|
onCrosshairPriceAction,
|
|
7773
|
+
onIndicatorPaneAction,
|
|
7774
|
+
onIndicatorPaneHeightChange,
|
|
7455
7775
|
zoomInX,
|
|
7456
7776
|
zoomOutX,
|
|
7457
7777
|
zoomInY,
|