hyperprop-charting-library 0.1.141 → 0.1.143

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
@@ -369,26 +369,45 @@ var getSeriesFingerprint = (data) => {
369
369
  var withCachedSeries = (key, data, compute) => {
370
370
  const fingerprint = getSeriesFingerprint(data);
371
371
  const existing = builtInSeriesCache.get(key);
372
- if (existing && existing.fingerprint === fingerprint) {
373
- return existing.values;
372
+ const shape = getSeriesShape(data);
373
+ if (existing) {
374
+ const unchanged = existing.fingerprint === fingerprint;
375
+ const liveTickWithinThrottle = !unchanged && indicatorLiveThrottleMs > 0 && existing.shape === shape && Date.now() - existing.computedAt < indicatorLiveThrottleMs;
376
+ if (unchanged || liveTickWithinThrottle) {
377
+ return existing.values;
378
+ }
374
379
  }
375
380
  const values = compute();
376
- builtInSeriesCache.set(key, { fingerprint, values });
381
+ builtInSeriesCache.set(key, { fingerprint, values, shape, computedAt: Date.now() });
377
382
  return values;
378
383
  };
379
384
  var builtInComputationCache = /* @__PURE__ */ new Map();
385
+ var indicatorLiveThrottleMs = 80;
386
+ var setIndicatorLiveThrottleMs = (ms) => {
387
+ indicatorLiveThrottleMs = Math.max(0, ms);
388
+ };
389
+ var getSeriesShape = (data) => {
390
+ const length = data.length;
391
+ const last = length > 0 ? data[length - 1] : void 0;
392
+ return last ? `${length}|${last.time.getTime()}` : "empty";
393
+ };
380
394
  var COMPUTATION_CACHE_MAX_ENTRIES = 128;
381
395
  var withCachedComputation = (key, data, compute) => {
382
396
  const fingerprint = getSeriesFingerprint(data);
383
397
  const existing = builtInComputationCache.get(key);
384
- if (existing && existing.fingerprint === fingerprint) {
385
- builtInComputationCache.delete(key);
386
- builtInComputationCache.set(key, existing);
387
- return existing.value;
398
+ const shape = getSeriesShape(data);
399
+ if (existing) {
400
+ const unchanged = existing.fingerprint === fingerprint;
401
+ const liveTickWithinThrottle = !unchanged && indicatorLiveThrottleMs > 0 && existing.shape === shape && Date.now() - existing.computedAt < indicatorLiveThrottleMs;
402
+ if (unchanged || liveTickWithinThrottle) {
403
+ builtInComputationCache.delete(key);
404
+ builtInComputationCache.set(key, existing);
405
+ return existing.value;
406
+ }
388
407
  }
389
408
  const value = compute();
390
409
  builtInComputationCache.delete(key);
391
- builtInComputationCache.set(key, { fingerprint, value });
410
+ builtInComputationCache.set(key, { fingerprint, value, shape, computedAt: Date.now() });
392
411
  while (builtInComputationCache.size > COMPUTATION_CACHE_MAX_ENTRIES) {
393
412
  const oldest = builtInComputationCache.keys().next().value;
394
413
  if (oldest === void 0) break;
@@ -2659,44 +2678,6 @@ var compileScriptIndicator = (definition) => {
2659
2678
 
2660
2679
  // src/themes.ts
2661
2680
  var CHART_THEMES = {
2662
- dark: {
2663
- name: "dark",
2664
- background: "#0f0f0f",
2665
- upColor: "#089981",
2666
- downColor: "#f23645",
2667
- lineColor: "#2962ff",
2668
- gridColor: "#3c3c3c",
2669
- gridOpacity: 0.5,
2670
- axisTextColor: "#dbdbdb",
2671
- axisLineColor: "#424242",
2672
- crosshairColor: "#9598a1",
2673
- crosshairLabelBackground: "#3c3c3c",
2674
- crosshairLabelText: "#dbdbdb",
2675
- crosshairLabelBorder: "#5d5d5d",
2676
- watermarkColor: "rgba(219,219,219,0.06)",
2677
- indicatorTextColor: "#b2b5be",
2678
- labelTextColor: "#ffffff",
2679
- labelBackground: "#1a1a1a"
2680
- },
2681
- light: {
2682
- name: "light",
2683
- background: "#ffffff",
2684
- upColor: "#089981",
2685
- downColor: "#f23645",
2686
- lineColor: "#2962ff",
2687
- gridColor: "#d5d5d5",
2688
- gridOpacity: 0.9,
2689
- axisTextColor: "#0f0f0f",
2690
- axisLineColor: "#c3c3c3",
2691
- crosshairColor: "#787b86",
2692
- crosshairLabelBackground: "#4b4b4b",
2693
- crosshairLabelText: "#ffffff",
2694
- crosshairLabelBorder: "#878787",
2695
- watermarkColor: "rgba(15,15,15,0.06)",
2696
- indicatorTextColor: "#4b4b4b",
2697
- labelTextColor: "#ffffff",
2698
- labelBackground: "#f0f3fa"
2699
- },
2700
2681
  midnight: {
2701
2682
  name: "midnight",
2702
2683
  background: "#171717",
@@ -2716,6 +2697,63 @@ var CHART_THEMES = {
2716
2697
  labelTextColor: "#dbeafe",
2717
2698
  labelBackground: "#0b1220"
2718
2699
  },
2700
+ light: {
2701
+ name: "light",
2702
+ background: "#ffffff",
2703
+ upColor: "#22ab94",
2704
+ downColor: "#f23645",
2705
+ lineColor: "#2563eb",
2706
+ gridColor: "#e0e3eb",
2707
+ gridOpacity: 0.9,
2708
+ axisTextColor: "#1f2430",
2709
+ axisLineColor: "#c8ccd6",
2710
+ crosshairColor: "#6b7280",
2711
+ crosshairLabelBackground: "#2a2e39",
2712
+ crosshairLabelText: "#ffffff",
2713
+ crosshairLabelBorder: "#6b7280",
2714
+ watermarkColor: "rgba(19,23,34,0.06)",
2715
+ indicatorTextColor: "#4b5563",
2716
+ labelTextColor: "#ffffff",
2717
+ labelBackground: "#f1f3f8"
2718
+ },
2719
+ brand: {
2720
+ name: "brand",
2721
+ background: "#0b1220",
2722
+ upColor: "#22ab94",
2723
+ downColor: "#f23645",
2724
+ lineColor: "#253cff",
2725
+ gridColor: "#1b2740",
2726
+ gridOpacity: 0.6,
2727
+ axisTextColor: "#c3cee8",
2728
+ axisLineColor: "#34405c",
2729
+ crosshairColor: "#6e85ff",
2730
+ crosshairLabelBackground: "#253cff",
2731
+ crosshairLabelText: "#ffffff",
2732
+ crosshairLabelBorder: "#6e85ff",
2733
+ watermarkColor: "rgba(37,60,255,0.08)",
2734
+ indicatorTextColor: "#a9b8dc",
2735
+ labelTextColor: "#ffffff",
2736
+ labelBackground: "#101a2e"
2737
+ },
2738
+ dark: {
2739
+ name: "dark",
2740
+ background: "#0f0f0f",
2741
+ upColor: "#089981",
2742
+ downColor: "#f23645",
2743
+ lineColor: "#2962ff",
2744
+ gridColor: "#3c3c3c",
2745
+ gridOpacity: 0.5,
2746
+ axisTextColor: "#dbdbdb",
2747
+ axisLineColor: "#424242",
2748
+ crosshairColor: "#9598a1",
2749
+ crosshairLabelBackground: "#3c3c3c",
2750
+ crosshairLabelText: "#dbdbdb",
2751
+ crosshairLabelBorder: "#5d5d5d",
2752
+ watermarkColor: "rgba(219,219,219,0.06)",
2753
+ indicatorTextColor: "#b2b5be",
2754
+ labelTextColor: "#ffffff",
2755
+ labelBackground: "#1a1a1a"
2756
+ },
2719
2757
  "high-contrast": {
2720
2758
  name: "high-contrast",
2721
2759
  background: "#000000",
@@ -2737,7 +2775,7 @@ var CHART_THEMES = {
2737
2775
  }
2738
2776
  };
2739
2777
  var CHART_THEME_NAMES = Object.keys(CHART_THEMES);
2740
- var resolveTheme = (theme) => typeof theme === "string" ? CHART_THEMES[theme] ?? CHART_THEMES.dark : theme;
2778
+ var resolveTheme = (theme) => typeof theme === "string" ? CHART_THEMES[theme] ?? CHART_THEMES.midnight : theme;
2741
2779
 
2742
2780
  // src/options.ts
2743
2781
  var DEFAULT_GRID_OPTIONS = {
@@ -2939,7 +2977,23 @@ var DEFAULT_OPTIONS = {
2939
2977
  accessibility: { label: "Price chart", description: "", focusable: true },
2940
2978
  downsampling: { enabled: true, thresholdPx: 1.5 },
2941
2979
  touch: { hitToleranceScale: 2.2, longPressTooltip: true, longPressMs: 400 },
2980
+ dataLine: {
2981
+ visible: false,
2982
+ symbol: "",
2983
+ interval: "",
2984
+ exchange: "",
2985
+ showOhlc: true,
2986
+ showChange: true,
2987
+ showVolume: false,
2988
+ details: [],
2989
+ statusColor: "",
2990
+ fontSize: 0,
2991
+ symbolColor: "",
2992
+ textColor: ""
2993
+ },
2942
2994
  datafeedOptions: { prefetchThresholdBars: 150, cooldownMs: 1200, chunkBars: 1500 },
2995
+ animation: { viewportTransitions: true, durationMs: 260 },
2996
+ indicatorUpdate: { liveThrottleMs: 80 },
2943
2997
  crosshair: DEFAULT_CROSSHAIR_OPTIONS,
2944
2998
  grid: DEFAULT_GRID_OPTIONS,
2945
2999
  watermark: DEFAULT_WATERMARK_OPTIONS,
@@ -2998,6 +3052,18 @@ var mergeChartOptions = (baseOptions, options = {}) => ({
2998
3052
  ...baseOptions.touch,
2999
3053
  ...options.touch ?? {}
3000
3054
  },
3055
+ dataLine: {
3056
+ ...baseOptions.dataLine,
3057
+ ...options.dataLine ?? {}
3058
+ },
3059
+ animation: {
3060
+ ...baseOptions.animation,
3061
+ ...options.animation ?? {}
3062
+ },
3063
+ indicatorUpdate: {
3064
+ ...baseOptions.indicatorUpdate,
3065
+ ...options.indicatorUpdate ?? {}
3066
+ },
3001
3067
  datafeedOptions: {
3002
3068
  ...baseOptions.datafeedOptions,
3003
3069
  ...options.datafeedOptions ?? {}
@@ -3257,6 +3323,7 @@ function createChart(element, options = {}) {
3257
3323
  let crosshairPoint = null;
3258
3324
  let doubleClickEnabled = mergedOptions.doubleClickEnabled;
3259
3325
  let doubleClickAction = mergedOptions.doubleClickAction;
3326
+ setIndicatorLiveThrottleMs(mergedOptions.indicatorUpdate?.liveThrottleMs ?? 80);
3260
3327
  let noOverlappingLineLabels = DEFAULT_LABELS_OPTIONS.noOverlapping;
3261
3328
  let rightAxisLabelSlots = [];
3262
3329
  let plotLabelSlots = [];
@@ -3498,21 +3565,69 @@ function createChart(element, options = {}) {
3498
3565
  Math.min(highCenter, count + maxPanBars)
3499
3566
  );
3500
3567
  };
3501
- const fitXViewport = () => {
3502
- const count = data.length;
3503
- if (count === 0) {
3504
- xCenter = 0;
3505
- xSpan = 60;
3506
- return;
3568
+ let viewportTweenRaf = null;
3569
+ const cancelViewportTween = () => {
3570
+ if (viewportTweenRaf !== null) {
3571
+ cancelAnimationFrame(viewportTweenRaf);
3572
+ viewportTweenRaf = null;
3573
+ }
3574
+ };
3575
+ const prefersReducedMotion = () => typeof window !== "undefined" && typeof window.matchMedia === "function" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
3576
+ const animateViewportTo = (targetCenter, targetSpan, onComplete) => {
3577
+ const animation = mergedOptions.animation ?? DEFAULT_OPTIONS.animation;
3578
+ const duration = Math.max(0, animation?.durationMs ?? 260);
3579
+ const startCenter = xCenter;
3580
+ const startSpan = xSpan;
3581
+ const centerDelta = targetCenter - startCenter;
3582
+ const spanRatio = startSpan > 0 ? targetSpan / startSpan : 1;
3583
+ const negligible = Math.abs(centerDelta) < 0.5 && Math.abs(spanRatio - 1) < 0.01;
3584
+ if (animation?.viewportTransitions === false || duration === 0 || negligible || prefersReducedMotion() || typeof requestAnimationFrame !== "function") {
3585
+ xCenter = targetCenter;
3586
+ xSpan = targetSpan;
3587
+ clampXViewport();
3588
+ onComplete?.();
3589
+ emitViewportChange();
3590
+ scheduleDraw();
3591
+ return false;
3507
3592
  }
3593
+ cancelViewportTween();
3594
+ const startedAt = performance.now();
3595
+ const step = (now) => {
3596
+ const t = clamp((now - startedAt) / duration, 0, 1);
3597
+ const eased = 1 - Math.pow(1 - t, 3);
3598
+ xCenter = startCenter + centerDelta * eased;
3599
+ xSpan = startSpan * Math.pow(spanRatio, eased);
3600
+ clampXViewport();
3601
+ scheduleDraw();
3602
+ if (t < 1) {
3603
+ viewportTweenRaf = requestAnimationFrame(step);
3604
+ return;
3605
+ }
3606
+ viewportTweenRaf = null;
3607
+ xCenter = targetCenter;
3608
+ xSpan = targetSpan;
3609
+ clampXViewport();
3610
+ onComplete?.();
3611
+ emitViewportChange();
3612
+ scheduleDraw();
3613
+ };
3614
+ viewportTweenRaf = requestAnimationFrame(step);
3615
+ return true;
3616
+ };
3617
+ const getFitXTarget = () => {
3618
+ const count = data.length;
3619
+ if (count === 0) return { center: 0, span: 60 };
3508
3620
  const maxSpan = Math.min(maxVisibleBars, Math.max(minVisibleBars, count + maxPanBars * 2));
3509
- const requestedVisibleBars = clamp(Math.floor(mergedOptions.initialVisibleBars), minVisibleBars, maxSpan);
3510
- xSpan = requestedVisibleBars;
3511
- if (mergedOptions.initialViewport === "center") {
3512
- xCenter = count / 2;
3513
- } else {
3514
- xCenter = count - xSpan / 2 + rightEdgePaddingBars;
3515
- }
3621
+ const span = clamp(Math.floor(mergedOptions.initialVisibleBars), minVisibleBars, maxSpan);
3622
+ return {
3623
+ center: mergedOptions.initialViewport === "center" ? count / 2 : count - span / 2 + rightEdgePaddingBars,
3624
+ span
3625
+ };
3626
+ };
3627
+ const fitXViewport = () => {
3628
+ const target = getFitXTarget();
3629
+ xSpan = target.span;
3630
+ xCenter = target.center;
3516
3631
  clampXViewport();
3517
3632
  };
3518
3633
  const getYBounds = () => {
@@ -6909,6 +7024,73 @@ function createChart(element, options = {}) {
6909
7024
  for (const orderLine of orderLines) {
6910
7025
  drawOrderLine(orderLine, yFromPrice, chartLeft, chartTop, chartRight, chartBottom);
6911
7026
  }
7027
+ let dataLineBottom = chartTop;
7028
+ const dataLine = mergedOptions.dataLine;
7029
+ if (dataLine?.visible && data.length > 0) {
7030
+ const hoverIndex = crosshairPoint && getHitRegion(crosshairPoint.x, crosshairPoint.y) === "plot" ? indexFromCanvasX(crosshairPoint.x) : null;
7031
+ const barIndex = hoverIndex !== null && hoverIndex >= 0 && hoverIndex < data.length ? hoverIndex : data.length - 1;
7032
+ const bar = data[barIndex];
7033
+ if (bar) {
7034
+ const prevFont = ctx.font;
7035
+ const fontSize = Math.max(9, dataLine.fontSize || axis.fontSize);
7036
+ ctx.font = `${fontSize}px ${mergedOptions.fontFamily}`;
7037
+ ctx.textBaseline = "top";
7038
+ ctx.textAlign = "left";
7039
+ const symbolColor = dataLine.symbolColor || axis.textColor;
7040
+ const textColor = dataLine.textColor || labels.indicatorTextColor;
7041
+ const changeAbs = bar.c - bar.o;
7042
+ const changeColor = changeAbs >= 0 ? mergedOptions.upColor : mergedOptions.downColor;
7043
+ const rowY = chartTop + 6;
7044
+ let cursorX = chartLeft + 10;
7045
+ if (dataLine.statusColor) {
7046
+ const dotRadius = Math.max(2.5, fontSize / 4);
7047
+ ctx.fillStyle = dataLine.statusColor;
7048
+ ctx.beginPath();
7049
+ ctx.arc(cursorX + dotRadius, rowY + fontSize / 2, dotRadius, 0, Math.PI * 2);
7050
+ ctx.fill();
7051
+ cursorX += dotRadius * 2 + 6;
7052
+ }
7053
+ const headline = [dataLine.symbol, dataLine.interval, dataLine.exchange].filter((part) => part && part.length > 0).join(" \xB7 ");
7054
+ if (headline) {
7055
+ ctx.fillStyle = symbolColor;
7056
+ ctx.fillText(headline, cursorX, rowY);
7057
+ cursorX += measureTextWidth(headline) + 10;
7058
+ }
7059
+ if (dataLine.showOhlc !== false) {
7060
+ const ohlc = `O${formatPrice(bar.o)} H${formatPrice(bar.h)} L${formatPrice(bar.l)} C${formatPrice(bar.c)}`;
7061
+ ctx.fillStyle = changeColor;
7062
+ ctx.fillText(ohlc, cursorX, rowY);
7063
+ cursorX += measureTextWidth(ohlc) + 8;
7064
+ }
7065
+ if (dataLine.showChange !== false) {
7066
+ const pct = bar.o !== 0 ? changeAbs / bar.o * 100 : 0;
7067
+ const changeText = `${changeAbs >= 0 ? "+" : ""}${formatPrice(changeAbs)} (${changeAbs >= 0 ? "+" : ""}${pct.toFixed(2)}%)`;
7068
+ ctx.fillStyle = changeColor;
7069
+ ctx.fillText(changeText, cursorX, rowY);
7070
+ cursorX += measureTextWidth(changeText) + 10;
7071
+ }
7072
+ if (dataLine.showVolume && bar.v !== void 0) {
7073
+ const volumeText = `Vol ${bar.v >= 1e6 ? `${(bar.v / 1e6).toFixed(2)}M` : bar.v >= 1e3 ? `${(bar.v / 1e3).toFixed(1)}K` : String(Math.round(bar.v))}`;
7074
+ ctx.fillStyle = textColor;
7075
+ ctx.fillText(volumeText, cursorX, rowY);
7076
+ cursorX += measureTextWidth(volumeText) + 10;
7077
+ }
7078
+ for (const detail of dataLine.details ?? []) {
7079
+ const text = detail.label ? `${detail.label} ${detail.value}` : detail.value;
7080
+ const width2 = measureTextWidth(text);
7081
+ if (cursorX + width2 > chartRight - 4) break;
7082
+ if (detail.background) {
7083
+ ctx.fillStyle = detail.background;
7084
+ fillRoundedRect(cursorX - 4, rowY - 2, width2 + 8, fontSize + 4, 3);
7085
+ }
7086
+ ctx.fillStyle = detail.color || textColor;
7087
+ ctx.fillText(text, cursorX, rowY);
7088
+ cursorX += width2 + 12;
7089
+ }
7090
+ dataLineBottom = rowY + fontSize + 4;
7091
+ ctx.font = prevFont;
7092
+ }
7093
+ }
6912
7094
  if (labels.visible && (labels.showIndicatorNames || labels.showIndicatorValues)) {
6913
7095
  const isLegendInputValue = (value) => {
6914
7096
  if (typeof value === "number" || typeof value === "boolean") {
@@ -6937,7 +7119,7 @@ function createChart(element, options = {}) {
6937
7119
  const isRight = position === "top-right" || position === "bottom-right";
6938
7120
  const isBottom = position === "bottom-left" || position === "bottom-right";
6939
7121
  const legendX = isRight ? chartRight - offsetX : chartLeft + offsetX;
6940
- const legendY = isBottom ? chartBottom - offsetY : chartTop + offsetY;
7122
+ const legendY = isBottom ? chartBottom - offsetY : Math.max(chartTop + offsetY, dataLineBottom);
6941
7123
  drawText(legendText, legendX, legendY, isRight ? "right" : "left", isBottom ? "bottom" : "top", labels.indicatorTextColor);
6942
7124
  ctx.font = prevFont;
6943
7125
  }
@@ -7478,27 +7660,24 @@ function createChart(element, options = {}) {
7478
7660
  scheduleDraw();
7479
7661
  };
7480
7662
  const fitContent = () => {
7481
- fitXViewport();
7482
- updateFollowLatest(true);
7483
- emitViewportChange();
7484
- scheduleDraw();
7663
+ const target = getFitXTarget();
7664
+ animateViewportTo(target.center, target.span, () => updateFollowLatest(true));
7485
7665
  };
7486
7666
  const resetViewport = () => {
7487
7667
  cancelKineticPan();
7488
- fitXViewport();
7668
+ const target = getFitXTarget();
7489
7669
  resetYViewport();
7490
- updateFollowLatest(true);
7491
- emitViewportChange();
7492
- scheduleDraw();
7670
+ animateViewportTo(target.center, target.span, () => updateFollowLatest(true));
7493
7671
  };
7494
7672
  const isFollowingLatest = () => followLatest;
7495
7673
  const setFollowingLatest = (follow) => {
7496
7674
  if (follow && data.length > 0) {
7497
7675
  cancelKineticPan();
7498
- xCenter = data.length - xSpan / 2 + rightEdgePaddingBars;
7499
- clampXViewport();
7500
- updateFollowLatest(true);
7501
- scheduleDraw();
7676
+ animateViewportTo(
7677
+ data.length - xSpan / 2 + rightEdgePaddingBars,
7678
+ xSpan,
7679
+ () => updateFollowLatest(true)
7680
+ );
7502
7681
  } else {
7503
7682
  updateFollowLatest(follow);
7504
7683
  }
@@ -8781,6 +8960,7 @@ function createChart(element, options = {}) {
8781
8960
  canvas.focus({ preventScroll: true });
8782
8961
  }
8783
8962
  cancelKineticPan();
8963
+ cancelViewportTween();
8784
8964
  panVelocitySamples.length = 0;
8785
8965
  magnetModifierActive = event.metaKey || event.ctrlKey;
8786
8966
  shiftKeyActive = event.shiftKey;
@@ -9445,6 +9625,7 @@ function createChart(element, options = {}) {
9445
9625
  return;
9446
9626
  }
9447
9627
  cancelKineticPan();
9628
+ cancelViewportTween();
9448
9629
  const point = getCanvasPoint(event);
9449
9630
  const region = getHitRegion(point.x, point.y);
9450
9631
  if (region === "outside") {
@@ -9722,6 +9903,7 @@ function createChart(element, options = {}) {
9722
9903
  resetRightMarginCache();
9723
9904
  doubleClickEnabled = mergedOptions.doubleClickEnabled;
9724
9905
  doubleClickAction = mergedOptions.doubleClickAction;
9906
+ setIndicatorLiveThrottleMs(mergedOptions.indicatorUpdate?.liveThrottleMs ?? 80);
9725
9907
  applyAccessibilityAttributes();
9726
9908
  const isTickerSmoothingEnabled = mergedOptions.tickerLine?.smoothing ?? false;
9727
9909
  if (!isTickerSmoothingEnabled) {
@@ -10200,6 +10382,7 @@ function createChart(element, options = {}) {
10200
10382
  return canvas.toDataURL(options2.type ?? "image/png", options2.quality);
10201
10383
  };
10202
10384
  const destroy = () => {
10385
+ cancelViewportTween();
10203
10386
  cancelLongPressTimer();
10204
10387
  datafeedUnsubscribe?.();
10205
10388
  datafeedUnsubscribe = null;
package/dist/index.d.cts CHANGED
@@ -83,6 +83,9 @@ interface ChartOptions {
83
83
  downsampling?: DownsamplingOptions;
84
84
  touch?: TouchOptions;
85
85
  datafeedOptions?: DatafeedOptions;
86
+ dataLine?: DataLineOptions;
87
+ animation?: AnimationOptions;
88
+ indicatorUpdate?: IndicatorUpdateOptions;
86
89
  crosshair?: CrosshairOptions;
87
90
  grid?: GridOptions;
88
91
  watermark?: WatermarkOptions;
@@ -635,7 +638,68 @@ interface ChartTheme {
635
638
  /** Background for preview labels and pills. */
636
639
  labelBackground: string;
637
640
  }
638
- type ChartThemeName = "dark" | "light" | "midnight" | "high-contrast";
641
+ type ChartThemeName = "midnight" | "light" | "brand" | "dark" | "high-contrast";
642
+ /**
643
+ * The symbol/OHLC line drawn inside the top-left of the plot, like
644
+ * TradingView's data line. Values follow the crosshair while hovering and fall
645
+ * back to the latest bar otherwise. Opt-in, because hosts that already render
646
+ * their own DOM overlay shouldn't suddenly get two.
647
+ */
648
+ interface DataLineOptions {
649
+ /** Default false. */
650
+ visible?: boolean;
651
+ /** e.g. "NQU6" — drawn first, in the emphasis color. */
652
+ symbol?: string;
653
+ /** e.g. "1h". */
654
+ interval?: string;
655
+ /** e.g. "CME". */
656
+ exchange?: string;
657
+ /** O/H/L/C values for the hovered (or latest) bar. Default true. */
658
+ showOhlc?: boolean;
659
+ /** Absolute and percent change of that bar, colored by direction. Default true. */
660
+ showChange?: boolean;
661
+ /** Bar volume. Default false. */
662
+ showVolume?: boolean;
663
+ /**
664
+ * Extra chips after the values — session, currency, a "Closed" badge. Each
665
+ * renders as `label value` with an optional color and pill background.
666
+ */
667
+ details?: Array<{
668
+ label?: string;
669
+ value: string;
670
+ color?: string;
671
+ background?: string;
672
+ }>;
673
+ /** Colored dot before the symbol, e.g. green when the market is open. */
674
+ statusColor?: string;
675
+ fontSize?: number;
676
+ /** Symbol color. Defaults to the axis text color. */
677
+ symbolColor?: string;
678
+ /** Everything after the symbol. Defaults to the indicator legend color. */
679
+ textColor?: string;
680
+ }
681
+ interface IndicatorUpdateOptions {
682
+ /**
683
+ * While only the forming bar is ticking, recompute indicator series at most
684
+ * this often (ms) rather than on every frame. Values are always exact — this
685
+ * changes how often the live bar's output refreshes, not how it's computed,
686
+ * and anything structural (a bar closing, history loading, inputs changing)
687
+ * recomputes immediately. Default 80; set 0 to recompute every frame.
688
+ */
689
+ liveThrottleMs?: number;
690
+ }
691
+ interface AnimationOptions {
692
+ /**
693
+ * Ease the big viewport jumps — reset, fit-all, scroll-to-realtime — instead
694
+ * of teleporting, so it stays obvious which way the chart moved. Continuous
695
+ * gestures (drag, wheel, pinch) are never animated; they already follow the
696
+ * hand. Default true, and always skipped when the OS asks for reduced
697
+ * motion.
698
+ */
699
+ viewportTransitions?: boolean;
700
+ /** Transition length in ms. Default 260. */
701
+ durationMs?: number;
702
+ }
639
703
  /** Touch ergonomics. Fingers are blunter than a mouse cursor. */
640
704
  interface TouchOptions {
641
705
  /**
@@ -1066,16 +1130,16 @@ declare const compileScriptIndicator: (definition: ScriptIndicatorDefinition) =>
1066
1130
  /**
1067
1131
  * Built-in palettes.
1068
1132
  *
1069
- * `dark` and `light` mirror TradingView's own chart colors (sampled from their
1070
- * rendered canvas), which is what most traders' eyes are calibrated to: the
1071
- * candle colors stay the same across both and only the surface changes.
1072
- * `midnight` is Hyperprop's long-standing default, kept as a named preset so
1073
- * existing setups have something to go back to. `high-contrast` trades
1074
- * prettiness for legibility on projectors and for low-vision users.
1133
+ * `midnight` is the long-standing default and `light` is its counterpart on a
1134
+ * white surface same candle colors, so switching surfaces doesn't change how
1135
+ * you read the tape. `brand` tints everything toward Hyperprop blue, `dark` is
1136
+ * a neutral near-black for embedders who want no tint at all, and
1137
+ * `high-contrast` trades subtlety for legibility on projectors and for
1138
+ * low-vision users.
1075
1139
  */
1076
1140
  declare const CHART_THEMES: Record<ChartThemeName, ChartTheme>;
1077
1141
  declare const CHART_THEME_NAMES: ChartThemeName[];
1078
1142
 
1079
1143
  declare function createChart(element: HTMLElement, options?: ChartOptions): ChartInstance;
1080
1144
 
1081
- export { type AccessibilityOptions, type AxisOptions, type BuiltInIndicatorInfo, CHART_THEMES, CHART_THEME_NAMES, type ChartClickEvent, type ChartContextMenuEvent, type ChartContextMenuRegion, type ChartDatafeed, type ChartInstance, type ChartKeyboardAction, type ChartKeyboardShortcutEvent, type ChartLongPressEvent, type ChartOptions, type ChartSavedState, type ChartTheme, type ChartThemeName, type ChartType, type CompareSeriesOptions, type CrosshairMoveEvent, type CrosshairOptions, type CrosshairPriceActionEvent, type DashPatternOptions, type DatafeedBarsRequest, type DatafeedOptions, type DownsamplingOptions, type DrawingBounds, type DrawingDefaults, type DrawingHoverEvent, type DrawingObjectOptions, type DrawingPoint, type DrawingSelectEvent, type DrawingSelectionChangeEvent, type DrawingToolType, FIB_DEFAULT_PALETTE, type GridOptions, type IndicatorInstanceOptions, type IndicatorPane, type IndicatorPaneActionEvent, type IndicatorPaneAxisOptions, type IndicatorPaneGuideLine, type IndicatorPaneHeightChangeEvent, type IndicatorPaneRenderInfo, type IndicatorPaneValue, type IndicatorPaneValueLabel, type IndicatorPlugin, type IndicatorRenderContext, type KeyboardOptions, type LabelsOptions, type OhlcDataPoint, type OrderActionButton, type OrderActionEvent, type OrderLineOptions, POSITION_DEFAULT_COLORS, type PriceLineOptions, type PriceScaleMode, type PriceScaleOptions, SCRIPT_SOURCE_INPUT_VALUES, type ScriptComputeResult, type ScriptIndicatorDefinition, type ScriptIndicatorInputDef, type ScriptInputHelper, type ScriptInputOptions, type ScriptPlotSpec, type TickerLineOptions, type TouchOptions, type TradeMarkerOptions, type ViewportState, type WatermarkOptions, compileScriptIndicator, createChart, extractScriptInputs, validateScriptSource };
1145
+ export { type AccessibilityOptions, type AnimationOptions, type AxisOptions, type BuiltInIndicatorInfo, CHART_THEMES, CHART_THEME_NAMES, type ChartClickEvent, type ChartContextMenuEvent, type ChartContextMenuRegion, type ChartDatafeed, type ChartInstance, type ChartKeyboardAction, type ChartKeyboardShortcutEvent, type ChartLongPressEvent, type ChartOptions, type ChartSavedState, type ChartTheme, type ChartThemeName, type ChartType, type CompareSeriesOptions, type CrosshairMoveEvent, type CrosshairOptions, type CrosshairPriceActionEvent, type DashPatternOptions, type DataLineOptions, type DatafeedBarsRequest, type DatafeedOptions, type DownsamplingOptions, type DrawingBounds, type DrawingDefaults, type DrawingHoverEvent, type DrawingObjectOptions, type DrawingPoint, type DrawingSelectEvent, type DrawingSelectionChangeEvent, type DrawingToolType, FIB_DEFAULT_PALETTE, type GridOptions, type IndicatorInstanceOptions, type IndicatorPane, type IndicatorPaneActionEvent, type IndicatorPaneAxisOptions, type IndicatorPaneGuideLine, type IndicatorPaneHeightChangeEvent, type IndicatorPaneRenderInfo, type IndicatorPaneValue, type IndicatorPaneValueLabel, type IndicatorPlugin, type IndicatorRenderContext, type IndicatorUpdateOptions, type KeyboardOptions, type LabelsOptions, type OhlcDataPoint, type OrderActionButton, type OrderActionEvent, type OrderLineOptions, POSITION_DEFAULT_COLORS, type PriceLineOptions, type PriceScaleMode, type PriceScaleOptions, SCRIPT_SOURCE_INPUT_VALUES, type ScriptComputeResult, type ScriptIndicatorDefinition, type ScriptIndicatorInputDef, type ScriptInputHelper, type ScriptInputOptions, type ScriptPlotSpec, type TickerLineOptions, type TouchOptions, type TradeMarkerOptions, type ViewportState, type WatermarkOptions, compileScriptIndicator, createChart, extractScriptInputs, validateScriptSource };
package/dist/index.d.ts CHANGED
@@ -83,6 +83,9 @@ interface ChartOptions {
83
83
  downsampling?: DownsamplingOptions;
84
84
  touch?: TouchOptions;
85
85
  datafeedOptions?: DatafeedOptions;
86
+ dataLine?: DataLineOptions;
87
+ animation?: AnimationOptions;
88
+ indicatorUpdate?: IndicatorUpdateOptions;
86
89
  crosshair?: CrosshairOptions;
87
90
  grid?: GridOptions;
88
91
  watermark?: WatermarkOptions;
@@ -635,7 +638,68 @@ interface ChartTheme {
635
638
  /** Background for preview labels and pills. */
636
639
  labelBackground: string;
637
640
  }
638
- type ChartThemeName = "dark" | "light" | "midnight" | "high-contrast";
641
+ type ChartThemeName = "midnight" | "light" | "brand" | "dark" | "high-contrast";
642
+ /**
643
+ * The symbol/OHLC line drawn inside the top-left of the plot, like
644
+ * TradingView's data line. Values follow the crosshair while hovering and fall
645
+ * back to the latest bar otherwise. Opt-in, because hosts that already render
646
+ * their own DOM overlay shouldn't suddenly get two.
647
+ */
648
+ interface DataLineOptions {
649
+ /** Default false. */
650
+ visible?: boolean;
651
+ /** e.g. "NQU6" — drawn first, in the emphasis color. */
652
+ symbol?: string;
653
+ /** e.g. "1h". */
654
+ interval?: string;
655
+ /** e.g. "CME". */
656
+ exchange?: string;
657
+ /** O/H/L/C values for the hovered (or latest) bar. Default true. */
658
+ showOhlc?: boolean;
659
+ /** Absolute and percent change of that bar, colored by direction. Default true. */
660
+ showChange?: boolean;
661
+ /** Bar volume. Default false. */
662
+ showVolume?: boolean;
663
+ /**
664
+ * Extra chips after the values — session, currency, a "Closed" badge. Each
665
+ * renders as `label value` with an optional color and pill background.
666
+ */
667
+ details?: Array<{
668
+ label?: string;
669
+ value: string;
670
+ color?: string;
671
+ background?: string;
672
+ }>;
673
+ /** Colored dot before the symbol, e.g. green when the market is open. */
674
+ statusColor?: string;
675
+ fontSize?: number;
676
+ /** Symbol color. Defaults to the axis text color. */
677
+ symbolColor?: string;
678
+ /** Everything after the symbol. Defaults to the indicator legend color. */
679
+ textColor?: string;
680
+ }
681
+ interface IndicatorUpdateOptions {
682
+ /**
683
+ * While only the forming bar is ticking, recompute indicator series at most
684
+ * this often (ms) rather than on every frame. Values are always exact — this
685
+ * changes how often the live bar's output refreshes, not how it's computed,
686
+ * and anything structural (a bar closing, history loading, inputs changing)
687
+ * recomputes immediately. Default 80; set 0 to recompute every frame.
688
+ */
689
+ liveThrottleMs?: number;
690
+ }
691
+ interface AnimationOptions {
692
+ /**
693
+ * Ease the big viewport jumps — reset, fit-all, scroll-to-realtime — instead
694
+ * of teleporting, so it stays obvious which way the chart moved. Continuous
695
+ * gestures (drag, wheel, pinch) are never animated; they already follow the
696
+ * hand. Default true, and always skipped when the OS asks for reduced
697
+ * motion.
698
+ */
699
+ viewportTransitions?: boolean;
700
+ /** Transition length in ms. Default 260. */
701
+ durationMs?: number;
702
+ }
639
703
  /** Touch ergonomics. Fingers are blunter than a mouse cursor. */
640
704
  interface TouchOptions {
641
705
  /**
@@ -1066,16 +1130,16 @@ declare const compileScriptIndicator: (definition: ScriptIndicatorDefinition) =>
1066
1130
  /**
1067
1131
  * Built-in palettes.
1068
1132
  *
1069
- * `dark` and `light` mirror TradingView's own chart colors (sampled from their
1070
- * rendered canvas), which is what most traders' eyes are calibrated to: the
1071
- * candle colors stay the same across both and only the surface changes.
1072
- * `midnight` is Hyperprop's long-standing default, kept as a named preset so
1073
- * existing setups have something to go back to. `high-contrast` trades
1074
- * prettiness for legibility on projectors and for low-vision users.
1133
+ * `midnight` is the long-standing default and `light` is its counterpart on a
1134
+ * white surface same candle colors, so switching surfaces doesn't change how
1135
+ * you read the tape. `brand` tints everything toward Hyperprop blue, `dark` is
1136
+ * a neutral near-black for embedders who want no tint at all, and
1137
+ * `high-contrast` trades subtlety for legibility on projectors and for
1138
+ * low-vision users.
1075
1139
  */
1076
1140
  declare const CHART_THEMES: Record<ChartThemeName, ChartTheme>;
1077
1141
  declare const CHART_THEME_NAMES: ChartThemeName[];
1078
1142
 
1079
1143
  declare function createChart(element: HTMLElement, options?: ChartOptions): ChartInstance;
1080
1144
 
1081
- export { type AccessibilityOptions, type AxisOptions, type BuiltInIndicatorInfo, CHART_THEMES, CHART_THEME_NAMES, type ChartClickEvent, type ChartContextMenuEvent, type ChartContextMenuRegion, type ChartDatafeed, type ChartInstance, type ChartKeyboardAction, type ChartKeyboardShortcutEvent, type ChartLongPressEvent, type ChartOptions, type ChartSavedState, type ChartTheme, type ChartThemeName, type ChartType, type CompareSeriesOptions, type CrosshairMoveEvent, type CrosshairOptions, type CrosshairPriceActionEvent, type DashPatternOptions, type DatafeedBarsRequest, type DatafeedOptions, type DownsamplingOptions, type DrawingBounds, type DrawingDefaults, type DrawingHoverEvent, type DrawingObjectOptions, type DrawingPoint, type DrawingSelectEvent, type DrawingSelectionChangeEvent, type DrawingToolType, FIB_DEFAULT_PALETTE, type GridOptions, type IndicatorInstanceOptions, type IndicatorPane, type IndicatorPaneActionEvent, type IndicatorPaneAxisOptions, type IndicatorPaneGuideLine, type IndicatorPaneHeightChangeEvent, type IndicatorPaneRenderInfo, type IndicatorPaneValue, type IndicatorPaneValueLabel, type IndicatorPlugin, type IndicatorRenderContext, type KeyboardOptions, type LabelsOptions, type OhlcDataPoint, type OrderActionButton, type OrderActionEvent, type OrderLineOptions, POSITION_DEFAULT_COLORS, type PriceLineOptions, type PriceScaleMode, type PriceScaleOptions, SCRIPT_SOURCE_INPUT_VALUES, type ScriptComputeResult, type ScriptIndicatorDefinition, type ScriptIndicatorInputDef, type ScriptInputHelper, type ScriptInputOptions, type ScriptPlotSpec, type TickerLineOptions, type TouchOptions, type TradeMarkerOptions, type ViewportState, type WatermarkOptions, compileScriptIndicator, createChart, extractScriptInputs, validateScriptSource };
1145
+ export { type AccessibilityOptions, type AnimationOptions, type AxisOptions, type BuiltInIndicatorInfo, CHART_THEMES, CHART_THEME_NAMES, type ChartClickEvent, type ChartContextMenuEvent, type ChartContextMenuRegion, type ChartDatafeed, type ChartInstance, type ChartKeyboardAction, type ChartKeyboardShortcutEvent, type ChartLongPressEvent, type ChartOptions, type ChartSavedState, type ChartTheme, type ChartThemeName, type ChartType, type CompareSeriesOptions, type CrosshairMoveEvent, type CrosshairOptions, type CrosshairPriceActionEvent, type DashPatternOptions, type DataLineOptions, type DatafeedBarsRequest, type DatafeedOptions, type DownsamplingOptions, type DrawingBounds, type DrawingDefaults, type DrawingHoverEvent, type DrawingObjectOptions, type DrawingPoint, type DrawingSelectEvent, type DrawingSelectionChangeEvent, type DrawingToolType, FIB_DEFAULT_PALETTE, type GridOptions, type IndicatorInstanceOptions, type IndicatorPane, type IndicatorPaneActionEvent, type IndicatorPaneAxisOptions, type IndicatorPaneGuideLine, type IndicatorPaneHeightChangeEvent, type IndicatorPaneRenderInfo, type IndicatorPaneValue, type IndicatorPaneValueLabel, type IndicatorPlugin, type IndicatorRenderContext, type IndicatorUpdateOptions, type KeyboardOptions, type LabelsOptions, type OhlcDataPoint, type OrderActionButton, type OrderActionEvent, type OrderLineOptions, POSITION_DEFAULT_COLORS, type PriceLineOptions, type PriceScaleMode, type PriceScaleOptions, SCRIPT_SOURCE_INPUT_VALUES, type ScriptComputeResult, type ScriptIndicatorDefinition, type ScriptIndicatorInputDef, type ScriptInputHelper, type ScriptInputOptions, type ScriptPlotSpec, type TickerLineOptions, type TouchOptions, type TradeMarkerOptions, type ViewportState, type WatermarkOptions, compileScriptIndicator, createChart, extractScriptInputs, validateScriptSource };