react-native-vroom-chart 0.13.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.mjs CHANGED
@@ -1,7 +1,14 @@
1
1
  // src/VroomChart.tsx
2
2
  import React, { useEffect as useEffect2, useRef as useRef2, useCallback as useCallback2, useState as useState2, useMemo } from "react";
3
- import { View } from "react-native";
4
- import { Canvas, Picture, Skia } from "@shopify/react-native-skia";
3
+ import { PixelRatio, View } from "react-native";
4
+ import {
5
+ AlphaType,
6
+ Canvas,
7
+ ColorType,
8
+ Image,
9
+ Picture,
10
+ Skia
11
+ } from "@shopify/react-native-skia";
5
12
  import {
6
13
  Gesture,
7
14
  GestureDetector,
@@ -479,6 +486,9 @@ function useChartCore(candles, size, visibleRange, defaultCandleWidth, chartType
479
486
  }
480
487
 
481
488
  // src/VroomChart.tsx
489
+ function isSkImage(frame) {
490
+ return typeof frame.getImageInfo === "function";
491
+ }
482
492
  function VroomChart(props) {
483
493
  const {
484
494
  candles,
@@ -530,17 +540,38 @@ function VroomChart(props) {
530
540
  rec.beginRecording(Skia.XYWHRect(0, 0, 1, 1));
531
541
  return rec.finishRecordingAsPicture();
532
542
  }, []);
543
+ const emptyImage = useMemo(() => {
544
+ const data = Skia.Data.fromBytes(new Uint8Array(4));
545
+ return Skia.Image.MakeImage(
546
+ {
547
+ width: 1,
548
+ height: 1,
549
+ colorType: ColorType.RGBA_8888,
550
+ alphaType: AlphaType.Premul
551
+ },
552
+ data,
553
+ 4
554
+ );
555
+ }, []);
533
556
  const pictureSV = useSharedValue(emptyPicture);
557
+ const imageSV = useSharedValue(emptyImage);
558
+ const applyFrame = useCallback2(
559
+ (frame) => {
560
+ if (isSkImage(frame)) imageSV.value = frame;
561
+ else pictureSV.value = frame;
562
+ },
563
+ [imageSV, pictureSV]
564
+ );
534
565
  const reduceMotion = useReducedMotion();
535
566
  const onFrame = useCallback2(
536
567
  (p) => {
537
- pictureSV.value = p;
568
+ applyFrame(p);
538
569
  },
539
- [pictureSV]
570
+ [applyFrame]
540
571
  );
541
572
  const { handle, picture, volumeCollapseRef } = useChartCore(
542
573
  candles,
543
- { width, height },
574
+ { width, height, pxRatio: PixelRatio.get() },
544
575
  visibleRange,
545
576
  defaultCandleWidth,
546
577
  chartType,
@@ -569,11 +600,11 @@ function VroomChart(props) {
569
600
  animRaf.current = null;
570
601
  if (!handle) return;
571
602
  const next = handle.render();
572
- if (next) pictureSV.value = next;
603
+ if (next) applyFrame(next);
573
604
  if (handle.isAnimating()) {
574
605
  animRaf.current = requestAnimationFrame(animTick);
575
606
  }
576
- }, [handle, pictureSV]);
607
+ }, [handle, applyFrame]);
577
608
  const maybeStartAnim = useCallback2(() => {
578
609
  if (animRaf.current != null) return;
579
610
  if (!handle?.isAnimating()) return;
@@ -588,9 +619,9 @@ function VroomChart(props) {
588
619
  };
589
620
  }, []);
590
621
  useEffect2(() => {
591
- if (picture) pictureSV.value = picture;
622
+ if (picture) applyFrame(picture);
592
623
  maybeStartAnim();
593
- }, [picture, pictureSV, maybeStartAnim]);
624
+ }, [picture, applyFrame, maybeStartAnim]);
594
625
  const morphRaf = useRef2(null);
595
626
  const morphFade = useRef2(null);
596
627
  const morphHandle = useRef2(null);
@@ -604,7 +635,7 @@ function VroomChart(props) {
604
635
  morphFade.current = target;
605
636
  handle.setChartType(target);
606
637
  const p = handle.render();
607
- if (p) pictureSV.value = p;
638
+ if (p) applyFrame(p);
608
639
  maybeStartAnim();
609
640
  return void 0;
610
641
  }
@@ -621,7 +652,7 @@ function VroomChart(props) {
621
652
  morphFade.current = target;
622
653
  handle.setChartType(target);
623
654
  const p = handle.render();
624
- if (p) pictureSV.value = p;
655
+ if (p) applyFrame(p);
625
656
  maybeStartAnim();
626
657
  return void 0;
627
658
  }
@@ -634,7 +665,7 @@ function VroomChart(props) {
634
665
  morphFade.current = fade;
635
666
  handle.setMorph(reduceMotion ? 0 : fade, fade);
636
667
  const p = handle.render();
637
- if (p) pictureSV.value = p;
668
+ if (p) applyFrame(p);
638
669
  if (prog < 1) {
639
670
  morphRaf.current = requestAnimationFrame(step);
640
671
  } else {
@@ -642,7 +673,7 @@ function VroomChart(props) {
642
673
  morphFade.current = target;
643
674
  handle.setChartType(target);
644
675
  const q = handle.render();
645
- if (q) pictureSV.value = q;
676
+ if (q) applyFrame(q);
646
677
  maybeStartAnim();
647
678
  }
648
679
  };
@@ -653,7 +684,7 @@ function VroomChart(props) {
653
684
  morphRaf.current = null;
654
685
  }
655
686
  };
656
- }, [handle, chartType, transitionMs, reduceMotion, pictureSV, maybeStartAnim]);
687
+ }, [handle, chartType, transitionMs, reduceMotion, applyFrame, maybeStartAnim]);
657
688
  const volumeRaf = useRef2(null);
658
689
  const volumeHandle = useRef2(null);
659
690
  useEffect2(() => {
@@ -679,7 +710,7 @@ function VroomChart(props) {
679
710
  volumeCollapseRef.current = { t: target, easing };
680
711
  handle.setVolumeCollapse(target, easing);
681
712
  const p = handle.render();
682
- if (p) pictureSV.value = p;
713
+ if (p) applyFrame(p);
683
714
  maybeStartAnim();
684
715
  return void 0;
685
716
  }
@@ -693,7 +724,7 @@ function VroomChart(props) {
693
724
  volumeCollapseRef.current = { t, easing: kind };
694
725
  handle.setVolumeCollapse(t, kind);
695
726
  const p = handle.render();
696
- if (p) pictureSV.value = p;
727
+ if (p) applyFrame(p);
697
728
  if (prog < 1) {
698
729
  volumeRaf.current = requestAnimationFrame(step);
699
730
  } else {
@@ -713,7 +744,7 @@ function VroomChart(props) {
713
744
  volume?.enabled,
714
745
  transitionMs,
715
746
  reduceMotion,
716
- pictureSV,
747
+ applyFrame,
717
748
  volumeCollapseRef,
718
749
  maybeStartAnim
719
750
  ]);
@@ -731,7 +762,7 @@ function VroomChart(props) {
731
762
  axisCollapse.current = { y: targetY, x: targetX };
732
763
  handle.setAxisCollapse(targetY, targetX);
733
764
  const p = handle.render();
734
- if (p) pictureSV.value = p;
765
+ if (p) applyFrame(p);
735
766
  maybeStartAnim();
736
767
  return void 0;
737
768
  }
@@ -750,7 +781,7 @@ function VroomChart(props) {
750
781
  axisCollapse.current = { y: targetY, x: targetX };
751
782
  handle.setAxisCollapse(targetY, targetX);
752
783
  const p = handle.render();
753
- if (p) pictureSV.value = p;
784
+ if (p) applyFrame(p);
754
785
  maybeStartAnim();
755
786
  return void 0;
756
787
  }
@@ -764,7 +795,7 @@ function VroomChart(props) {
764
795
  axisCollapse.current = { y, x };
765
796
  handle.setAxisCollapse(y, x);
766
797
  const p = handle.render();
767
- if (p) pictureSV.value = p;
798
+ if (p) applyFrame(p);
768
799
  if (prog < 1) {
769
800
  axisRaf.current = requestAnimationFrame(step);
770
801
  } else {
@@ -785,7 +816,7 @@ function VroomChart(props) {
785
816
  showXAxis,
786
817
  transitionMs,
787
818
  reduceMotion,
788
- pictureSV,
819
+ applyFrame,
789
820
  maybeStartAnim
790
821
  ]);
791
822
  const hitAxis = useCallback2(
@@ -825,7 +856,7 @@ function VroomChart(props) {
825
856
  priceDrag.current = { index: pl.index, id: pl.line.id, price: pl.line.price };
826
857
  handle.setPriceLineDrag(pl.index, pl.line.price);
827
858
  const p = handle.render();
828
- if (p) pictureSV.value = p;
859
+ if (p) applyFrame(p);
829
860
  }
830
861
  }
831
862
  }).onChange((e) => {
@@ -848,7 +879,7 @@ function VroomChart(props) {
848
879
  next = handle.render();
849
880
  } else if (crosshairActive.current) {
850
881
  const ch = handle.setCrosshair(e.x, e.y - crosshairOffset);
851
- if (ch) pictureSV.value = ch;
882
+ if (ch) applyFrame(ch);
852
883
  const info = handle.getCrosshairInfo();
853
884
  const t = info?.timeMs ?? null;
854
885
  if (t !== lastCrosshairTime.current) {
@@ -859,7 +890,7 @@ function VroomChart(props) {
859
890
  } else {
860
891
  next = handle.translate(e.changeX, e.changeY);
861
892
  }
862
- if (next) pictureSV.value = next;
893
+ if (next) applyFrame(next);
863
894
  maybeStartAnim();
864
895
  }).onEnd((e) => {
865
896
  if (!handle) return;
@@ -868,7 +899,7 @@ function VroomChart(props) {
868
899
  priceDrag.current = null;
869
900
  handle.setPriceLineDrag(-1, 0);
870
901
  const p = handle.render();
871
- if (p) pictureSV.value = p;
902
+ if (p) applyFrame(p);
872
903
  if (g) onPriceLineDragEnd?.(g.id, g.price);
873
904
  return;
874
905
  }
@@ -888,7 +919,7 @@ function VroomChart(props) {
888
919
  velocity *= Math.pow(0.5, dt / HALF_LIFE_S);
889
920
  const dx = velocity * dt;
890
921
  const next = handle.pan(dx, 0);
891
- if (next) pictureSV.value = next;
922
+ if (next) applyFrame(next);
892
923
  maybeStartAnim();
893
924
  if (Math.abs(velocity) > MIN_STOP) {
894
925
  decayRaf.current = requestAnimationFrame(tick);
@@ -942,7 +973,7 @@ function VroomChart(props) {
942
973
  }
943
974
  if (frameX === 1 && frameY === 1) return;
944
975
  const next = handle.zoom(frameX, frameY, focalX, focalY);
945
- if (next) pictureSV.value = next;
976
+ if (next) applyFrame(next);
946
977
  maybeStartAnim();
947
978
  });
948
979
  const longPress = Gesture.LongPress().runOnJS(true).onStart((e) => {
@@ -952,7 +983,7 @@ function VroomChart(props) {
952
983
  cancelDecay();
953
984
  crosshairActive.current = true;
954
985
  const ch = handle.setCrosshair(e.x, e.y - crosshairOffset);
955
- if (ch) pictureSV.value = ch;
986
+ if (ch) applyFrame(ch);
956
987
  const info = handle.getCrosshairInfo();
957
988
  lastCrosshairTime.current = info?.timeMs ?? null;
958
989
  onCrosshair?.({
@@ -975,7 +1006,7 @@ function VroomChart(props) {
975
1006
  if (hitAxis(e.x, e.y) !== "chart") return;
976
1007
  crosshairActive.current = false;
977
1008
  const ch = handle.clearCrosshair();
978
- if (ch) pictureSV.value = ch;
1009
+ if (ch) applyFrame(ch);
979
1010
  lastCrosshairTime.current = null;
980
1011
  onCrosshair?.({ active: false, candle: null, timeMs: null, price: null, reason: "hide" });
981
1012
  });
@@ -990,11 +1021,17 @@ function VroomChart(props) {
990
1021
  style
991
1022
  ]
992
1023
  },
993
- /* @__PURE__ */ React.createElement(GestureDetector, { gesture }, /* @__PURE__ */ React.createElement(View, { style: { flex: 1 } }, /* @__PURE__ */ React.createElement(Canvas, { style: { flex: 1 } }, width > 0 && height > 0 ? (
994
- // pictureSV is always a valid picture (seeded empty, never null),
995
- // so RN-Skia's UI-thread reader never sees null.
996
- /* @__PURE__ */ React.createElement(Picture, { picture: pictureSV })
997
- ) : null)))
1024
+ /* @__PURE__ */ React.createElement(GestureDetector, { gesture }, /* @__PURE__ */ React.createElement(View, { style: { flex: 1 } }, /* @__PURE__ */ React.createElement(Canvas, { style: { flex: 1 } }, width > 0 && height > 0 ? /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Picture, { picture: pictureSV }), /* @__PURE__ */ React.createElement(
1025
+ Image,
1026
+ {
1027
+ image: imageSV,
1028
+ x: 0,
1029
+ y: 0,
1030
+ width,
1031
+ height,
1032
+ fit: "fill"
1033
+ }
1034
+ )) : null)))
998
1035
  );
999
1036
  }
1000
1037
  export {