hyperprop-charting-library 0.1.11 → 0.1.13

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/index.cjs CHANGED
@@ -68,6 +68,14 @@ var DEFAULT_WATERMARK_OPTIONS = {
68
68
  imageTintColor: "",
69
69
  imageTintOpacity: 1
70
70
  };
71
+ var DEFAULT_DASH_PATTERNS = {
72
+ dotted: [2, 2],
73
+ dashed: [8, 6],
74
+ connectorDotted: [2, 3],
75
+ connectorDashed: [6, 5],
76
+ borderDotted: [2, 2],
77
+ borderDashed: [6, 4]
78
+ };
71
79
  var DEFAULT_PRICE_LINE_OPTIONS = {
72
80
  visible: true,
73
81
  style: "solid",
@@ -118,6 +126,9 @@ var DEFAULT_OPTIONS = {
118
126
  priceDecimals: 2,
119
127
  initialViewport: "latest",
120
128
  initialVisibleBars: 60,
129
+ minVisibleBars: 5,
130
+ maxVisibleBars: 2e4,
131
+ maxPanBars: 1e6,
121
132
  rightEdgePaddingBars: 2,
122
133
  preserveViewportOnDataUpdate: true,
123
134
  upColor: "#2fb171",
@@ -144,7 +155,8 @@ var DEFAULT_OPTIONS = {
144
155
  labelBackgroundColor: "#38bdf8",
145
156
  labelTextColor: "#0b1220",
146
157
  labelBorderRadius: 3
147
- }
158
+ },
159
+ dashPatterns: DEFAULT_DASH_PATTERNS
148
160
  };
149
161
  var BRAND_LOGO_VIEWBOX_WIDTH = 190;
150
162
  var BRAND_LOGO_VIEWBOX_HEIGHT = 186;
@@ -174,6 +186,10 @@ function createChart(element, options = {}) {
174
186
  tickerLine: {
175
187
  ...DEFAULT_OPTIONS.tickerLine,
176
188
  ...options.tickerLine
189
+ },
190
+ dashPatterns: {
191
+ ...DEFAULT_DASH_PATTERNS,
192
+ ...options.dashPatterns ?? {}
177
193
  }
178
194
  };
179
195
  let width = mergedOptions.width;
@@ -224,7 +240,9 @@ function createChart(element, options = {}) {
224
240
  element.innerHTML = "";
225
241
  element.appendChild(canvas);
226
242
  const margin = { top: 16, right: 72, bottom: 34, left: 12 };
227
- const maxPanBars = 1e6;
243
+ const minVisibleBars = Math.max(1, Math.floor(mergedOptions.minVisibleBars));
244
+ const maxVisibleBars = Math.max(minVisibleBars, Math.floor(mergedOptions.maxVisibleBars));
245
+ const maxPanBars = Math.max(0, Math.floor(mergedOptions.maxPanBars));
228
246
  const rightEdgePaddingBars = Math.max(0, mergedOptions.rightEdgePaddingBars);
229
247
  const getPixelRatio = () => {
230
248
  if (typeof window === "undefined") {
@@ -259,6 +277,23 @@ function createChart(element, options = {}) {
259
277
  const clamp = (value, min, max) => {
260
278
  return Math.min(max, Math.max(min, value));
261
279
  };
280
+ const dashPatterns = {
281
+ dotted: mergedOptions.dashPatterns.dotted ?? DEFAULT_DASH_PATTERNS.dotted,
282
+ dashed: mergedOptions.dashPatterns.dashed ?? DEFAULT_DASH_PATTERNS.dashed,
283
+ connectorDotted: mergedOptions.dashPatterns.connectorDotted ?? DEFAULT_DASH_PATTERNS.connectorDotted,
284
+ connectorDashed: mergedOptions.dashPatterns.connectorDashed ?? DEFAULT_DASH_PATTERNS.connectorDashed,
285
+ borderDotted: mergedOptions.dashPatterns.borderDotted ?? DEFAULT_DASH_PATTERNS.borderDotted,
286
+ borderDashed: mergedOptions.dashPatterns.borderDashed ?? DEFAULT_DASH_PATTERNS.borderDashed
287
+ };
288
+ const applyDashPattern = (style, dotted, dashed) => {
289
+ if (style === "dotted") {
290
+ ctx.setLineDash(dotted);
291
+ } else if (style === "dashed") {
292
+ ctx.setLineDash(dashed);
293
+ } else {
294
+ ctx.setLineDash([]);
295
+ }
296
+ };
262
297
  const clampXViewport = () => {
263
298
  const count = data.length;
264
299
  if (count === 0) {
@@ -266,8 +301,8 @@ function createChart(element, options = {}) {
266
301
  xSpan = 60;
267
302
  return;
268
303
  }
269
- const minSpan = 5;
270
- const maxSpan = Math.max(minSpan, count + maxPanBars * 2);
304
+ const minSpan = minVisibleBars;
305
+ const maxSpan = Math.min(maxVisibleBars, Math.max(minSpan, count + maxPanBars * 2));
271
306
  xSpan = clamp(xSpan, minSpan, maxSpan);
272
307
  xCenter = clamp(xCenter, -maxPanBars, count + maxPanBars);
273
308
  };
@@ -278,8 +313,9 @@ function createChart(element, options = {}) {
278
313
  xSpan = 60;
279
314
  return;
280
315
  }
281
- const requestedVisibleBars = Math.max(5, Math.floor(mergedOptions.initialVisibleBars));
282
- xSpan = Math.min(requestedVisibleBars, Math.max(5, count));
316
+ const maxSpan = Math.min(maxVisibleBars, Math.max(minVisibleBars, count + maxPanBars * 2));
317
+ const requestedVisibleBars = clamp(Math.floor(mergedOptions.initialVisibleBars), minVisibleBars, maxSpan);
318
+ xSpan = requestedVisibleBars;
283
319
  if (mergedOptions.initialViewport === "center") {
284
320
  xCenter = count / 2;
285
321
  } else {
@@ -431,13 +467,7 @@ function createChart(element, options = {}) {
431
467
  ctx.save();
432
468
  ctx.strokeStyle = color;
433
469
  ctx.lineWidth = Math.max(1, mergedLine.thickness);
434
- if (mergedLine.style === "dotted") {
435
- ctx.setLineDash([2, 4]);
436
- } else if (mergedLine.style === "dashed") {
437
- ctx.setLineDash([8, 6]);
438
- } else {
439
- ctx.setLineDash([]);
440
- }
470
+ applyDashPattern(mergedLine.style, dashPatterns.dotted, dashPatterns.dashed);
441
471
  ctx.beginPath();
442
472
  ctx.moveTo(crisp(chartLeft), crisp(lineY));
443
473
  ctx.lineTo(crisp(chartRight), crisp(lineY));
@@ -491,13 +521,7 @@ function createChart(element, options = {}) {
491
521
  ctx.save();
492
522
  ctx.strokeStyle = color;
493
523
  ctx.lineWidth = Math.max(1, mergedLine.thickness);
494
- if (mergedLine.style === "dotted") {
495
- ctx.setLineDash([2, 4]);
496
- } else if (mergedLine.style === "dashed") {
497
- ctx.setLineDash([8, 6]);
498
- } else {
499
- ctx.setLineDash([]);
500
- }
524
+ applyDashPattern(mergedLine.style, dashPatterns.dotted, dashPatterns.dashed);
501
525
  ctx.beginPath();
502
526
  ctx.moveTo(crisp(chartLeft), crisp(lineY));
503
527
  ctx.lineTo(crisp(chartRight), crisp(lineY));
@@ -509,13 +533,11 @@ function createChart(element, options = {}) {
509
533
  ctx.save();
510
534
  ctx.strokeStyle = mergedLine.connectorColor ?? color;
511
535
  ctx.lineWidth = Math.max(1, mergedLine.connectorThickness);
512
- if (mergedLine.connectorStyle === "dotted") {
513
- ctx.setLineDash([2, 5]);
514
- } else if (mergedLine.connectorStyle === "dashed") {
515
- ctx.setLineDash([6, 5]);
516
- } else {
517
- ctx.setLineDash([]);
518
- }
536
+ applyDashPattern(
537
+ mergedLine.connectorStyle,
538
+ dashPatterns.connectorDotted,
539
+ dashPatterns.connectorDashed
540
+ );
519
541
  ctx.beginPath();
520
542
  ctx.moveTo(crisp(connectorX), crisp(lineY));
521
543
  ctx.lineTo(crisp(connectorX), crisp(connectorY));
@@ -618,13 +640,11 @@ function createChart(element, options = {}) {
618
640
  ctx.save();
619
641
  ctx.strokeStyle = actionBorderColor;
620
642
  ctx.lineWidth = 1;
621
- if (actionBorderStyle === "dotted") {
622
- ctx.setLineDash([2, 3]);
623
- } else if (actionBorderStyle === "dashed") {
624
- ctx.setLineDash([6, 4]);
625
- } else {
626
- ctx.setLineDash([]);
627
- }
643
+ applyDashPattern(
644
+ actionBorderStyle,
645
+ dashPatterns.borderDotted,
646
+ dashPatterns.borderDashed
647
+ );
628
648
  strokeRoundedRect(Math.round(actionX), Math.round(actionY), actionW, actionH, actionRadius);
629
649
  ctx.restore();
630
650
  const baseFont = ctx.font;
@@ -963,13 +983,7 @@ function createChart(element, options = {}) {
963
983
  ctx.save();
964
984
  ctx.strokeStyle = crosshair.color;
965
985
  ctx.lineWidth = Math.max(1, crosshair.width);
966
- if (crosshair.style === "dotted") {
967
- ctx.setLineDash([2, 4]);
968
- } else if (crosshair.style === "dashed") {
969
- ctx.setLineDash([8, 6]);
970
- } else {
971
- ctx.setLineDash([]);
972
- }
986
+ applyDashPattern(crosshair.style, dashPatterns.dotted, dashPatterns.dashed);
973
987
  if (crosshair.showVertical) {
974
988
  ctx.beginPath();
975
989
  ctx.moveTo(crisp(cx), crisp(chartTop));
@@ -1011,13 +1025,7 @@ function createChart(element, options = {}) {
1011
1025
  ctx.save();
1012
1026
  ctx.strokeStyle = tickerColor;
1013
1027
  ctx.lineWidth = tickerThickness;
1014
- if (tickerStyle === "dotted") {
1015
- ctx.setLineDash([2, 4]);
1016
- } else if (tickerStyle === "dashed") {
1017
- ctx.setLineDash([8, 6]);
1018
- } else {
1019
- ctx.setLineDash([]);
1020
- }
1028
+ applyDashPattern(tickerStyle, dashPatterns.dotted, dashPatterns.dashed);
1021
1029
  ctx.beginPath();
1022
1030
  ctx.moveTo(crisp(chartLeft), crisp(lineY));
1023
1031
  ctx.lineTo(crisp(chartRight), crisp(lineY));
@@ -1090,13 +1098,11 @@ function createChart(element, options = {}) {
1090
1098
  ctx.save();
1091
1099
  ctx.strokeStyle = labelBorderColor;
1092
1100
  ctx.lineWidth = labelBorderWidth;
1093
- if (labelBorderStyle === "dotted") {
1094
- ctx.setLineDash([2, 3]);
1095
- } else if (labelBorderStyle === "dashed") {
1096
- ctx.setLineDash([6, 4]);
1097
- } else {
1098
- ctx.setLineDash([]);
1099
- }
1101
+ applyDashPattern(
1102
+ labelBorderStyle,
1103
+ dashPatterns.borderDotted,
1104
+ dashPatterns.borderDashed
1105
+ );
1100
1106
  strokeRoundedRect(Math.round(x), Math.round(y), widthValue, labelHeight, labelRadius);
1101
1107
  ctx.restore();
1102
1108
  };
@@ -1132,8 +1138,8 @@ function createChart(element, options = {}) {
1132
1138
  if (!drawState || data.length === 0) {
1133
1139
  return;
1134
1140
  }
1135
- const minSpan = 5;
1136
- const maxSpan = Math.max(minSpan, data.length + maxPanBars * 2);
1141
+ const minSpan = minVisibleBars;
1142
+ const maxSpan = Math.min(maxVisibleBars, Math.max(minSpan, data.length + maxPanBars * 2));
1137
1143
  const nextSpan = clamp(xSpan * factor, minSpan, maxSpan);
1138
1144
  const anchorRatio = clamp((anchorX - drawState.chartLeft) / drawState.chartWidth, 0, 1);
1139
1145
  const anchorIndex = drawState.xStart + anchorRatio * xSpan;
@@ -1147,8 +1153,8 @@ function createChart(element, options = {}) {
1147
1153
  if (!drawState || data.length === 0) {
1148
1154
  return;
1149
1155
  }
1150
- const minSpan = 5;
1151
- const maxSpan = Math.max(minSpan, data.length + maxPanBars * 2);
1156
+ const minSpan = minVisibleBars;
1157
+ const maxSpan = Math.min(maxVisibleBars, Math.max(minSpan, data.length + maxPanBars * 2));
1152
1158
  const nextSpan = clamp(xSpan * factor, minSpan, maxSpan);
1153
1159
  const rightEdgeIndex = data.length + rightEdgePaddingBars;
1154
1160
  const nextStart = rightEdgeIndex - nextSpan;
@@ -1197,6 +1203,64 @@ function createChart(element, options = {}) {
1197
1203
  }
1198
1204
  draw();
1199
1205
  };
1206
+ const resetYViewport = () => {
1207
+ yMinOverride = null;
1208
+ yMaxOverride = null;
1209
+ autoYMin = null;
1210
+ autoYMax = null;
1211
+ };
1212
+ const zoomInX = (factor = 1.25) => {
1213
+ if (!drawState) {
1214
+ return;
1215
+ }
1216
+ zoomX(1 / Math.max(1.01, factor), drawState.chartLeft + drawState.chartWidth / 2);
1217
+ };
1218
+ const zoomOutX = (factor = 1.25) => {
1219
+ if (!drawState) {
1220
+ return;
1221
+ }
1222
+ zoomX(Math.max(1.01, factor), drawState.chartLeft + drawState.chartWidth / 2);
1223
+ };
1224
+ const zoomInY = (factor = 1.25) => {
1225
+ if (!drawState) {
1226
+ return;
1227
+ }
1228
+ zoomY(1 / Math.max(1.01, factor), drawState.chartTop + drawState.chartHeight / 2);
1229
+ };
1230
+ const zoomOutY = (factor = 1.25) => {
1231
+ if (!drawState) {
1232
+ return;
1233
+ }
1234
+ zoomY(Math.max(1.01, factor), drawState.chartTop + drawState.chartHeight / 2);
1235
+ };
1236
+ const panX = (bars) => {
1237
+ if (!Number.isFinite(bars) || bars === 0) {
1238
+ return;
1239
+ }
1240
+ xCenter += bars;
1241
+ clampXViewport();
1242
+ draw();
1243
+ };
1244
+ const panY = (priceDelta) => {
1245
+ if (!drawState || !Number.isFinite(priceDelta) || priceDelta === 0) {
1246
+ return;
1247
+ }
1248
+ const currentMin = yMinOverride ?? drawState.yMin;
1249
+ const currentMax = yMaxOverride ?? drawState.yMax;
1250
+ const clamped = clampYRange(currentMin + priceDelta, currentMax + priceDelta);
1251
+ yMinOverride = clamped.min;
1252
+ yMaxOverride = clamped.max;
1253
+ draw();
1254
+ };
1255
+ const fitContent = () => {
1256
+ fitXViewport();
1257
+ draw();
1258
+ };
1259
+ const resetViewport = () => {
1260
+ fitXViewport();
1261
+ resetYViewport();
1262
+ draw();
1263
+ };
1200
1264
  const getCanvasPoint = (event) => {
1201
1265
  const rect = canvas.getBoundingClientRect();
1202
1266
  return {
@@ -1540,19 +1604,11 @@ function createChart(element, options = {}) {
1540
1604
  return;
1541
1605
  }
1542
1606
  if (region === "y-axis") {
1543
- yMinOverride = null;
1544
- yMaxOverride = null;
1545
- autoYMin = null;
1546
- autoYMax = null;
1607
+ resetYViewport();
1547
1608
  draw();
1548
1609
  return;
1549
1610
  }
1550
- fitXViewport();
1551
- yMinOverride = null;
1552
- yMaxOverride = null;
1553
- autoYMin = null;
1554
- autoYMax = null;
1555
- draw();
1611
+ resetViewport();
1556
1612
  };
1557
1613
  canvas.addEventListener("pointerdown", onPointerDown);
1558
1614
  canvas.addEventListener("pointermove", onPointerMove);
@@ -1576,19 +1632,13 @@ function createChart(element, options = {}) {
1576
1632
  if (data.length === 0) {
1577
1633
  xCenter = 0;
1578
1634
  xSpan = 60;
1579
- yMinOverride = null;
1580
- yMaxOverride = null;
1581
- autoYMin = null;
1582
- autoYMax = null;
1635
+ resetYViewport();
1583
1636
  draw();
1584
1637
  return;
1585
1638
  }
1586
1639
  if (!hadData) {
1587
1640
  fitXViewport();
1588
- yMinOverride = null;
1589
- yMaxOverride = null;
1590
- autoYMin = null;
1591
- autoYMax = null;
1641
+ resetYViewport();
1592
1642
  } else {
1593
1643
  if (mergedOptions.preserveViewportOnDataUpdate) {
1594
1644
  clampXViewport();
@@ -1687,6 +1737,14 @@ function createChart(element, options = {}) {
1687
1737
  onOrderAction,
1688
1738
  onChartClick,
1689
1739
  onCrosshairMove,
1740
+ zoomInX,
1741
+ zoomOutX,
1742
+ zoomInY,
1743
+ zoomOutY,
1744
+ panX,
1745
+ panY,
1746
+ resetViewport,
1747
+ fitContent,
1690
1748
  setDoubleClickEnabled,
1691
1749
  setDoubleClickAction,
1692
1750
  resize,
package/dist/index.d.cts CHANGED
@@ -7,6 +7,9 @@ interface ChartOptions {
7
7
  priceDecimals?: number;
8
8
  initialViewport?: "latest" | "center";
9
9
  initialVisibleBars?: number;
10
+ minVisibleBars?: number;
11
+ maxVisibleBars?: number;
12
+ maxPanBars?: number;
10
13
  rightEdgePaddingBars?: number;
11
14
  preserveViewportOnDataUpdate?: boolean;
12
15
  upColor?: string;
@@ -26,6 +29,15 @@ interface ChartOptions {
26
29
  priceLines?: PriceLineOptions[];
27
30
  orderLines?: OrderLineOptions[];
28
31
  tickerLine?: TickerLineOptions;
32
+ dashPatterns?: Partial<DashPatternOptions>;
33
+ }
34
+ interface DashPatternOptions {
35
+ dotted: [number, number];
36
+ dashed: [number, number];
37
+ connectorDotted: [number, number];
38
+ connectorDashed: [number, number];
39
+ borderDotted: [number, number];
40
+ borderDashed: [number, number];
29
41
  }
30
42
  interface AxisOptions {
31
43
  lineColor?: string;
@@ -182,6 +194,14 @@ interface ChartInstance {
182
194
  onOrderAction: (handler: ((event: OrderActionEvent) => void) | null) => void;
183
195
  onChartClick: (handler: ((event: ChartClickEvent) => void) | null) => void;
184
196
  onCrosshairMove: (handler: ((event: CrosshairMoveEvent) => void) | null) => void;
197
+ zoomInX: (factor?: number) => void;
198
+ zoomOutX: (factor?: number) => void;
199
+ zoomInY: (factor?: number) => void;
200
+ zoomOutY: (factor?: number) => void;
201
+ panX: (bars: number) => void;
202
+ panY: (priceDelta: number) => void;
203
+ resetViewport: () => void;
204
+ fitContent: () => void;
185
205
  setDoubleClickEnabled: (enabled: boolean) => void;
186
206
  setDoubleClickAction: (action: "reset" | "placeLimitOrder") => void;
187
207
  resize: (width?: number, height?: number) => void;
@@ -197,4 +217,4 @@ interface OhlcDataPoint {
197
217
  }
198
218
  declare function createChart(element: HTMLElement, options?: ChartOptions): ChartInstance;
199
219
 
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 };
220
+ export { type AxisOptions, type ChartClickEvent, type ChartInstance, type ChartOptions, type CrosshairMoveEvent, type CrosshairOptions, type DashPatternOptions, type GridOptions, type OhlcDataPoint, type OrderActionButton, type OrderActionEvent, type OrderLineOptions, type PriceLineOptions, type TickerLineOptions, type WatermarkOptions, createChart };
package/dist/index.d.ts CHANGED
@@ -7,6 +7,9 @@ interface ChartOptions {
7
7
  priceDecimals?: number;
8
8
  initialViewport?: "latest" | "center";
9
9
  initialVisibleBars?: number;
10
+ minVisibleBars?: number;
11
+ maxVisibleBars?: number;
12
+ maxPanBars?: number;
10
13
  rightEdgePaddingBars?: number;
11
14
  preserveViewportOnDataUpdate?: boolean;
12
15
  upColor?: string;
@@ -26,6 +29,15 @@ interface ChartOptions {
26
29
  priceLines?: PriceLineOptions[];
27
30
  orderLines?: OrderLineOptions[];
28
31
  tickerLine?: TickerLineOptions;
32
+ dashPatterns?: Partial<DashPatternOptions>;
33
+ }
34
+ interface DashPatternOptions {
35
+ dotted: [number, number];
36
+ dashed: [number, number];
37
+ connectorDotted: [number, number];
38
+ connectorDashed: [number, number];
39
+ borderDotted: [number, number];
40
+ borderDashed: [number, number];
29
41
  }
30
42
  interface AxisOptions {
31
43
  lineColor?: string;
@@ -182,6 +194,14 @@ interface ChartInstance {
182
194
  onOrderAction: (handler: ((event: OrderActionEvent) => void) | null) => void;
183
195
  onChartClick: (handler: ((event: ChartClickEvent) => void) | null) => void;
184
196
  onCrosshairMove: (handler: ((event: CrosshairMoveEvent) => void) | null) => void;
197
+ zoomInX: (factor?: number) => void;
198
+ zoomOutX: (factor?: number) => void;
199
+ zoomInY: (factor?: number) => void;
200
+ zoomOutY: (factor?: number) => void;
201
+ panX: (bars: number) => void;
202
+ panY: (priceDelta: number) => void;
203
+ resetViewport: () => void;
204
+ fitContent: () => void;
185
205
  setDoubleClickEnabled: (enabled: boolean) => void;
186
206
  setDoubleClickAction: (action: "reset" | "placeLimitOrder") => void;
187
207
  resize: (width?: number, height?: number) => void;
@@ -197,4 +217,4 @@ interface OhlcDataPoint {
197
217
  }
198
218
  declare function createChart(element: HTMLElement, options?: ChartOptions): ChartInstance;
199
219
 
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 };
220
+ export { type AxisOptions, type ChartClickEvent, type ChartInstance, type ChartOptions, type CrosshairMoveEvent, type CrosshairOptions, type DashPatternOptions, type GridOptions, type OhlcDataPoint, type OrderActionButton, type OrderActionEvent, type OrderLineOptions, type PriceLineOptions, type TickerLineOptions, type WatermarkOptions, createChart };