react-native-vroom-chart 0.12.0 → 0.13.1

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/lib/index.js CHANGED
@@ -514,6 +514,9 @@ function useChartCore(candles, size, visibleRange, defaultCandleWidth, chartType
514
514
  }
515
515
 
516
516
  // src/VroomChart.tsx
517
+ function isSkImage(frame) {
518
+ return typeof frame.getImageInfo === "function";
519
+ }
517
520
  function VroomChart(props) {
518
521
  const {
519
522
  candles,
@@ -565,17 +568,38 @@ function VroomChart(props) {
565
568
  rec.beginRecording(import_react_native_skia.Skia.XYWHRect(0, 0, 1, 1));
566
569
  return rec.finishRecordingAsPicture();
567
570
  }, []);
571
+ const emptyImage = (0, import_react2.useMemo)(() => {
572
+ const data = import_react_native_skia.Skia.Data.fromBytes(new Uint8Array(4));
573
+ return import_react_native_skia.Skia.Image.MakeImage(
574
+ {
575
+ width: 1,
576
+ height: 1,
577
+ colorType: import_react_native_skia.ColorType.RGBA_8888,
578
+ alphaType: import_react_native_skia.AlphaType.Premul
579
+ },
580
+ data,
581
+ 4
582
+ );
583
+ }, []);
568
584
  const pictureSV = (0, import_react_native_reanimated.useSharedValue)(emptyPicture);
585
+ const imageSV = (0, import_react_native_reanimated.useSharedValue)(emptyImage);
586
+ const applyFrame = (0, import_react2.useCallback)(
587
+ (frame) => {
588
+ if (isSkImage(frame)) imageSV.value = frame;
589
+ else pictureSV.value = frame;
590
+ },
591
+ [imageSV, pictureSV]
592
+ );
569
593
  const reduceMotion = (0, import_react_native_reanimated.useReducedMotion)();
570
594
  const onFrame = (0, import_react2.useCallback)(
571
595
  (p) => {
572
- pictureSV.value = p;
596
+ applyFrame(p);
573
597
  },
574
- [pictureSV]
598
+ [applyFrame]
575
599
  );
576
600
  const { handle, picture, volumeCollapseRef } = useChartCore(
577
601
  candles,
578
- { width, height },
602
+ { width, height, pxRatio: import_react_native2.PixelRatio.get() },
579
603
  visibleRange,
580
604
  defaultCandleWidth,
581
605
  chartType,
@@ -604,11 +628,11 @@ function VroomChart(props) {
604
628
  animRaf.current = null;
605
629
  if (!handle) return;
606
630
  const next = handle.render();
607
- if (next) pictureSV.value = next;
631
+ if (next) applyFrame(next);
608
632
  if (handle.isAnimating()) {
609
633
  animRaf.current = requestAnimationFrame(animTick);
610
634
  }
611
- }, [handle, pictureSV]);
635
+ }, [handle, applyFrame]);
612
636
  const maybeStartAnim = (0, import_react2.useCallback)(() => {
613
637
  if (animRaf.current != null) return;
614
638
  if (!handle?.isAnimating()) return;
@@ -623,9 +647,9 @@ function VroomChart(props) {
623
647
  };
624
648
  }, []);
625
649
  (0, import_react2.useEffect)(() => {
626
- if (picture) pictureSV.value = picture;
650
+ if (picture) applyFrame(picture);
627
651
  maybeStartAnim();
628
- }, [picture, pictureSV, maybeStartAnim]);
652
+ }, [picture, applyFrame, maybeStartAnim]);
629
653
  const morphRaf = (0, import_react2.useRef)(null);
630
654
  const morphFade = (0, import_react2.useRef)(null);
631
655
  const morphHandle = (0, import_react2.useRef)(null);
@@ -639,7 +663,7 @@ function VroomChart(props) {
639
663
  morphFade.current = target;
640
664
  handle.setChartType(target);
641
665
  const p = handle.render();
642
- if (p) pictureSV.value = p;
666
+ if (p) applyFrame(p);
643
667
  maybeStartAnim();
644
668
  return void 0;
645
669
  }
@@ -656,7 +680,7 @@ function VroomChart(props) {
656
680
  morphFade.current = target;
657
681
  handle.setChartType(target);
658
682
  const p = handle.render();
659
- if (p) pictureSV.value = p;
683
+ if (p) applyFrame(p);
660
684
  maybeStartAnim();
661
685
  return void 0;
662
686
  }
@@ -669,7 +693,7 @@ function VroomChart(props) {
669
693
  morphFade.current = fade;
670
694
  handle.setMorph(reduceMotion ? 0 : fade, fade);
671
695
  const p = handle.render();
672
- if (p) pictureSV.value = p;
696
+ if (p) applyFrame(p);
673
697
  if (prog < 1) {
674
698
  morphRaf.current = requestAnimationFrame(step);
675
699
  } else {
@@ -677,7 +701,7 @@ function VroomChart(props) {
677
701
  morphFade.current = target;
678
702
  handle.setChartType(target);
679
703
  const q = handle.render();
680
- if (q) pictureSV.value = q;
704
+ if (q) applyFrame(q);
681
705
  maybeStartAnim();
682
706
  }
683
707
  };
@@ -688,7 +712,7 @@ function VroomChart(props) {
688
712
  morphRaf.current = null;
689
713
  }
690
714
  };
691
- }, [handle, chartType, transitionMs, reduceMotion, pictureSV, maybeStartAnim]);
715
+ }, [handle, chartType, transitionMs, reduceMotion, applyFrame, maybeStartAnim]);
692
716
  const volumeRaf = (0, import_react2.useRef)(null);
693
717
  const volumeHandle = (0, import_react2.useRef)(null);
694
718
  (0, import_react2.useEffect)(() => {
@@ -714,7 +738,7 @@ function VroomChart(props) {
714
738
  volumeCollapseRef.current = { t: target, easing };
715
739
  handle.setVolumeCollapse(target, easing);
716
740
  const p = handle.render();
717
- if (p) pictureSV.value = p;
741
+ if (p) applyFrame(p);
718
742
  maybeStartAnim();
719
743
  return void 0;
720
744
  }
@@ -728,7 +752,7 @@ function VroomChart(props) {
728
752
  volumeCollapseRef.current = { t, easing: kind };
729
753
  handle.setVolumeCollapse(t, kind);
730
754
  const p = handle.render();
731
- if (p) pictureSV.value = p;
755
+ if (p) applyFrame(p);
732
756
  if (prog < 1) {
733
757
  volumeRaf.current = requestAnimationFrame(step);
734
758
  } else {
@@ -748,7 +772,7 @@ function VroomChart(props) {
748
772
  volume?.enabled,
749
773
  transitionMs,
750
774
  reduceMotion,
751
- pictureSV,
775
+ applyFrame,
752
776
  volumeCollapseRef,
753
777
  maybeStartAnim
754
778
  ]);
@@ -766,7 +790,7 @@ function VroomChart(props) {
766
790
  axisCollapse.current = { y: targetY, x: targetX };
767
791
  handle.setAxisCollapse(targetY, targetX);
768
792
  const p = handle.render();
769
- if (p) pictureSV.value = p;
793
+ if (p) applyFrame(p);
770
794
  maybeStartAnim();
771
795
  return void 0;
772
796
  }
@@ -785,7 +809,7 @@ function VroomChart(props) {
785
809
  axisCollapse.current = { y: targetY, x: targetX };
786
810
  handle.setAxisCollapse(targetY, targetX);
787
811
  const p = handle.render();
788
- if (p) pictureSV.value = p;
812
+ if (p) applyFrame(p);
789
813
  maybeStartAnim();
790
814
  return void 0;
791
815
  }
@@ -799,7 +823,7 @@ function VroomChart(props) {
799
823
  axisCollapse.current = { y, x };
800
824
  handle.setAxisCollapse(y, x);
801
825
  const p = handle.render();
802
- if (p) pictureSV.value = p;
826
+ if (p) applyFrame(p);
803
827
  if (prog < 1) {
804
828
  axisRaf.current = requestAnimationFrame(step);
805
829
  } else {
@@ -820,7 +844,7 @@ function VroomChart(props) {
820
844
  showXAxis,
821
845
  transitionMs,
822
846
  reduceMotion,
823
- pictureSV,
847
+ applyFrame,
824
848
  maybeStartAnim
825
849
  ]);
826
850
  const hitAxis = (0, import_react2.useCallback)(
@@ -860,7 +884,7 @@ function VroomChart(props) {
860
884
  priceDrag.current = { index: pl.index, id: pl.line.id, price: pl.line.price };
861
885
  handle.setPriceLineDrag(pl.index, pl.line.price);
862
886
  const p = handle.render();
863
- if (p) pictureSV.value = p;
887
+ if (p) applyFrame(p);
864
888
  }
865
889
  }
866
890
  }).onChange((e) => {
@@ -883,7 +907,7 @@ function VroomChart(props) {
883
907
  next = handle.render();
884
908
  } else if (crosshairActive.current) {
885
909
  const ch = handle.setCrosshair(e.x, e.y - crosshairOffset);
886
- if (ch) pictureSV.value = ch;
910
+ if (ch) applyFrame(ch);
887
911
  const info = handle.getCrosshairInfo();
888
912
  const t = info?.timeMs ?? null;
889
913
  if (t !== lastCrosshairTime.current) {
@@ -894,7 +918,7 @@ function VroomChart(props) {
894
918
  } else {
895
919
  next = handle.translate(e.changeX, e.changeY);
896
920
  }
897
- if (next) pictureSV.value = next;
921
+ if (next) applyFrame(next);
898
922
  maybeStartAnim();
899
923
  }).onEnd((e) => {
900
924
  if (!handle) return;
@@ -903,7 +927,7 @@ function VroomChart(props) {
903
927
  priceDrag.current = null;
904
928
  handle.setPriceLineDrag(-1, 0);
905
929
  const p = handle.render();
906
- if (p) pictureSV.value = p;
930
+ if (p) applyFrame(p);
907
931
  if (g) onPriceLineDragEnd?.(g.id, g.price);
908
932
  return;
909
933
  }
@@ -923,7 +947,7 @@ function VroomChart(props) {
923
947
  velocity *= Math.pow(0.5, dt / HALF_LIFE_S);
924
948
  const dx = velocity * dt;
925
949
  const next = handle.pan(dx, 0);
926
- if (next) pictureSV.value = next;
950
+ if (next) applyFrame(next);
927
951
  maybeStartAnim();
928
952
  if (Math.abs(velocity) > MIN_STOP) {
929
953
  decayRaf.current = requestAnimationFrame(tick);
@@ -977,7 +1001,7 @@ function VroomChart(props) {
977
1001
  }
978
1002
  if (frameX === 1 && frameY === 1) return;
979
1003
  const next = handle.zoom(frameX, frameY, focalX, focalY);
980
- if (next) pictureSV.value = next;
1004
+ if (next) applyFrame(next);
981
1005
  maybeStartAnim();
982
1006
  });
983
1007
  const longPress = import_react_native_gesture_handler.Gesture.LongPress().runOnJS(true).onStart((e) => {
@@ -987,7 +1011,7 @@ function VroomChart(props) {
987
1011
  cancelDecay();
988
1012
  crosshairActive.current = true;
989
1013
  const ch = handle.setCrosshair(e.x, e.y - crosshairOffset);
990
- if (ch) pictureSV.value = ch;
1014
+ if (ch) applyFrame(ch);
991
1015
  const info = handle.getCrosshairInfo();
992
1016
  lastCrosshairTime.current = info?.timeMs ?? null;
993
1017
  onCrosshair?.({
@@ -1010,7 +1034,7 @@ function VroomChart(props) {
1010
1034
  if (hitAxis(e.x, e.y) !== "chart") return;
1011
1035
  crosshairActive.current = false;
1012
1036
  const ch = handle.clearCrosshair();
1013
- if (ch) pictureSV.value = ch;
1037
+ if (ch) applyFrame(ch);
1014
1038
  lastCrosshairTime.current = null;
1015
1039
  onCrosshair?.({ active: false, candle: null, timeMs: null, price: null, reason: "hide" });
1016
1040
  });
@@ -1025,11 +1049,17 @@ function VroomChart(props) {
1025
1049
  style
1026
1050
  ]
1027
1051
  },
1028
- /* @__PURE__ */ import_react2.default.createElement(import_react_native_gesture_handler.GestureDetector, { gesture }, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: { flex: 1 } }, /* @__PURE__ */ import_react2.default.createElement(import_react_native_skia.Canvas, { style: { flex: 1 } }, width > 0 && height > 0 ? (
1029
- // pictureSV is always a valid picture (seeded empty, never null),
1030
- // so RN-Skia's UI-thread reader never sees null.
1031
- /* @__PURE__ */ import_react2.default.createElement(import_react_native_skia.Picture, { picture: pictureSV })
1032
- ) : null)))
1052
+ /* @__PURE__ */ import_react2.default.createElement(import_react_native_gesture_handler.GestureDetector, { gesture }, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: { flex: 1 } }, /* @__PURE__ */ import_react2.default.createElement(import_react_native_skia.Canvas, { style: { flex: 1 } }, width > 0 && height > 0 ? /* @__PURE__ */ import_react2.default.createElement(import_react2.default.Fragment, null, /* @__PURE__ */ import_react2.default.createElement(import_react_native_skia.Picture, { picture: pictureSV }), /* @__PURE__ */ import_react2.default.createElement(
1053
+ import_react_native_skia.Image,
1054
+ {
1055
+ image: imageSV,
1056
+ x: 0,
1057
+ y: 0,
1058
+ width,
1059
+ height,
1060
+ fit: "fill"
1061
+ }
1062
+ )) : null)))
1033
1063
  );
1034
1064
  }
1035
1065
  // Annotate the CommonJS export names for ESM import in node: