hyperprop-charting-library 0.1.8 → 0.1.9

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.
@@ -24,15 +24,15 @@ __export(index_exports, {
24
24
  });
25
25
  module.exports = __toCommonJS(index_exports);
26
26
  var DEFAULT_GRID_OPTIONS = {
27
- color: "#e2e8f0",
28
- opacity: 0.9,
27
+ color: "#2b2f38",
28
+ opacity: 0.38,
29
29
  horizontalLines: true,
30
30
  verticalLines: true,
31
31
  horizontalTickCount: 5
32
32
  };
33
33
  var DEFAULT_AXIS_OPTIONS = {
34
- lineColor: "#94a3b8",
35
- textColor: "#94a3b8",
34
+ lineColor: "#3b3f47",
35
+ textColor: "#a9adb6",
36
36
  fontSize: 12,
37
37
  lineWidth: 1
38
38
  };
@@ -42,24 +42,39 @@ var DEFAULT_CROSSHAIR_OPTIONS = {
42
42
  width: 1,
43
43
  style: "dotted",
44
44
  showHorizontal: true,
45
- showVertical: true
45
+ showVertical: true,
46
+ showPriceLabel: true,
47
+ showTimeLabel: true,
48
+ timeLabelFormat: "auto",
49
+ labelBackgroundColor: "#0b1220",
50
+ labelTextColor: "#cbd5e1",
51
+ labelBorderRadius: 3,
52
+ labelBorderColor: "#94a3b8",
53
+ labelBorderWidth: 1,
54
+ labelBorderStyle: "solid"
46
55
  };
47
56
  var DEFAULT_WATERMARK_OPTIONS = {
48
57
  visible: false,
49
58
  text: "",
50
- color: "#94a3b8",
51
- opacity: 0.2,
59
+ color: "#81858d",
60
+ opacity: 0.14,
52
61
  fontSize: 92,
53
62
  fontWeight: 700,
54
- thickness: 0
63
+ thickness: 0,
64
+ imageSrc: "",
65
+ imageScale: 1,
66
+ imageMaxWidthRatio: 0.42,
67
+ imageMaxHeightRatio: 0.3,
68
+ imageTintColor: "",
69
+ imageTintOpacity: 1
55
70
  };
56
71
  var DEFAULT_PRICE_LINE_OPTIONS = {
57
72
  visible: true,
58
73
  style: "solid",
59
74
  thickness: 1,
60
- color: "#f59e0b",
61
- labelBackgroundColor: "#f59e0b",
62
- labelTextColor: "#0f172a",
75
+ color: "#38bdf8",
76
+ labelBackgroundColor: "#0b1220",
77
+ labelTextColor: "#60a5fa",
63
78
  labelBorderRadius: 3,
64
79
  showLabel: true
65
80
  };
@@ -68,9 +83,9 @@ var DEFAULT_ORDER_LINE_OPTIONS = {
68
83
  behavior: "static",
69
84
  style: "solid",
70
85
  thickness: 1,
71
- color: "#f59e0b",
72
- labelBackgroundColor: "#f59e0b",
73
- labelTextColor: "#0f172a",
86
+ color: "rgba(59,130,246,0.8)",
87
+ labelBackgroundColor: "#0b1220",
88
+ labelTextColor: "#60a5fa",
74
89
  labelBorderRadius: 3,
75
90
  showCloseButton: true,
76
91
  widgetPosition: "left",
@@ -97,12 +112,17 @@ var DEFAULT_ORDER_LINE_OPTIONS = {
97
112
  var DEFAULT_OPTIONS = {
98
113
  width: 720,
99
114
  height: 360,
100
- backgroundColor: "#ffffff",
101
- axisColor: "#94a3b8",
115
+ backgroundColor: "#101114",
116
+ axisColor: "#7f8289",
102
117
  axis: DEFAULT_AXIS_OPTIONS,
103
- upColor: "#16a34a",
104
- downColor: "#dc2626",
105
- gridColor: "#e2e8f0",
118
+ priceDecimals: 2,
119
+ initialViewport: "latest",
120
+ initialVisibleBars: 60,
121
+ rightEdgePaddingBars: 2,
122
+ preserveViewportOnDataUpdate: true,
123
+ upColor: "#2fb171",
124
+ downColor: "#d35a5a",
125
+ gridColor: "#252932",
106
126
  fontFamily: "Inter, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, sans-serif",
107
127
  candleBodyWidthRatio: 0.7,
108
128
  candleMinWidth: 0.5,
@@ -118,12 +138,12 @@ var DEFAULT_OPTIONS = {
118
138
  orderLines: [],
119
139
  tickerLine: {
120
140
  visible: true,
121
- style: "dashed",
141
+ style: "dotted",
122
142
  thickness: 1,
123
- color: "#22c55e",
124
- labelBackgroundColor: "#22c55e",
143
+ color: "#38bdf8",
144
+ labelBackgroundColor: "#38bdf8",
125
145
  labelTextColor: "#0b1220",
126
- labelBorderRadius: 6
146
+ labelBorderRadius: 3
127
147
  }
128
148
  };
129
149
  function createChart(element, options = {}) {
@@ -165,6 +185,7 @@ function createChart(element, options = {}) {
165
185
  }));
166
186
  let orderActionHandler = null;
167
187
  let chartClickHandler = null;
188
+ let crosshairMoveHandler = null;
168
189
  let orderActionRegions = [];
169
190
  let orderDragRegions = [];
170
191
  let generatedPriceLineId = 1;
@@ -177,6 +198,9 @@ function createChart(element, options = {}) {
177
198
  let yMaxOverride = null;
178
199
  let autoYMin = null;
179
200
  let autoYMax = null;
201
+ let watermarkImageSrc = null;
202
+ let watermarkImage = null;
203
+ let watermarkImageReady = false;
180
204
  let drawState = null;
181
205
  let orderDragState = null;
182
206
  let actionDragState = null;
@@ -195,13 +219,36 @@ function createChart(element, options = {}) {
195
219
  element.appendChild(canvas);
196
220
  const margin = { top: 16, right: 72, bottom: 34, left: 12 };
197
221
  const maxPanBars = 1e6;
198
- const rightEdgePaddingBars = 2;
222
+ const rightEdgePaddingBars = Math.max(0, mergedOptions.rightEdgePaddingBars);
199
223
  const getPixelRatio = () => {
200
224
  if (typeof window === "undefined") {
201
225
  return 1;
202
226
  }
203
227
  return Math.max(1, window.devicePixelRatio || 1);
204
228
  };
229
+ const ensureWatermarkImage = (src) => {
230
+ if (src === watermarkImageSrc) {
231
+ return;
232
+ }
233
+ watermarkImageSrc = src;
234
+ watermarkImageReady = false;
235
+ watermarkImage = null;
236
+ if (!src) {
237
+ return;
238
+ }
239
+ const image = new Image();
240
+ image.crossOrigin = "anonymous";
241
+ image.onload = () => {
242
+ watermarkImage = image;
243
+ watermarkImageReady = true;
244
+ draw();
245
+ };
246
+ image.onerror = () => {
247
+ watermarkImage = null;
248
+ watermarkImageReady = false;
249
+ };
250
+ image.src = src;
251
+ };
205
252
  const crisp = (value) => Math.round(value) + 0.5;
206
253
  const clamp = (value, min, max) => {
207
254
  return Math.min(max, Math.max(min, value));
@@ -225,8 +272,13 @@ function createChart(element, options = {}) {
225
272
  xSpan = 60;
226
273
  return;
227
274
  }
228
- xSpan = Math.min(60, count);
229
- xCenter = count - xSpan / 2;
275
+ const requestedVisibleBars = Math.max(5, Math.floor(mergedOptions.initialVisibleBars));
276
+ xSpan = Math.min(requestedVisibleBars, Math.max(5, count));
277
+ if (mergedOptions.initialViewport === "center") {
278
+ xCenter = count / 2;
279
+ } else {
280
+ xCenter = count - xSpan / 2 + rightEdgePaddingBars;
281
+ }
230
282
  clampXViewport();
231
283
  };
232
284
  const getYBounds = () => {
@@ -266,13 +318,8 @@ function createChart(element, options = {}) {
266
318
  return { min: nextMin, max: nextMax };
267
319
  };
268
320
  const formatPrice = (price) => {
269
- if (price >= 1e3) {
270
- return price.toFixed(0);
271
- }
272
- if (price >= 100) {
273
- return price.toFixed(1);
274
- }
275
- return price.toFixed(2);
321
+ const decimals = clamp(Math.round(mergedOptions.priceDecimals), 0, 8);
322
+ return price.toFixed(decimals);
276
323
  };
277
324
  const parseData = (nextData) => {
278
325
  return nextData.map((point) => ({
@@ -326,6 +373,42 @@ function createChart(element, options = {}) {
326
373
  const extra = index - (data.length - 1);
327
374
  return new Date(last.time.getTime() + extra * stepMs);
328
375
  };
376
+ const formatHoverTimeLabel = (time, mode) => {
377
+ if (mode === "time") {
378
+ return time.toLocaleTimeString(void 0, {
379
+ hour: "2-digit",
380
+ minute: "2-digit",
381
+ hour12: false
382
+ });
383
+ }
384
+ if (mode === "datetime") {
385
+ return time.toLocaleString(void 0, {
386
+ month: "short",
387
+ day: "numeric",
388
+ hour: "2-digit",
389
+ minute: "2-digit",
390
+ hour12: false
391
+ });
392
+ }
393
+ if (mode === "date") {
394
+ return time.toLocaleDateString(void 0, {
395
+ month: "short",
396
+ day: "numeric"
397
+ });
398
+ }
399
+ const stepMs = getTimeStepMs();
400
+ if (stepMs < 24 * 60 * 60 * 1e3) {
401
+ return time.toLocaleTimeString(void 0, {
402
+ hour: "2-digit",
403
+ minute: "2-digit",
404
+ hour12: false
405
+ });
406
+ }
407
+ return time.toLocaleDateString(void 0, {
408
+ month: "short",
409
+ day: "numeric"
410
+ });
411
+ };
329
412
  const drawText = (text, x, y, align = "left", baseline = "alphabetic", color = mergedOptions.axis?.textColor ?? mergedOptions.axisColor) => {
330
413
  ctx.fillStyle = color;
331
414
  ctx.textAlign = align;
@@ -389,7 +472,7 @@ function createChart(element, options = {}) {
389
472
  return;
390
473
  }
391
474
  const lineY = clamp(yFromPrice(renderPrice), chartTop + 1, chartBottom - 1);
392
- const color = mergedLine.color ?? (mergedLine.side === "buy" ? mergedOptions.upColor : mergedLine.side === "sell" ? mergedOptions.downColor : "#f59e0b");
475
+ const color = line.color ?? (mergedLine.type === "takeProfit" ? "rgba(45,212,191,0.86)" : mergedLine.type === "stop" ? "rgba(245,158,11,0.86)" : "rgba(59,130,246,0.8)");
393
476
  if (Number.isFinite(mergedLine.fillToPrice)) {
394
477
  const fillY = clamp(yFromPrice(mergedLine.fillToPrice), chartTop + 1, chartBottom - 1);
395
478
  const topY = Math.min(lineY, fillY);
@@ -500,7 +583,7 @@ function createChart(element, options = {}) {
500
583
  const borderRadius = Math.max(0, mergedLine.labelBorderRadius);
501
584
  const widgetBackground = mergedOptions.backgroundColor;
502
585
  const widgetBorder = color;
503
- const textColor = mergedLine.labelTextColor;
586
+ const textColor = line.labelTextColor ?? (mergedLine.type === "takeProfit" ? "#5eead4" : mergedLine.type === "stop" ? "#fbbf24" : mergedLine.labelTextColor);
504
587
  const mainWidgetX = leftWidgetX + actionButtonsTotalWidth + actionButtonsGap;
505
588
  ctx.fillStyle = widgetBackground;
506
589
  fillRoundedRect(Math.round(mainWidgetX), Math.round(labelY), mainWidgetWidth, labelHeight, borderRadius);
@@ -750,6 +833,31 @@ function createChart(element, options = {}) {
750
833
  const yFromPrice = (price) => {
751
834
  return chartBottom - (price - yMin) / yRange * chartHeight;
752
835
  };
836
+ if (watermark.visible && watermark.imageSrc.trim().length > 0) {
837
+ ensureWatermarkImage(watermark.imageSrc.trim());
838
+ if (watermarkImageReady && watermarkImage) {
839
+ const maxW = chartWidth * clamp(watermark.imageMaxWidthRatio, 0.05, 1);
840
+ const maxH = chartHeight * clamp(watermark.imageMaxHeightRatio, 0.05, 1);
841
+ const naturalW = Math.max(1, watermarkImage.naturalWidth || watermarkImage.width);
842
+ const naturalH = Math.max(1, watermarkImage.naturalHeight || watermarkImage.height);
843
+ const containScale = Math.min(maxW / naturalW, maxH / naturalH);
844
+ const scale = Math.max(0.05, containScale * Math.max(0.05, watermark.imageScale));
845
+ const drawW = naturalW * scale;
846
+ const drawH = naturalH * scale;
847
+ const drawX = chartLeft + (chartWidth - drawW) / 2;
848
+ const drawY = chartTop + (chartHeight - drawH) / 2;
849
+ ctx.save();
850
+ ctx.globalAlpha = clamp(watermark.opacity, 0, 1);
851
+ ctx.drawImage(watermarkImage, drawX, drawY, drawW, drawH);
852
+ if (watermark.imageTintColor.trim().length > 0) {
853
+ ctx.globalCompositeOperation = "source-atop";
854
+ ctx.globalAlpha = clamp(watermark.opacity, 0, 1) * clamp(watermark.imageTintOpacity, 0, 1);
855
+ ctx.fillStyle = watermark.imageTintColor;
856
+ ctx.fillRect(drawX, drawY, drawW, drawH);
857
+ }
858
+ ctx.restore();
859
+ }
860
+ }
753
861
  if (watermark.visible && watermark.text.trim().length > 0) {
754
862
  ctx.save();
755
863
  ctx.globalAlpha = clamp(watermark.opacity, 0, 1);
@@ -947,6 +1055,61 @@ function createChart(element, options = {}) {
947
1055
  });
948
1056
  drawText(timeLabel, x, chartBottom + 8, "center", "top", axis.textColor);
949
1057
  }
1058
+ if (crosshair.visible && crosshairPoint) {
1059
+ const cx = clamp(crosshairPoint.x, chartLeft, chartRight);
1060
+ const cy = clamp(crosshairPoint.y, chartTop, chartBottom);
1061
+ const labelPaddingX = 8;
1062
+ const labelHeight = 20;
1063
+ const labelRadius = Math.max(0, crosshair.labelBorderRadius);
1064
+ const labelBackground = crosshair.labelBackgroundColor;
1065
+ const labelTextColor = crosshair.labelTextColor;
1066
+ const labelBorderColor = crosshair.labelBorderColor;
1067
+ const labelBorderWidth = Math.max(0, crosshair.labelBorderWidth);
1068
+ const labelBorderStyle = crosshair.labelBorderStyle;
1069
+ const strokeCrosshairLabel = (x, y, widthValue) => {
1070
+ if (labelBorderWidth <= 0) {
1071
+ return;
1072
+ }
1073
+ ctx.save();
1074
+ ctx.strokeStyle = labelBorderColor;
1075
+ ctx.lineWidth = labelBorderWidth;
1076
+ if (labelBorderStyle === "dotted") {
1077
+ ctx.setLineDash([2, 3]);
1078
+ } else if (labelBorderStyle === "dashed") {
1079
+ ctx.setLineDash([6, 4]);
1080
+ } else {
1081
+ ctx.setLineDash([]);
1082
+ }
1083
+ strokeRoundedRect(Math.round(x), Math.round(y), widthValue, labelHeight, labelRadius);
1084
+ ctx.restore();
1085
+ };
1086
+ if (crosshair.showPriceLabel) {
1087
+ const hoverPrice = yMin + (chartBottom - cy) / chartHeight * yRange;
1088
+ const priceText = formatPrice(hoverPrice);
1089
+ const priceWidth = Math.ceil(ctx.measureText(priceText).width) + labelPaddingX * 2;
1090
+ const priceX = chartRight + 4;
1091
+ const priceY = clamp(cy - labelHeight / 2, chartTop, chartBottom - labelHeight);
1092
+ ctx.fillStyle = labelBackground;
1093
+ fillRoundedRect(Math.round(priceX), Math.round(priceY), priceWidth, labelHeight, labelRadius);
1094
+ strokeCrosshairLabel(priceX, priceY, priceWidth);
1095
+ drawText(priceText, priceX + labelPaddingX, priceY + labelHeight / 2, "left", "middle", labelTextColor);
1096
+ }
1097
+ if (crosshair.showTimeLabel) {
1098
+ const ratio = clamp((cx - chartLeft) / chartWidth, 0, 1);
1099
+ const hoverIndex = Math.round(xStart + ratio * xSpan - 0.5);
1100
+ const hoverTime = getTimeForIndex(hoverIndex);
1101
+ if (hoverTime) {
1102
+ const timeText = formatHoverTimeLabel(hoverTime, crosshair.timeLabelFormat);
1103
+ const timeWidth = Math.ceil(ctx.measureText(timeText).width) + labelPaddingX * 2;
1104
+ const timeX = clamp(cx - timeWidth / 2, chartLeft, chartRight - timeWidth);
1105
+ const timeY = chartBottom + 8;
1106
+ ctx.fillStyle = labelBackground;
1107
+ fillRoundedRect(Math.round(timeX), Math.round(timeY), timeWidth, labelHeight, labelRadius);
1108
+ strokeCrosshairLabel(timeX, timeY, timeWidth);
1109
+ drawText(timeText, timeX + labelPaddingX, timeY + labelHeight / 2, "left", "middle", labelTextColor);
1110
+ }
1111
+ }
1112
+ }
950
1113
  };
951
1114
  const zoomX = (factor, anchorX) => {
952
1115
  if (!drawState || data.length === 0) {
@@ -1041,6 +1204,39 @@ function createChart(element, options = {}) {
1041
1204
  const ratio = clamp((drawState.chartBottom - y) / drawState.chartHeight, 0, 1);
1042
1205
  return drawState.yMin + ratio * (drawState.yMax - drawState.yMin);
1043
1206
  };
1207
+ const indexFromCanvasX = (x) => {
1208
+ if (!drawState) {
1209
+ return null;
1210
+ }
1211
+ const ratio = clamp((x - drawState.chartLeft) / drawState.chartWidth, 0, 1);
1212
+ return Math.round(drawState.xStart + ratio * drawState.xSpan - 0.5);
1213
+ };
1214
+ const emitCrosshairMove = (x, y, region) => {
1215
+ if (!crosshairMoveHandler) {
1216
+ return;
1217
+ }
1218
+ const index = indexFromCanvasX(x);
1219
+ const hoverTime = index === null ? null : getTimeForIndex(index);
1220
+ const parsedPoint = index === null ? void 0 : data[index];
1221
+ const point = parsedPoint === void 0 ? void 0 : {
1222
+ t: parsedPoint.time.toISOString(),
1223
+ o: parsedPoint.o,
1224
+ h: parsedPoint.h,
1225
+ l: parsedPoint.l,
1226
+ c: parsedPoint.c,
1227
+ ...parsedPoint.v === void 0 ? {} : { v: parsedPoint.v }
1228
+ };
1229
+ const payload = {
1230
+ x,
1231
+ y,
1232
+ region,
1233
+ ...region === "plot" ? { price: Number(priceFromCanvasY(y).toFixed(mergedOptions.priceDecimals)) } : {},
1234
+ ...index === null ? {} : { index },
1235
+ ...hoverTime ? { time: hoverTime.toISOString() } : {},
1236
+ ...point ? { point } : {}
1237
+ };
1238
+ crosshairMoveHandler(payload);
1239
+ };
1044
1240
  const getHitRegion = (x, y) => {
1045
1241
  if (!drawState) {
1046
1242
  return "outside";
@@ -1192,14 +1388,17 @@ function createChart(element, options = {}) {
1192
1388
  }
1193
1389
  const hoverRegion = getHitRegion(point.x, point.y);
1194
1390
  if (hoverRegion === "plot") {
1195
- canvas.style.cursor = "grab";
1391
+ canvas.style.cursor = "default";
1196
1392
  setCrosshairPoint(point);
1393
+ emitCrosshairMove(point.x, point.y, "plot");
1197
1394
  } else if (hoverRegion === "x-axis") {
1198
1395
  canvas.style.cursor = "ew-resize";
1199
1396
  setCrosshairPoint(null);
1397
+ emitCrosshairMove(point.x, point.y, "x-axis");
1200
1398
  } else if (hoverRegion === "y-axis") {
1201
1399
  canvas.style.cursor = "ns-resize";
1202
1400
  setCrosshairPoint(null);
1401
+ emitCrosshairMove(point.x, point.y, "y-axis");
1203
1402
  } else {
1204
1403
  canvas.style.cursor = "default";
1205
1404
  setCrosshairPoint(null);
@@ -1209,7 +1408,7 @@ function createChart(element, options = {}) {
1209
1408
  const deltaX = point.x - lastPointerX;
1210
1409
  const deltaY = point.y - lastPointerY;
1211
1410
  if (dragMode === "plot") {
1212
- canvas.style.cursor = "grabbing";
1411
+ canvas.style.cursor = "default";
1213
1412
  pan(deltaX, deltaY, true, true);
1214
1413
  setCrosshairPoint(null);
1215
1414
  } else if (dragMode === "x-axis") {
@@ -1374,7 +1573,11 @@ function createChart(element, options = {}) {
1374
1573
  autoYMin = null;
1375
1574
  autoYMax = null;
1376
1575
  } else {
1377
- clampXViewport();
1576
+ if (mergedOptions.preserveViewportOnDataUpdate) {
1577
+ clampXViewport();
1578
+ } else {
1579
+ fitXViewport();
1580
+ }
1378
1581
  }
1379
1582
  draw();
1380
1583
  };
@@ -1435,6 +1638,9 @@ function createChart(element, options = {}) {
1435
1638
  const onChartClick = (handler) => {
1436
1639
  chartClickHandler = handler;
1437
1640
  };
1641
+ const onCrosshairMove = (handler) => {
1642
+ crosshairMoveHandler = handler;
1643
+ };
1438
1644
  const setDoubleClickEnabled = (enabled) => {
1439
1645
  doubleClickEnabled = enabled;
1440
1646
  };
@@ -1463,6 +1669,7 @@ function createChart(element, options = {}) {
1463
1669
  removeOrderLine,
1464
1670
  onOrderAction,
1465
1671
  onChartClick,
1672
+ onCrosshairMove,
1466
1673
  setDoubleClickEnabled,
1467
1674
  setDoubleClickAction,
1468
1675
  resize,
@@ -4,6 +4,11 @@ interface ChartOptions {
4
4
  backgroundColor?: string;
5
5
  axisColor?: string;
6
6
  axis?: AxisOptions;
7
+ priceDecimals?: number;
8
+ initialViewport?: "latest" | "center";
9
+ initialVisibleBars?: number;
10
+ rightEdgePaddingBars?: number;
11
+ preserveViewportOnDataUpdate?: boolean;
7
12
  upColor?: string;
8
13
  downColor?: string;
9
14
  gridColor?: string;
@@ -42,6 +47,15 @@ interface CrosshairOptions {
42
47
  style?: "solid" | "dotted" | "dashed";
43
48
  showHorizontal?: boolean;
44
49
  showVertical?: boolean;
50
+ showPriceLabel?: boolean;
51
+ showTimeLabel?: boolean;
52
+ timeLabelFormat?: "auto" | "date" | "time" | "datetime";
53
+ labelBackgroundColor?: string;
54
+ labelTextColor?: string;
55
+ labelBorderRadius?: number;
56
+ labelBorderColor?: string;
57
+ labelBorderWidth?: number;
58
+ labelBorderStyle?: "solid" | "dotted" | "dashed";
45
59
  }
46
60
  interface WatermarkOptions {
47
61
  visible?: boolean;
@@ -51,6 +65,12 @@ interface WatermarkOptions {
51
65
  fontSize?: number;
52
66
  fontWeight?: number | string;
53
67
  thickness?: number;
68
+ imageSrc?: string;
69
+ imageScale?: number;
70
+ imageMaxWidthRatio?: number;
71
+ imageMaxHeightRatio?: number;
72
+ imageTintColor?: string;
73
+ imageTintOpacity?: number;
54
74
  }
55
75
  interface PriceLineOptions {
56
76
  id?: string;
@@ -132,6 +152,15 @@ interface ChartClickEvent {
132
152
  price?: number;
133
153
  region: "plot" | "x-axis" | "y-axis";
134
154
  }
155
+ interface CrosshairMoveEvent {
156
+ x: number;
157
+ y: number;
158
+ region: "plot" | "x-axis" | "y-axis";
159
+ price?: number;
160
+ index?: number;
161
+ time?: string;
162
+ point?: OhlcDataPoint;
163
+ }
135
164
  interface TickerLineOptions {
136
165
  visible?: boolean;
137
166
  style?: "solid" | "dotted" | "dashed";
@@ -152,6 +181,7 @@ interface ChartInstance {
152
181
  removeOrderLine: (id: string) => void;
153
182
  onOrderAction: (handler: ((event: OrderActionEvent) => void) | null) => void;
154
183
  onChartClick: (handler: ((event: ChartClickEvent) => void) | null) => void;
184
+ onCrosshairMove: (handler: ((event: CrosshairMoveEvent) => void) | null) => void;
155
185
  setDoubleClickEnabled: (enabled: boolean) => void;
156
186
  setDoubleClickAction: (action: "reset" | "placeLimitOrder") => void;
157
187
  resize: (width?: number, height?: number) => void;
@@ -167,4 +197,4 @@ interface OhlcDataPoint {
167
197
  }
168
198
  declare function createChart(element: HTMLElement, options?: ChartOptions): ChartInstance;
169
199
 
170
- export { type AxisOptions, type ChartClickEvent, type ChartInstance, type ChartOptions, type CrosshairOptions, type GridOptions, type OhlcDataPoint, type OrderActionButton, type OrderActionEvent, type OrderLineOptions, type PriceLineOptions, type TickerLineOptions, type WatermarkOptions, createChart };
200
+ export { type AxisOptions, type ChartClickEvent, type ChartInstance, type ChartOptions, type CrosshairMoveEvent, type CrosshairOptions, type GridOptions, type OhlcDataPoint, type OrderActionButton, type OrderActionEvent, type OrderLineOptions, type PriceLineOptions, type TickerLineOptions, type WatermarkOptions, createChart };