hyperprop-charting-library 0.1.147 → 0.1.149
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 +165 -92
- package/dist/hyperprop-charting-library.d.ts +8 -0
- package/dist/hyperprop-charting-library.js +165 -92
- package/dist/index.cjs +165 -92
- package/dist/index.d.cts +8 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +165 -92
- package/docs/API.md +43 -0
- package/package.json +1 -1
|
@@ -4297,6 +4297,8 @@ function createChart(element, options = {}) {
|
|
|
4297
4297
|
let paneButtonRegions = [];
|
|
4298
4298
|
let hoveredPaneId = null;
|
|
4299
4299
|
let hoveredPaneButton = null;
|
|
4300
|
+
let legendRowRegions = [];
|
|
4301
|
+
let hoveredLegendId = null;
|
|
4300
4302
|
let paneDividerDrag = null;
|
|
4301
4303
|
let indicatorPaneActionHandler = null;
|
|
4302
4304
|
let indicatorPaneHeightChangeHandler = null;
|
|
@@ -4304,6 +4306,7 @@ function createChart(element, options = {}) {
|
|
|
4304
4306
|
let actionDragState = null;
|
|
4305
4307
|
let pointerDownInfo = null;
|
|
4306
4308
|
let crosshairPoint = null;
|
|
4309
|
+
let externalCrosshair = null;
|
|
4307
4310
|
let doubleClickEnabled = mergedOptions.doubleClickEnabled;
|
|
4308
4311
|
let doubleClickAction = mergedOptions.doubleClickAction;
|
|
4309
4312
|
setIndicatorLiveThrottleMs(mergedOptions.indicatorUpdate?.liveThrottleMs ?? 80);
|
|
@@ -5593,6 +5596,85 @@ function createChart(element, options = {}) {
|
|
|
5593
5596
|
ctx.closePath();
|
|
5594
5597
|
ctx.stroke();
|
|
5595
5598
|
};
|
|
5599
|
+
const INDICATOR_CONTROL_SIZE = 16;
|
|
5600
|
+
const INDICATOR_CONTROL_GAP = 4;
|
|
5601
|
+
const LEGEND_CONTROLS_WIDTH = (INDICATOR_CONTROL_SIZE + INDICATOR_CONTROL_GAP) * 4 + 8;
|
|
5602
|
+
const drawIndicatorControls = (indicatorId, indicatorType, indicatorVisible, startX, centerY) => {
|
|
5603
|
+
const labels = resolvedLabels;
|
|
5604
|
+
const actionList = [
|
|
5605
|
+
"visibility",
|
|
5606
|
+
"settings",
|
|
5607
|
+
"source",
|
|
5608
|
+
"remove"
|
|
5609
|
+
];
|
|
5610
|
+
let buttonX = startX;
|
|
5611
|
+
for (const action of actionList) {
|
|
5612
|
+
const buttonY = centerY - INDICATOR_CONTROL_SIZE / 2;
|
|
5613
|
+
const hovered = hoveredPaneButton?.id === indicatorId && hoveredPaneButton.action === action;
|
|
5614
|
+
const iconColor = labels.indicatorTextColor;
|
|
5615
|
+
ctx.save();
|
|
5616
|
+
ctx.fillStyle = hovered ? "rgba(148,163,184,0.30)" : "rgba(148,163,184,0.12)";
|
|
5617
|
+
fillRoundedRect(Math.round(buttonX), Math.round(buttonY), INDICATOR_CONTROL_SIZE, INDICATOR_CONTROL_SIZE, 4);
|
|
5618
|
+
ctx.strokeStyle = iconColor;
|
|
5619
|
+
ctx.fillStyle = iconColor;
|
|
5620
|
+
ctx.globalAlpha = hovered ? 1 : 0.75;
|
|
5621
|
+
ctx.lineWidth = 1.2;
|
|
5622
|
+
ctx.setLineDash([]);
|
|
5623
|
+
const cx = buttonX + INDICATOR_CONTROL_SIZE / 2;
|
|
5624
|
+
const cy = centerY;
|
|
5625
|
+
if (action === "visibility") {
|
|
5626
|
+
ctx.beginPath();
|
|
5627
|
+
ctx.ellipse(cx, cy, 4.6, 3, 0, 0, Math.PI * 2);
|
|
5628
|
+
ctx.stroke();
|
|
5629
|
+
ctx.beginPath();
|
|
5630
|
+
ctx.arc(cx, cy, 1.3, 0, Math.PI * 2);
|
|
5631
|
+
ctx.fill();
|
|
5632
|
+
if (!indicatorVisible) {
|
|
5633
|
+
ctx.beginPath();
|
|
5634
|
+
ctx.moveTo(cx - 5.2, cy + 4.6);
|
|
5635
|
+
ctx.lineTo(cx + 5.2, cy - 4.6);
|
|
5636
|
+
ctx.stroke();
|
|
5637
|
+
}
|
|
5638
|
+
} else if (action === "settings") {
|
|
5639
|
+
ctx.beginPath();
|
|
5640
|
+
ctx.arc(cx, cy, 3.4, 0, Math.PI * 2);
|
|
5641
|
+
ctx.stroke();
|
|
5642
|
+
for (let toothIndex = 0; toothIndex < 8; toothIndex += 1) {
|
|
5643
|
+
const angle = Math.PI / 4 * toothIndex;
|
|
5644
|
+
ctx.beginPath();
|
|
5645
|
+
ctx.moveTo(cx + Math.cos(angle) * 3.4, cy + Math.sin(angle) * 3.4);
|
|
5646
|
+
ctx.lineTo(cx + Math.cos(angle) * 5.2, cy + Math.sin(angle) * 5.2);
|
|
5647
|
+
ctx.stroke();
|
|
5648
|
+
}
|
|
5649
|
+
ctx.beginPath();
|
|
5650
|
+
ctx.arc(cx, cy, 1.1, 0, Math.PI * 2);
|
|
5651
|
+
ctx.fill();
|
|
5652
|
+
} else if (action === "source") {
|
|
5653
|
+
const prevSourceFont = ctx.font;
|
|
5654
|
+
ctx.font = `bold 9px ${mergedOptions.fontFamily}`;
|
|
5655
|
+
drawText("{}", cx, cy + 0.5, "center", "middle", iconColor);
|
|
5656
|
+
ctx.font = prevSourceFont;
|
|
5657
|
+
} else {
|
|
5658
|
+
ctx.beginPath();
|
|
5659
|
+
ctx.moveTo(cx - 3.4, cy - 3.4);
|
|
5660
|
+
ctx.lineTo(cx + 3.4, cy + 3.4);
|
|
5661
|
+
ctx.moveTo(cx + 3.4, cy - 3.4);
|
|
5662
|
+
ctx.lineTo(cx - 3.4, cy + 3.4);
|
|
5663
|
+
ctx.stroke();
|
|
5664
|
+
}
|
|
5665
|
+
ctx.restore();
|
|
5666
|
+
paneButtonRegions.push({
|
|
5667
|
+
id: indicatorId,
|
|
5668
|
+
type: indicatorType,
|
|
5669
|
+
action,
|
|
5670
|
+
x: buttonX,
|
|
5671
|
+
y: buttonY,
|
|
5672
|
+
width: INDICATOR_CONTROL_SIZE,
|
|
5673
|
+
height: INDICATOR_CONTROL_SIZE
|
|
5674
|
+
});
|
|
5675
|
+
buttonX += INDICATOR_CONTROL_SIZE + INDICATOR_CONTROL_GAP;
|
|
5676
|
+
}
|
|
5677
|
+
};
|
|
5596
5678
|
const drawMarkBadge = (x, y, radius, color, shape, label, textColor) => {
|
|
5597
5679
|
ctx.save();
|
|
5598
5680
|
ctx.fillStyle = color;
|
|
@@ -5673,6 +5755,8 @@ function createChart(element, options = {}) {
|
|
|
5673
5755
|
orderDragRegions = [];
|
|
5674
5756
|
alertRegions = [];
|
|
5675
5757
|
markRegions = [];
|
|
5758
|
+
paneButtonRegions = [];
|
|
5759
|
+
legendRowRegions = [];
|
|
5676
5760
|
crosshairPriceActionRegion = null;
|
|
5677
5761
|
const pixelRatio = getPixelRatio();
|
|
5678
5762
|
canvas.style.width = `${width}px`;
|
|
@@ -7761,87 +7845,10 @@ function createChart(element, options = {}) {
|
|
|
7761
7845
|
}
|
|
7762
7846
|
paneLayoutFullChartHeight = fullChartHeight;
|
|
7763
7847
|
paneLayoutInfos = [];
|
|
7764
|
-
paneButtonRegions = [];
|
|
7765
7848
|
if (activeSeparateIndicators.length > 0) {
|
|
7766
7849
|
const xFromIndex = (index) => chartLeft + (index + 0.5 - xStart) / xSpan * chartWidth;
|
|
7767
7850
|
let paneTopCursor = chartBottom + paneGap;
|
|
7768
|
-
const
|
|
7769
|
-
const paneButtonGap = 4;
|
|
7770
|
-
const drawPaneButtons = (indicatorId, indicatorType, indicatorVisible, startX, centerY) => {
|
|
7771
|
-
const actionList = [
|
|
7772
|
-
"visibility",
|
|
7773
|
-
"settings",
|
|
7774
|
-
"source",
|
|
7775
|
-
"remove"
|
|
7776
|
-
];
|
|
7777
|
-
let buttonX = startX;
|
|
7778
|
-
for (const action of actionList) {
|
|
7779
|
-
const buttonY = centerY - paneButtonSize / 2;
|
|
7780
|
-
const hovered = hoveredPaneButton?.id === indicatorId && hoveredPaneButton.action === action;
|
|
7781
|
-
const iconColor = labels.indicatorTextColor;
|
|
7782
|
-
ctx.save();
|
|
7783
|
-
ctx.fillStyle = hovered ? "rgba(148,163,184,0.30)" : "rgba(148,163,184,0.12)";
|
|
7784
|
-
fillRoundedRect(Math.round(buttonX), Math.round(buttonY), paneButtonSize, paneButtonSize, 4);
|
|
7785
|
-
ctx.strokeStyle = iconColor;
|
|
7786
|
-
ctx.fillStyle = iconColor;
|
|
7787
|
-
ctx.globalAlpha = hovered ? 1 : 0.75;
|
|
7788
|
-
ctx.lineWidth = 1.2;
|
|
7789
|
-
ctx.setLineDash([]);
|
|
7790
|
-
const cx = buttonX + paneButtonSize / 2;
|
|
7791
|
-
const cy = centerY;
|
|
7792
|
-
if (action === "visibility") {
|
|
7793
|
-
ctx.beginPath();
|
|
7794
|
-
ctx.ellipse(cx, cy, 4.6, 3, 0, 0, Math.PI * 2);
|
|
7795
|
-
ctx.stroke();
|
|
7796
|
-
ctx.beginPath();
|
|
7797
|
-
ctx.arc(cx, cy, 1.3, 0, Math.PI * 2);
|
|
7798
|
-
ctx.fill();
|
|
7799
|
-
if (!indicatorVisible) {
|
|
7800
|
-
ctx.beginPath();
|
|
7801
|
-
ctx.moveTo(cx - 5.2, cy + 4.6);
|
|
7802
|
-
ctx.lineTo(cx + 5.2, cy - 4.6);
|
|
7803
|
-
ctx.stroke();
|
|
7804
|
-
}
|
|
7805
|
-
} else if (action === "settings") {
|
|
7806
|
-
ctx.beginPath();
|
|
7807
|
-
ctx.arc(cx, cy, 3.4, 0, Math.PI * 2);
|
|
7808
|
-
ctx.stroke();
|
|
7809
|
-
for (let toothIndex = 0; toothIndex < 8; toothIndex += 1) {
|
|
7810
|
-
const angle = Math.PI / 4 * toothIndex;
|
|
7811
|
-
ctx.beginPath();
|
|
7812
|
-
ctx.moveTo(cx + Math.cos(angle) * 3.4, cy + Math.sin(angle) * 3.4);
|
|
7813
|
-
ctx.lineTo(cx + Math.cos(angle) * 5.2, cy + Math.sin(angle) * 5.2);
|
|
7814
|
-
ctx.stroke();
|
|
7815
|
-
}
|
|
7816
|
-
ctx.beginPath();
|
|
7817
|
-
ctx.arc(cx, cy, 1.1, 0, Math.PI * 2);
|
|
7818
|
-
ctx.fill();
|
|
7819
|
-
} else if (action === "source") {
|
|
7820
|
-
const prevSourceFont = ctx.font;
|
|
7821
|
-
ctx.font = `bold 9px ${mergedOptions.fontFamily}`;
|
|
7822
|
-
drawText("{}", cx, cy + 0.5, "center", "middle", iconColor);
|
|
7823
|
-
ctx.font = prevSourceFont;
|
|
7824
|
-
} else {
|
|
7825
|
-
ctx.beginPath();
|
|
7826
|
-
ctx.moveTo(cx - 3.4, cy - 3.4);
|
|
7827
|
-
ctx.lineTo(cx + 3.4, cy + 3.4);
|
|
7828
|
-
ctx.moveTo(cx + 3.4, cy - 3.4);
|
|
7829
|
-
ctx.lineTo(cx - 3.4, cy + 3.4);
|
|
7830
|
-
ctx.stroke();
|
|
7831
|
-
}
|
|
7832
|
-
ctx.restore();
|
|
7833
|
-
paneButtonRegions.push({
|
|
7834
|
-
id: indicatorId,
|
|
7835
|
-
type: indicatorType,
|
|
7836
|
-
action,
|
|
7837
|
-
x: buttonX,
|
|
7838
|
-
y: buttonY,
|
|
7839
|
-
width: paneButtonSize,
|
|
7840
|
-
height: paneButtonSize
|
|
7841
|
-
});
|
|
7842
|
-
buttonX += paneButtonSize + paneButtonGap;
|
|
7843
|
-
}
|
|
7844
|
-
};
|
|
7851
|
+
const drawPaneButtons = drawIndicatorControls;
|
|
7845
7852
|
activeSeparateIndicators.forEach(({ indicator, plugin }, paneIndex) => {
|
|
7846
7853
|
const paneHeight = separatePaneHeights[paneIndex] ?? 80;
|
|
7847
7854
|
const paneTop = paneTopCursor;
|
|
@@ -8343,26 +8350,56 @@ function createChart(element, options = {}) {
|
|
|
8343
8350
|
};
|
|
8344
8351
|
const labelEntries = activeOverlayIndicators.map(({ indicator, plugin }) => {
|
|
8345
8352
|
const inputValues = Object.entries(indicator.inputs).filter(([key, value]) => !LEGEND_EXCLUDED_INPUT_KEYS.has(key) && typeof value !== "boolean" && isLegendInputValue(value)).slice(0, 2).map(([, value]) => formatLegendValue(value));
|
|
8346
|
-
|
|
8347
|
-
|
|
8348
|
-
|
|
8349
|
-
if (labels.showIndicatorNames) {
|
|
8350
|
-
return plugin.name;
|
|
8351
|
-
}
|
|
8352
|
-
return inputValues.join(" ");
|
|
8353
|
-
}).filter((entry) => entry.length > 0);
|
|
8353
|
+
const text = labels.showIndicatorNames && labels.showIndicatorValues && inputValues.length > 0 ? `${plugin.name} ${inputValues.join(" ")}` : labels.showIndicatorNames ? plugin.name : inputValues.join(" ");
|
|
8354
|
+
return { id: indicator.id, type: indicator.type, visible: indicator.visible, text };
|
|
8355
|
+
}).filter((entry) => entry.text.length > 0);
|
|
8354
8356
|
if (labelEntries.length > 0) {
|
|
8355
8357
|
const prevFont = ctx.font;
|
|
8356
|
-
|
|
8357
|
-
|
|
8358
|
+
const legendFontSize = Math.max(8, axis.fontSize);
|
|
8359
|
+
ctx.font = `${legendFontSize}px ${mergedOptions.fontFamily}`;
|
|
8358
8360
|
const offsetX = Math.max(0, Number(labels.indicatorLegendOffsetX) || 0);
|
|
8359
8361
|
const offsetY = Math.max(0, Number(labels.indicatorLegendOffsetY) || 0);
|
|
8360
8362
|
const position = labels.indicatorLegendPosition;
|
|
8361
8363
|
const isRight = position === "top-right" || position === "bottom-right";
|
|
8362
8364
|
const isBottom = position === "bottom-left" || position === "bottom-right";
|
|
8363
8365
|
const legendX = isRight ? chartRight - offsetX : chartLeft + offsetX;
|
|
8364
|
-
const
|
|
8365
|
-
|
|
8366
|
+
const legendTop = isBottom ? chartBottom - offsetY : Math.max(chartTop + offsetY, dataLineBottom);
|
|
8367
|
+
const rowHeight = Math.round(legendFontSize * 1.55);
|
|
8368
|
+
labelEntries.forEach((entry, rowIndex) => {
|
|
8369
|
+
const rowTop = isBottom ? legendTop - (labelEntries.length - rowIndex) * rowHeight : legendTop + rowIndex * rowHeight;
|
|
8370
|
+
const rowCenter = rowTop + rowHeight / 2;
|
|
8371
|
+
const dimmed = entry.visible === false;
|
|
8372
|
+
ctx.save();
|
|
8373
|
+
if (dimmed) ctx.globalAlpha = 0.45;
|
|
8374
|
+
drawText(
|
|
8375
|
+
entry.text,
|
|
8376
|
+
legendX,
|
|
8377
|
+
rowCenter,
|
|
8378
|
+
isRight ? "right" : "left",
|
|
8379
|
+
"middle",
|
|
8380
|
+
labels.indicatorTextColor
|
|
8381
|
+
);
|
|
8382
|
+
ctx.restore();
|
|
8383
|
+
const textWidth = measureTextWidth(entry.text);
|
|
8384
|
+
const rowLeft = isRight ? legendX - textWidth : legendX;
|
|
8385
|
+
legendRowRegions.push({
|
|
8386
|
+
id: entry.id,
|
|
8387
|
+
type: entry.type,
|
|
8388
|
+
x: rowLeft,
|
|
8389
|
+
y: rowTop,
|
|
8390
|
+
width: textWidth + LEGEND_CONTROLS_WIDTH,
|
|
8391
|
+
height: rowHeight
|
|
8392
|
+
});
|
|
8393
|
+
if (hoveredLegendId === entry.id) {
|
|
8394
|
+
drawIndicatorControls(
|
|
8395
|
+
entry.id,
|
|
8396
|
+
entry.type,
|
|
8397
|
+
entry.visible !== false,
|
|
8398
|
+
isRight ? legendX + 6 : rowLeft + textWidth + 8,
|
|
8399
|
+
rowCenter
|
|
8400
|
+
);
|
|
8401
|
+
}
|
|
8402
|
+
});
|
|
8366
8403
|
ctx.font = prevFont;
|
|
8367
8404
|
}
|
|
8368
8405
|
}
|
|
@@ -8472,7 +8509,26 @@ function createChart(element, options = {}) {
|
|
|
8472
8509
|
crosshairPriceActionRegion = null;
|
|
8473
8510
|
const layout = overlayLayout;
|
|
8474
8511
|
const crosshair = resolvedCrosshair;
|
|
8475
|
-
if (!layout
|
|
8512
|
+
if (!layout) return;
|
|
8513
|
+
if (!crosshairPoint && externalCrosshair !== null && crosshair.visible) {
|
|
8514
|
+
const index = findNearestIndexForTimeMs(externalCrosshair.timeMs);
|
|
8515
|
+
if (index !== null) {
|
|
8516
|
+
const x = layout.chartLeft + (index + 0.5 - layout.xStart) / layout.xSpan * layout.chartWidth;
|
|
8517
|
+
if (x >= layout.chartLeft && x <= layout.chartRight) {
|
|
8518
|
+
ctx.save();
|
|
8519
|
+
ctx.globalAlpha = 0.55;
|
|
8520
|
+
ctx.strokeStyle = crosshair.color;
|
|
8521
|
+
ctx.lineWidth = Math.max(1, crosshair.width);
|
|
8522
|
+
applyDashPattern(crosshair.style, dashPatterns.dotted, dashPatterns.dashed);
|
|
8523
|
+
ctx.beginPath();
|
|
8524
|
+
ctx.moveTo(crisp(x), crisp(layout.chartTop));
|
|
8525
|
+
ctx.lineTo(crisp(x), crisp(layout.fullChartBottom));
|
|
8526
|
+
ctx.stroke();
|
|
8527
|
+
ctx.restore();
|
|
8528
|
+
}
|
|
8529
|
+
}
|
|
8530
|
+
}
|
|
8531
|
+
if (!crosshair.visible || !crosshairPoint) {
|
|
8476
8532
|
return;
|
|
8477
8533
|
}
|
|
8478
8534
|
const { chartLeft, chartTop, chartRight, chartBottom, chartWidth, chartHeight, fullChartBottom, yMin, yRange, xStart, xSpan: xSpan2 } = layout;
|
|
@@ -9034,6 +9090,9 @@ function createChart(element, options = {}) {
|
|
|
9034
9090
|
if (hits.length === 0) return null;
|
|
9035
9091
|
return hits.find((region) => region.part === "remove") ?? hits[0];
|
|
9036
9092
|
};
|
|
9093
|
+
const getLegendRowAt = (x, y) => legendRowRegions.find(
|
|
9094
|
+
(region) => x >= region.x && x <= region.x + region.width && y >= region.y && y <= region.y + region.height
|
|
9095
|
+
) ?? null;
|
|
9037
9096
|
const getMarkAt = (x, y) => {
|
|
9038
9097
|
const tolerance = touchInputActive ? Math.max(1, mergedOptions.touch?.hitToleranceScale ?? 2.2) : 1;
|
|
9039
9098
|
for (let index = markRegions.length - 1; index >= 0; index -= 1) {
|
|
@@ -10783,6 +10842,12 @@ function createChart(element, options = {}) {
|
|
|
10783
10842
|
setCrosshairPoint(null);
|
|
10784
10843
|
return;
|
|
10785
10844
|
}
|
|
10845
|
+
const legendRow = getLegendRowAt(point.x, point.y);
|
|
10846
|
+
const nextLegendId = legendRow?.id ?? null;
|
|
10847
|
+
if (nextLegendId !== hoveredLegendId) {
|
|
10848
|
+
hoveredLegendId = nextLegendId;
|
|
10849
|
+
scheduleDraw();
|
|
10850
|
+
}
|
|
10786
10851
|
const hoveredPane = getPaneAt(point.x, point.y);
|
|
10787
10852
|
const nextHoveredPaneId = hoveredPane?.id ?? null;
|
|
10788
10853
|
if (nextHoveredPaneId !== hoveredPaneId) {
|
|
@@ -11001,10 +11066,11 @@ function createChart(element, options = {}) {
|
|
|
11001
11066
|
});
|
|
11002
11067
|
paneDividerDrag = null;
|
|
11003
11068
|
}
|
|
11004
|
-
if (event?.type === "pointerleave" && (hoveredPaneId !== null || hoveredPaneButton !== null || hoveredAlertId !== null || hoveredMarkKey !== null)) {
|
|
11069
|
+
if (event?.type === "pointerleave" && (hoveredPaneId !== null || hoveredPaneButton !== null || hoveredAlertId !== null || hoveredMarkKey !== null || hoveredLegendId !== null)) {
|
|
11005
11070
|
hoveredPaneId = null;
|
|
11006
11071
|
hoveredPaneButton = null;
|
|
11007
11072
|
hoveredAlertId = null;
|
|
11073
|
+
hoveredLegendId = null;
|
|
11008
11074
|
if (hoveredMarkKey !== null) {
|
|
11009
11075
|
hoveredMarkKey = null;
|
|
11010
11076
|
markHoverHandler?.(null);
|
|
@@ -11944,6 +12010,12 @@ function createChart(element, options = {}) {
|
|
|
11944
12010
|
const onAlertAction = (handler) => {
|
|
11945
12011
|
alertActionHandler = handler;
|
|
11946
12012
|
};
|
|
12013
|
+
const setExternalCrosshair = (point) => {
|
|
12014
|
+
const nextMs = point && Number.isFinite(point.timeMs) ? point.timeMs : null;
|
|
12015
|
+
if (nextMs === (externalCrosshair?.timeMs ?? null)) return;
|
|
12016
|
+
externalCrosshair = nextMs === null ? null : { timeMs: nextMs };
|
|
12017
|
+
scheduleDraw({ overlayOnly: true });
|
|
12018
|
+
};
|
|
11947
12019
|
const setTimezone = (timezone) => {
|
|
11948
12020
|
timezoneSetting = timezone || "local";
|
|
11949
12021
|
zoneClock = createZoneClock(timezoneSetting);
|
|
@@ -12254,6 +12326,7 @@ function createChart(element, options = {}) {
|
|
|
12254
12326
|
saveState,
|
|
12255
12327
|
loadState,
|
|
12256
12328
|
takeScreenshot,
|
|
12329
|
+
setExternalCrosshair,
|
|
12257
12330
|
setTimezone,
|
|
12258
12331
|
getTimezone,
|
|
12259
12332
|
setTimeFormat,
|
|
@@ -1030,6 +1030,14 @@ interface ChartInstance {
|
|
|
1030
1030
|
* the crosshair tag and day/session boundaries move. Unknown ids fall back
|
|
1031
1031
|
* to local time rather than throwing.
|
|
1032
1032
|
*/
|
|
1033
|
+
/**
|
|
1034
|
+
* Mirror a sibling chart's crosshair in a multi-chart layout. Matching is
|
|
1035
|
+
* by timestamp, so charts on different intervals or instruments still line
|
|
1036
|
+
* up. Pass null to clear.
|
|
1037
|
+
*/
|
|
1038
|
+
setExternalCrosshair: (point: {
|
|
1039
|
+
timeMs: number;
|
|
1040
|
+
} | null) => void;
|
|
1033
1041
|
setTimezone: (timezone: ChartTimezone) => void;
|
|
1034
1042
|
getTimezone: () => ChartTimezone;
|
|
1035
1043
|
/** Switch rendered clock times between 24-hour and 12-hour. */
|