hyperprop-charting-library 0.1.41 → 0.1.43

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.
@@ -599,7 +599,8 @@ var BUILTIN_VOLUME_INDICATOR = {
599
599
  if (!point || point.v === void 0 || point.v <= 0) {
600
600
  continue;
601
601
  }
602
- const clampedVolume = Math.min(maxVolume, Math.max(0, point.v));
602
+ const displayVolume = renderContext.getVolumeByIndex(index) ?? point.v;
603
+ const clampedVolume = Math.min(maxVolume, Math.max(0, displayVolume));
603
604
  const ratio = scaleType === "linear" ? Math.min(1, Math.max(0, clampedVolume / maxVolume)) : scaleType === "log" ? Math.min(1, Math.max(0, Math.log1p(clampedVolume) / Math.log1p(maxVolume))) : Math.min(1, Math.max(0, Math.sqrt(clampedVolume) / Math.sqrt(maxVolume)));
604
605
  const volumeHeight = Math.max(1, Math.round(paneHeight * ratio));
605
606
  const xCenter = xFromIndex(index);
@@ -853,13 +854,19 @@ function createChart(element, options = {}) {
853
854
  let doubleClickAction = mergedOptions.doubleClickAction;
854
855
  let smoothedTickerPrice = null;
855
856
  let tickerPriceTarget = null;
857
+ let smoothedTickerVolume = null;
858
+ let tickerVolumeTarget = null;
856
859
  let smoothingRafId = null;
857
860
  const tickerSmoothingLoop = () => {
858
861
  smoothingRafId = null;
859
- if (smoothedTickerPrice === null || tickerPriceTarget === null) return;
860
- const diff = tickerPriceTarget - smoothedTickerPrice;
861
- if (Math.abs(diff) < 1e-9) {
862
+ if (smoothedTickerPrice === null || tickerPriceTarget === null || smoothedTickerVolume === null || tickerVolumeTarget === null) {
863
+ return;
864
+ }
865
+ const priceDiff = tickerPriceTarget - smoothedTickerPrice;
866
+ const volumeDiff = tickerVolumeTarget - smoothedTickerVolume;
867
+ if (Math.abs(priceDiff) < 1e-9 && Math.abs(volumeDiff) < 1e-6) {
862
868
  smoothedTickerPrice = tickerPriceTarget;
869
+ smoothedTickerVolume = tickerVolumeTarget;
863
870
  draw({ updateAutoScale: false });
864
871
  return;
865
872
  }
@@ -867,20 +874,28 @@ function createChart(element, options = {}) {
867
874
  const speed = clamp(tickerOpts.smoothingSpeed ?? 8, 1, 60);
868
875
  const dt = 1 / 60;
869
876
  const lerp = 1 - Math.exp(-speed * dt);
870
- smoothedTickerPrice += diff * lerp;
877
+ smoothedTickerPrice += priceDiff * lerp;
878
+ smoothedTickerVolume += volumeDiff * lerp;
871
879
  draw({ updateAutoScale: false });
872
880
  smoothingRafId = requestAnimationFrame(tickerSmoothingLoop);
873
881
  };
874
- const pushSmoothedPrice = (target) => {
882
+ const pushSmoothedTicker = (targetPrice, targetVolume) => {
875
883
  const tickerOpts = mergedOptions.tickerLine ?? DEFAULT_OPTIONS.tickerLine;
876
884
  if (!tickerOpts.smoothing) {
877
885
  smoothedTickerPrice = null;
878
886
  tickerPriceTarget = null;
887
+ smoothedTickerVolume = null;
888
+ tickerVolumeTarget = null;
879
889
  return;
880
890
  }
881
- tickerPriceTarget = target;
891
+ const normalizedVolume = Math.max(0, targetVolume ?? 0);
892
+ tickerPriceTarget = targetPrice;
893
+ tickerVolumeTarget = normalizedVolume;
882
894
  if (smoothedTickerPrice === null) {
883
- smoothedTickerPrice = target;
895
+ smoothedTickerPrice = targetPrice;
896
+ }
897
+ if (smoothedTickerVolume === null) {
898
+ smoothedTickerVolume = normalizedVolume;
884
899
  }
885
900
  if (smoothingRafId === null) {
886
901
  smoothingRafId = requestAnimationFrame(tickerSmoothingLoop);
@@ -1853,6 +1868,12 @@ function createChart(element, options = {}) {
1853
1868
  const tickerOpts = mergedOptions.tickerLine ?? DEFAULT_OPTIONS.tickerLine;
1854
1869
  const useSmoothedCandle = tickerOpts.smoothing && smoothedTickerPrice !== null;
1855
1870
  const lastDataIndex = data.length - 1;
1871
+ const getVolumeByIndex = (index) => {
1872
+ if (useSmoothedCandle && index === lastDataIndex && smoothedTickerVolume !== null) {
1873
+ return smoothedTickerVolume;
1874
+ }
1875
+ return data[index]?.v;
1876
+ };
1856
1877
  for (let index = startIndex; index <= endIndex; index += 1) {
1857
1878
  const point = data[index];
1858
1879
  if (!point) {
@@ -1909,6 +1930,7 @@ function createChart(element, options = {}) {
1909
1930
  xFromIndex,
1910
1931
  yFromPrice,
1911
1932
  getCandleDirectionByIndex,
1933
+ getVolumeByIndex,
1912
1934
  candleSpacing,
1913
1935
  upColor: mergedOptions.upColor,
1914
1936
  downColor: mergedOptions.downColor
@@ -1969,6 +1991,7 @@ function createChart(element, options = {}) {
1969
1991
  xFromIndex,
1970
1992
  yFromPrice: null,
1971
1993
  getCandleDirectionByIndex,
1994
+ getVolumeByIndex,
1972
1995
  candleSpacing,
1973
1996
  upColor: mergedOptions.upColor,
1974
1997
  downColor: mergedOptions.downColor
@@ -2680,7 +2703,7 @@ function createChart(element, options = {}) {
2680
2703
  setCrosshairPoint(null);
2681
2704
  } else if (dragMode === "x-axis") {
2682
2705
  canvas.style.cursor = "ew-resize";
2683
- zoomXToLatest(Math.exp(-deltaX * 0.01));
2706
+ zoomXToLatest(Math.exp(deltaX * 6e-3));
2684
2707
  setCrosshairPoint(null);
2685
2708
  } else if (dragMode === "y-axis") {
2686
2709
  canvas.style.cursor = "ns-resize";
@@ -2827,12 +2850,15 @@ function createChart(element, options = {}) {
2827
2850
  if (!isTickerSmoothingEnabled) {
2828
2851
  smoothedTickerPrice = null;
2829
2852
  tickerPriceTarget = null;
2853
+ smoothedTickerVolume = null;
2854
+ tickerVolumeTarget = null;
2830
2855
  if (smoothingRafId !== null) {
2831
2856
  cancelAnimationFrame(smoothingRafId);
2832
2857
  smoothingRafId = null;
2833
2858
  }
2834
2859
  } else if (!wasTickerSmoothingEnabled && data.length > 0) {
2835
- pushSmoothedPrice(data[data.length - 1].c);
2860
+ const lastPoint = data[data.length - 1];
2861
+ pushSmoothedTicker(lastPoint.c, lastPoint.v);
2836
2862
  }
2837
2863
  draw();
2838
2864
  };
@@ -2856,6 +2882,10 @@ function createChart(element, options = {}) {
2856
2882
  if (data.length === 0) {
2857
2883
  xCenter = 0;
2858
2884
  xSpan = 60;
2885
+ smoothedTickerPrice = null;
2886
+ tickerPriceTarget = null;
2887
+ smoothedTickerVolume = null;
2888
+ tickerVolumeTarget = null;
2859
2889
  resetYViewport();
2860
2890
  draw();
2861
2891
  return;
@@ -2878,9 +2908,9 @@ function createChart(element, options = {}) {
2878
2908
  fitXViewport();
2879
2909
  }
2880
2910
  }
2881
- const lastClose = data.length > 0 ? data[data.length - 1].c : null;
2882
- if (lastClose !== null) {
2883
- pushSmoothedPrice(lastClose);
2911
+ const lastPoint = data[data.length - 1];
2912
+ if (lastPoint) {
2913
+ pushSmoothedTicker(lastPoint.c, lastPoint.v);
2884
2914
  }
2885
2915
  draw();
2886
2916
  };
@@ -74,6 +74,7 @@ interface IndicatorRenderContext {
74
74
  xFromIndex: (index: number) => number;
75
75
  yFromPrice: ((price: number) => number) | null;
76
76
  getCandleDirectionByIndex: (index: number) => "up" | "down";
77
+ getVolumeByIndex: (index: number) => number | undefined;
77
78
  candleSpacing: number;
78
79
  upColor: string;
79
80
  downColor: string;
@@ -575,7 +575,8 @@ var BUILTIN_VOLUME_INDICATOR = {
575
575
  if (!point || point.v === void 0 || point.v <= 0) {
576
576
  continue;
577
577
  }
578
- const clampedVolume = Math.min(maxVolume, Math.max(0, point.v));
578
+ const displayVolume = renderContext.getVolumeByIndex(index) ?? point.v;
579
+ const clampedVolume = Math.min(maxVolume, Math.max(0, displayVolume));
579
580
  const ratio = scaleType === "linear" ? Math.min(1, Math.max(0, clampedVolume / maxVolume)) : scaleType === "log" ? Math.min(1, Math.max(0, Math.log1p(clampedVolume) / Math.log1p(maxVolume))) : Math.min(1, Math.max(0, Math.sqrt(clampedVolume) / Math.sqrt(maxVolume)));
580
581
  const volumeHeight = Math.max(1, Math.round(paneHeight * ratio));
581
582
  const xCenter = xFromIndex(index);
@@ -829,13 +830,19 @@ function createChart(element, options = {}) {
829
830
  let doubleClickAction = mergedOptions.doubleClickAction;
830
831
  let smoothedTickerPrice = null;
831
832
  let tickerPriceTarget = null;
833
+ let smoothedTickerVolume = null;
834
+ let tickerVolumeTarget = null;
832
835
  let smoothingRafId = null;
833
836
  const tickerSmoothingLoop = () => {
834
837
  smoothingRafId = null;
835
- if (smoothedTickerPrice === null || tickerPriceTarget === null) return;
836
- const diff = tickerPriceTarget - smoothedTickerPrice;
837
- if (Math.abs(diff) < 1e-9) {
838
+ if (smoothedTickerPrice === null || tickerPriceTarget === null || smoothedTickerVolume === null || tickerVolumeTarget === null) {
839
+ return;
840
+ }
841
+ const priceDiff = tickerPriceTarget - smoothedTickerPrice;
842
+ const volumeDiff = tickerVolumeTarget - smoothedTickerVolume;
843
+ if (Math.abs(priceDiff) < 1e-9 && Math.abs(volumeDiff) < 1e-6) {
838
844
  smoothedTickerPrice = tickerPriceTarget;
845
+ smoothedTickerVolume = tickerVolumeTarget;
839
846
  draw({ updateAutoScale: false });
840
847
  return;
841
848
  }
@@ -843,20 +850,28 @@ function createChart(element, options = {}) {
843
850
  const speed = clamp(tickerOpts.smoothingSpeed ?? 8, 1, 60);
844
851
  const dt = 1 / 60;
845
852
  const lerp = 1 - Math.exp(-speed * dt);
846
- smoothedTickerPrice += diff * lerp;
853
+ smoothedTickerPrice += priceDiff * lerp;
854
+ smoothedTickerVolume += volumeDiff * lerp;
847
855
  draw({ updateAutoScale: false });
848
856
  smoothingRafId = requestAnimationFrame(tickerSmoothingLoop);
849
857
  };
850
- const pushSmoothedPrice = (target) => {
858
+ const pushSmoothedTicker = (targetPrice, targetVolume) => {
851
859
  const tickerOpts = mergedOptions.tickerLine ?? DEFAULT_OPTIONS.tickerLine;
852
860
  if (!tickerOpts.smoothing) {
853
861
  smoothedTickerPrice = null;
854
862
  tickerPriceTarget = null;
863
+ smoothedTickerVolume = null;
864
+ tickerVolumeTarget = null;
855
865
  return;
856
866
  }
857
- tickerPriceTarget = target;
867
+ const normalizedVolume = Math.max(0, targetVolume ?? 0);
868
+ tickerPriceTarget = targetPrice;
869
+ tickerVolumeTarget = normalizedVolume;
858
870
  if (smoothedTickerPrice === null) {
859
- smoothedTickerPrice = target;
871
+ smoothedTickerPrice = targetPrice;
872
+ }
873
+ if (smoothedTickerVolume === null) {
874
+ smoothedTickerVolume = normalizedVolume;
860
875
  }
861
876
  if (smoothingRafId === null) {
862
877
  smoothingRafId = requestAnimationFrame(tickerSmoothingLoop);
@@ -1829,6 +1844,12 @@ function createChart(element, options = {}) {
1829
1844
  const tickerOpts = mergedOptions.tickerLine ?? DEFAULT_OPTIONS.tickerLine;
1830
1845
  const useSmoothedCandle = tickerOpts.smoothing && smoothedTickerPrice !== null;
1831
1846
  const lastDataIndex = data.length - 1;
1847
+ const getVolumeByIndex = (index) => {
1848
+ if (useSmoothedCandle && index === lastDataIndex && smoothedTickerVolume !== null) {
1849
+ return smoothedTickerVolume;
1850
+ }
1851
+ return data[index]?.v;
1852
+ };
1832
1853
  for (let index = startIndex; index <= endIndex; index += 1) {
1833
1854
  const point = data[index];
1834
1855
  if (!point) {
@@ -1885,6 +1906,7 @@ function createChart(element, options = {}) {
1885
1906
  xFromIndex,
1886
1907
  yFromPrice,
1887
1908
  getCandleDirectionByIndex,
1909
+ getVolumeByIndex,
1888
1910
  candleSpacing,
1889
1911
  upColor: mergedOptions.upColor,
1890
1912
  downColor: mergedOptions.downColor
@@ -1945,6 +1967,7 @@ function createChart(element, options = {}) {
1945
1967
  xFromIndex,
1946
1968
  yFromPrice: null,
1947
1969
  getCandleDirectionByIndex,
1970
+ getVolumeByIndex,
1948
1971
  candleSpacing,
1949
1972
  upColor: mergedOptions.upColor,
1950
1973
  downColor: mergedOptions.downColor
@@ -2656,7 +2679,7 @@ function createChart(element, options = {}) {
2656
2679
  setCrosshairPoint(null);
2657
2680
  } else if (dragMode === "x-axis") {
2658
2681
  canvas.style.cursor = "ew-resize";
2659
- zoomXToLatest(Math.exp(-deltaX * 0.01));
2682
+ zoomXToLatest(Math.exp(deltaX * 6e-3));
2660
2683
  setCrosshairPoint(null);
2661
2684
  } else if (dragMode === "y-axis") {
2662
2685
  canvas.style.cursor = "ns-resize";
@@ -2803,12 +2826,15 @@ function createChart(element, options = {}) {
2803
2826
  if (!isTickerSmoothingEnabled) {
2804
2827
  smoothedTickerPrice = null;
2805
2828
  tickerPriceTarget = null;
2829
+ smoothedTickerVolume = null;
2830
+ tickerVolumeTarget = null;
2806
2831
  if (smoothingRafId !== null) {
2807
2832
  cancelAnimationFrame(smoothingRafId);
2808
2833
  smoothingRafId = null;
2809
2834
  }
2810
2835
  } else if (!wasTickerSmoothingEnabled && data.length > 0) {
2811
- pushSmoothedPrice(data[data.length - 1].c);
2836
+ const lastPoint = data[data.length - 1];
2837
+ pushSmoothedTicker(lastPoint.c, lastPoint.v);
2812
2838
  }
2813
2839
  draw();
2814
2840
  };
@@ -2832,6 +2858,10 @@ function createChart(element, options = {}) {
2832
2858
  if (data.length === 0) {
2833
2859
  xCenter = 0;
2834
2860
  xSpan = 60;
2861
+ smoothedTickerPrice = null;
2862
+ tickerPriceTarget = null;
2863
+ smoothedTickerVolume = null;
2864
+ tickerVolumeTarget = null;
2835
2865
  resetYViewport();
2836
2866
  draw();
2837
2867
  return;
@@ -2854,9 +2884,9 @@ function createChart(element, options = {}) {
2854
2884
  fitXViewport();
2855
2885
  }
2856
2886
  }
2857
- const lastClose = data.length > 0 ? data[data.length - 1].c : null;
2858
- if (lastClose !== null) {
2859
- pushSmoothedPrice(lastClose);
2887
+ const lastPoint = data[data.length - 1];
2888
+ if (lastPoint) {
2889
+ pushSmoothedTicker(lastPoint.c, lastPoint.v);
2860
2890
  }
2861
2891
  draw();
2862
2892
  };
package/dist/index.cjs CHANGED
@@ -599,7 +599,8 @@ var BUILTIN_VOLUME_INDICATOR = {
599
599
  if (!point || point.v === void 0 || point.v <= 0) {
600
600
  continue;
601
601
  }
602
- const clampedVolume = Math.min(maxVolume, Math.max(0, point.v));
602
+ const displayVolume = renderContext.getVolumeByIndex(index) ?? point.v;
603
+ const clampedVolume = Math.min(maxVolume, Math.max(0, displayVolume));
603
604
  const ratio = scaleType === "linear" ? Math.min(1, Math.max(0, clampedVolume / maxVolume)) : scaleType === "log" ? Math.min(1, Math.max(0, Math.log1p(clampedVolume) / Math.log1p(maxVolume))) : Math.min(1, Math.max(0, Math.sqrt(clampedVolume) / Math.sqrt(maxVolume)));
604
605
  const volumeHeight = Math.max(1, Math.round(paneHeight * ratio));
605
606
  const xCenter = xFromIndex(index);
@@ -853,13 +854,19 @@ function createChart(element, options = {}) {
853
854
  let doubleClickAction = mergedOptions.doubleClickAction;
854
855
  let smoothedTickerPrice = null;
855
856
  let tickerPriceTarget = null;
857
+ let smoothedTickerVolume = null;
858
+ let tickerVolumeTarget = null;
856
859
  let smoothingRafId = null;
857
860
  const tickerSmoothingLoop = () => {
858
861
  smoothingRafId = null;
859
- if (smoothedTickerPrice === null || tickerPriceTarget === null) return;
860
- const diff = tickerPriceTarget - smoothedTickerPrice;
861
- if (Math.abs(diff) < 1e-9) {
862
+ if (smoothedTickerPrice === null || tickerPriceTarget === null || smoothedTickerVolume === null || tickerVolumeTarget === null) {
863
+ return;
864
+ }
865
+ const priceDiff = tickerPriceTarget - smoothedTickerPrice;
866
+ const volumeDiff = tickerVolumeTarget - smoothedTickerVolume;
867
+ if (Math.abs(priceDiff) < 1e-9 && Math.abs(volumeDiff) < 1e-6) {
862
868
  smoothedTickerPrice = tickerPriceTarget;
869
+ smoothedTickerVolume = tickerVolumeTarget;
863
870
  draw({ updateAutoScale: false });
864
871
  return;
865
872
  }
@@ -867,20 +874,28 @@ function createChart(element, options = {}) {
867
874
  const speed = clamp(tickerOpts.smoothingSpeed ?? 8, 1, 60);
868
875
  const dt = 1 / 60;
869
876
  const lerp = 1 - Math.exp(-speed * dt);
870
- smoothedTickerPrice += diff * lerp;
877
+ smoothedTickerPrice += priceDiff * lerp;
878
+ smoothedTickerVolume += volumeDiff * lerp;
871
879
  draw({ updateAutoScale: false });
872
880
  smoothingRafId = requestAnimationFrame(tickerSmoothingLoop);
873
881
  };
874
- const pushSmoothedPrice = (target) => {
882
+ const pushSmoothedTicker = (targetPrice, targetVolume) => {
875
883
  const tickerOpts = mergedOptions.tickerLine ?? DEFAULT_OPTIONS.tickerLine;
876
884
  if (!tickerOpts.smoothing) {
877
885
  smoothedTickerPrice = null;
878
886
  tickerPriceTarget = null;
887
+ smoothedTickerVolume = null;
888
+ tickerVolumeTarget = null;
879
889
  return;
880
890
  }
881
- tickerPriceTarget = target;
891
+ const normalizedVolume = Math.max(0, targetVolume ?? 0);
892
+ tickerPriceTarget = targetPrice;
893
+ tickerVolumeTarget = normalizedVolume;
882
894
  if (smoothedTickerPrice === null) {
883
- smoothedTickerPrice = target;
895
+ smoothedTickerPrice = targetPrice;
896
+ }
897
+ if (smoothedTickerVolume === null) {
898
+ smoothedTickerVolume = normalizedVolume;
884
899
  }
885
900
  if (smoothingRafId === null) {
886
901
  smoothingRafId = requestAnimationFrame(tickerSmoothingLoop);
@@ -1853,6 +1868,12 @@ function createChart(element, options = {}) {
1853
1868
  const tickerOpts = mergedOptions.tickerLine ?? DEFAULT_OPTIONS.tickerLine;
1854
1869
  const useSmoothedCandle = tickerOpts.smoothing && smoothedTickerPrice !== null;
1855
1870
  const lastDataIndex = data.length - 1;
1871
+ const getVolumeByIndex = (index) => {
1872
+ if (useSmoothedCandle && index === lastDataIndex && smoothedTickerVolume !== null) {
1873
+ return smoothedTickerVolume;
1874
+ }
1875
+ return data[index]?.v;
1876
+ };
1856
1877
  for (let index = startIndex; index <= endIndex; index += 1) {
1857
1878
  const point = data[index];
1858
1879
  if (!point) {
@@ -1909,6 +1930,7 @@ function createChart(element, options = {}) {
1909
1930
  xFromIndex,
1910
1931
  yFromPrice,
1911
1932
  getCandleDirectionByIndex,
1933
+ getVolumeByIndex,
1912
1934
  candleSpacing,
1913
1935
  upColor: mergedOptions.upColor,
1914
1936
  downColor: mergedOptions.downColor
@@ -1969,6 +1991,7 @@ function createChart(element, options = {}) {
1969
1991
  xFromIndex,
1970
1992
  yFromPrice: null,
1971
1993
  getCandleDirectionByIndex,
1994
+ getVolumeByIndex,
1972
1995
  candleSpacing,
1973
1996
  upColor: mergedOptions.upColor,
1974
1997
  downColor: mergedOptions.downColor
@@ -2680,7 +2703,7 @@ function createChart(element, options = {}) {
2680
2703
  setCrosshairPoint(null);
2681
2704
  } else if (dragMode === "x-axis") {
2682
2705
  canvas.style.cursor = "ew-resize";
2683
- zoomXToLatest(Math.exp(-deltaX * 0.01));
2706
+ zoomXToLatest(Math.exp(deltaX * 6e-3));
2684
2707
  setCrosshairPoint(null);
2685
2708
  } else if (dragMode === "y-axis") {
2686
2709
  canvas.style.cursor = "ns-resize";
@@ -2827,12 +2850,15 @@ function createChart(element, options = {}) {
2827
2850
  if (!isTickerSmoothingEnabled) {
2828
2851
  smoothedTickerPrice = null;
2829
2852
  tickerPriceTarget = null;
2853
+ smoothedTickerVolume = null;
2854
+ tickerVolumeTarget = null;
2830
2855
  if (smoothingRafId !== null) {
2831
2856
  cancelAnimationFrame(smoothingRafId);
2832
2857
  smoothingRafId = null;
2833
2858
  }
2834
2859
  } else if (!wasTickerSmoothingEnabled && data.length > 0) {
2835
- pushSmoothedPrice(data[data.length - 1].c);
2860
+ const lastPoint = data[data.length - 1];
2861
+ pushSmoothedTicker(lastPoint.c, lastPoint.v);
2836
2862
  }
2837
2863
  draw();
2838
2864
  };
@@ -2856,6 +2882,10 @@ function createChart(element, options = {}) {
2856
2882
  if (data.length === 0) {
2857
2883
  xCenter = 0;
2858
2884
  xSpan = 60;
2885
+ smoothedTickerPrice = null;
2886
+ tickerPriceTarget = null;
2887
+ smoothedTickerVolume = null;
2888
+ tickerVolumeTarget = null;
2859
2889
  resetYViewport();
2860
2890
  draw();
2861
2891
  return;
@@ -2878,9 +2908,9 @@ function createChart(element, options = {}) {
2878
2908
  fitXViewport();
2879
2909
  }
2880
2910
  }
2881
- const lastClose = data.length > 0 ? data[data.length - 1].c : null;
2882
- if (lastClose !== null) {
2883
- pushSmoothedPrice(lastClose);
2911
+ const lastPoint = data[data.length - 1];
2912
+ if (lastPoint) {
2913
+ pushSmoothedTicker(lastPoint.c, lastPoint.v);
2884
2914
  }
2885
2915
  draw();
2886
2916
  };
package/dist/index.d.cts CHANGED
@@ -74,6 +74,7 @@ interface IndicatorRenderContext {
74
74
  xFromIndex: (index: number) => number;
75
75
  yFromPrice: ((price: number) => number) | null;
76
76
  getCandleDirectionByIndex: (index: number) => "up" | "down";
77
+ getVolumeByIndex: (index: number) => number | undefined;
77
78
  candleSpacing: number;
78
79
  upColor: string;
79
80
  downColor: string;
package/dist/index.d.ts CHANGED
@@ -74,6 +74,7 @@ interface IndicatorRenderContext {
74
74
  xFromIndex: (index: number) => number;
75
75
  yFromPrice: ((price: number) => number) | null;
76
76
  getCandleDirectionByIndex: (index: number) => "up" | "down";
77
+ getVolumeByIndex: (index: number) => number | undefined;
77
78
  candleSpacing: number;
78
79
  upColor: string;
79
80
  downColor: string;
package/dist/index.js CHANGED
@@ -575,7 +575,8 @@ var BUILTIN_VOLUME_INDICATOR = {
575
575
  if (!point || point.v === void 0 || point.v <= 0) {
576
576
  continue;
577
577
  }
578
- const clampedVolume = Math.min(maxVolume, Math.max(0, point.v));
578
+ const displayVolume = renderContext.getVolumeByIndex(index) ?? point.v;
579
+ const clampedVolume = Math.min(maxVolume, Math.max(0, displayVolume));
579
580
  const ratio = scaleType === "linear" ? Math.min(1, Math.max(0, clampedVolume / maxVolume)) : scaleType === "log" ? Math.min(1, Math.max(0, Math.log1p(clampedVolume) / Math.log1p(maxVolume))) : Math.min(1, Math.max(0, Math.sqrt(clampedVolume) / Math.sqrt(maxVolume)));
580
581
  const volumeHeight = Math.max(1, Math.round(paneHeight * ratio));
581
582
  const xCenter = xFromIndex(index);
@@ -829,13 +830,19 @@ function createChart(element, options = {}) {
829
830
  let doubleClickAction = mergedOptions.doubleClickAction;
830
831
  let smoothedTickerPrice = null;
831
832
  let tickerPriceTarget = null;
833
+ let smoothedTickerVolume = null;
834
+ let tickerVolumeTarget = null;
832
835
  let smoothingRafId = null;
833
836
  const tickerSmoothingLoop = () => {
834
837
  smoothingRafId = null;
835
- if (smoothedTickerPrice === null || tickerPriceTarget === null) return;
836
- const diff = tickerPriceTarget - smoothedTickerPrice;
837
- if (Math.abs(diff) < 1e-9) {
838
+ if (smoothedTickerPrice === null || tickerPriceTarget === null || smoothedTickerVolume === null || tickerVolumeTarget === null) {
839
+ return;
840
+ }
841
+ const priceDiff = tickerPriceTarget - smoothedTickerPrice;
842
+ const volumeDiff = tickerVolumeTarget - smoothedTickerVolume;
843
+ if (Math.abs(priceDiff) < 1e-9 && Math.abs(volumeDiff) < 1e-6) {
838
844
  smoothedTickerPrice = tickerPriceTarget;
845
+ smoothedTickerVolume = tickerVolumeTarget;
839
846
  draw({ updateAutoScale: false });
840
847
  return;
841
848
  }
@@ -843,20 +850,28 @@ function createChart(element, options = {}) {
843
850
  const speed = clamp(tickerOpts.smoothingSpeed ?? 8, 1, 60);
844
851
  const dt = 1 / 60;
845
852
  const lerp = 1 - Math.exp(-speed * dt);
846
- smoothedTickerPrice += diff * lerp;
853
+ smoothedTickerPrice += priceDiff * lerp;
854
+ smoothedTickerVolume += volumeDiff * lerp;
847
855
  draw({ updateAutoScale: false });
848
856
  smoothingRafId = requestAnimationFrame(tickerSmoothingLoop);
849
857
  };
850
- const pushSmoothedPrice = (target) => {
858
+ const pushSmoothedTicker = (targetPrice, targetVolume) => {
851
859
  const tickerOpts = mergedOptions.tickerLine ?? DEFAULT_OPTIONS.tickerLine;
852
860
  if (!tickerOpts.smoothing) {
853
861
  smoothedTickerPrice = null;
854
862
  tickerPriceTarget = null;
863
+ smoothedTickerVolume = null;
864
+ tickerVolumeTarget = null;
855
865
  return;
856
866
  }
857
- tickerPriceTarget = target;
867
+ const normalizedVolume = Math.max(0, targetVolume ?? 0);
868
+ tickerPriceTarget = targetPrice;
869
+ tickerVolumeTarget = normalizedVolume;
858
870
  if (smoothedTickerPrice === null) {
859
- smoothedTickerPrice = target;
871
+ smoothedTickerPrice = targetPrice;
872
+ }
873
+ if (smoothedTickerVolume === null) {
874
+ smoothedTickerVolume = normalizedVolume;
860
875
  }
861
876
  if (smoothingRafId === null) {
862
877
  smoothingRafId = requestAnimationFrame(tickerSmoothingLoop);
@@ -1829,6 +1844,12 @@ function createChart(element, options = {}) {
1829
1844
  const tickerOpts = mergedOptions.tickerLine ?? DEFAULT_OPTIONS.tickerLine;
1830
1845
  const useSmoothedCandle = tickerOpts.smoothing && smoothedTickerPrice !== null;
1831
1846
  const lastDataIndex = data.length - 1;
1847
+ const getVolumeByIndex = (index) => {
1848
+ if (useSmoothedCandle && index === lastDataIndex && smoothedTickerVolume !== null) {
1849
+ return smoothedTickerVolume;
1850
+ }
1851
+ return data[index]?.v;
1852
+ };
1832
1853
  for (let index = startIndex; index <= endIndex; index += 1) {
1833
1854
  const point = data[index];
1834
1855
  if (!point) {
@@ -1885,6 +1906,7 @@ function createChart(element, options = {}) {
1885
1906
  xFromIndex,
1886
1907
  yFromPrice,
1887
1908
  getCandleDirectionByIndex,
1909
+ getVolumeByIndex,
1888
1910
  candleSpacing,
1889
1911
  upColor: mergedOptions.upColor,
1890
1912
  downColor: mergedOptions.downColor
@@ -1945,6 +1967,7 @@ function createChart(element, options = {}) {
1945
1967
  xFromIndex,
1946
1968
  yFromPrice: null,
1947
1969
  getCandleDirectionByIndex,
1970
+ getVolumeByIndex,
1948
1971
  candleSpacing,
1949
1972
  upColor: mergedOptions.upColor,
1950
1973
  downColor: mergedOptions.downColor
@@ -2656,7 +2679,7 @@ function createChart(element, options = {}) {
2656
2679
  setCrosshairPoint(null);
2657
2680
  } else if (dragMode === "x-axis") {
2658
2681
  canvas.style.cursor = "ew-resize";
2659
- zoomXToLatest(Math.exp(-deltaX * 0.01));
2682
+ zoomXToLatest(Math.exp(deltaX * 6e-3));
2660
2683
  setCrosshairPoint(null);
2661
2684
  } else if (dragMode === "y-axis") {
2662
2685
  canvas.style.cursor = "ns-resize";
@@ -2803,12 +2826,15 @@ function createChart(element, options = {}) {
2803
2826
  if (!isTickerSmoothingEnabled) {
2804
2827
  smoothedTickerPrice = null;
2805
2828
  tickerPriceTarget = null;
2829
+ smoothedTickerVolume = null;
2830
+ tickerVolumeTarget = null;
2806
2831
  if (smoothingRafId !== null) {
2807
2832
  cancelAnimationFrame(smoothingRafId);
2808
2833
  smoothingRafId = null;
2809
2834
  }
2810
2835
  } else if (!wasTickerSmoothingEnabled && data.length > 0) {
2811
- pushSmoothedPrice(data[data.length - 1].c);
2836
+ const lastPoint = data[data.length - 1];
2837
+ pushSmoothedTicker(lastPoint.c, lastPoint.v);
2812
2838
  }
2813
2839
  draw();
2814
2840
  };
@@ -2832,6 +2858,10 @@ function createChart(element, options = {}) {
2832
2858
  if (data.length === 0) {
2833
2859
  xCenter = 0;
2834
2860
  xSpan = 60;
2861
+ smoothedTickerPrice = null;
2862
+ tickerPriceTarget = null;
2863
+ smoothedTickerVolume = null;
2864
+ tickerVolumeTarget = null;
2835
2865
  resetYViewport();
2836
2866
  draw();
2837
2867
  return;
@@ -2854,9 +2884,9 @@ function createChart(element, options = {}) {
2854
2884
  fitXViewport();
2855
2885
  }
2856
2886
  }
2857
- const lastClose = data.length > 0 ? data[data.length - 1].c : null;
2858
- if (lastClose !== null) {
2859
- pushSmoothedPrice(lastClose);
2887
+ const lastPoint = data[data.length - 1];
2888
+ if (lastPoint) {
2889
+ pushSmoothedTicker(lastPoint.c, lastPoint.v);
2860
2890
  }
2861
2891
  draw();
2862
2892
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hyperprop-charting-library",
3
- "version": "0.1.41",
3
+ "version": "0.1.43",
4
4
  "description": "Lightweight TypeScript charting core",
5
5
  "type": "module",
6
6
  "main": "./dist/hyperprop-charting-library.cjs",