react-native-vroom-chart 0.16.0 → 0.17.0
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/cpp/VroomChartHostObject.cpp +81 -0
- package/cpp/_core_include/vroom/vroom_chart.h +41 -0
- package/cpp/_core_src/candles.cpp +15 -14
- package/cpp/_core_src/chart.cpp +297 -28
- package/cpp/_core_src/chart.h +71 -2
- package/cpp/_core_src/chart_facade.cpp +27 -0
- package/cpp/_core_src/color_lerp.h +28 -0
- package/cpp/_core_src/loading_line.cpp +183 -0
- package/cpp/_core_src/loading_line.h +38 -0
- package/cpp/_core_src/loading_wave.h +140 -0
- package/cpp/_core_src/ma_overlay.cpp +15 -10
- package/cpp/_core_src/ma_overlay.h +7 -0
- package/cpp/_core_src/price_indicator.cpp +21 -7
- package/cpp/_core_src/price_indicator.h +11 -1
- package/cpp/_core_src/price_indicator_anim.h +81 -0
- package/cpp/_core_src/theme.cpp +5 -0
- package/cpp/_core_src/tip_geometry.h +55 -0
- package/cpp/_core_src/viewport.h +33 -0
- package/lib/index.d.mts +30 -0
- package/lib/index.d.ts +30 -0
- package/lib/index.js +71 -11
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +71 -11
- package/lib/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/VroomChart.tsx +12 -0
- package/src/jsi.d.ts +42 -0
- package/src/theme.ts +1 -0
- package/src/useChartCore.ts +119 -4
package/lib/index.mjs
CHANGED
|
@@ -158,8 +158,10 @@ var COLOR_KEYS = {
|
|
|
158
158
|
// VROOM_COLOR_ACCENT_BULL
|
|
159
159
|
accentBear: 15,
|
|
160
160
|
// VROOM_COLOR_ACCENT_BEAR
|
|
161
|
-
lineColor: 16
|
|
161
|
+
lineColor: 16,
|
|
162
162
|
// VROOM_COLOR_LINE
|
|
163
|
+
skeleton: 17
|
|
164
|
+
// VROOM_COLOR_SKELETON
|
|
163
165
|
};
|
|
164
166
|
var FLOAT_KEYS = {
|
|
165
167
|
wickWidth: 1,
|
|
@@ -459,7 +461,7 @@ function ensureInstalled() {
|
|
|
459
461
|
}
|
|
460
462
|
installed = true;
|
|
461
463
|
}
|
|
462
|
-
function useChartCore(candles, size, visibleRange, defaultCandleWidth, chartType, theme, rsi, macd, atr, movingAverages, vwap, bollingerBands, ichimoku, fairValueGaps, volume, priceLines, footprints, transition) {
|
|
464
|
+
function useChartCore(candles, size, visibleRange, defaultCandleWidth, chartType, theme, rsi, macd, atr, movingAverages, vwap, bollingerBands, ichimoku, fairValueGaps, volume, priceLines, footprints, transition, loading) {
|
|
463
465
|
const handleRef = useRef(null);
|
|
464
466
|
const defaultWidthAppliedRef = useRef(false);
|
|
465
467
|
const volumeCollapseRef = useRef(null);
|
|
@@ -494,18 +496,26 @@ function useChartCore(candles, size, visibleRange, defaultCandleWidth, chartType
|
|
|
494
496
|
const onFrameRef = useRef(transition?.onFrame);
|
|
495
497
|
onFrameRef.current = transition?.onFrame;
|
|
496
498
|
const seriesKey = transition?.seriesKey;
|
|
499
|
+
const loadingHandoffRef = useRef(false);
|
|
497
500
|
const endIntervalMorph = useCallback(() => {
|
|
498
501
|
if (intervalMorphRaf.current != null) {
|
|
499
502
|
cancelAnimationFrame(intervalMorphRaf.current);
|
|
500
503
|
intervalMorphRaf.current = null;
|
|
501
504
|
}
|
|
502
|
-
handleRef.current
|
|
505
|
+
const h = handleRef.current;
|
|
506
|
+
if (loadingHandoffRef.current) {
|
|
507
|
+
loadingHandoffRef.current = false;
|
|
508
|
+
h?.setLoadingMorph(1);
|
|
509
|
+
h?.beginLoadingReveal();
|
|
510
|
+
}
|
|
511
|
+
h?.setIntervalMorph(1);
|
|
503
512
|
}, []);
|
|
504
|
-
const startIntervalMorph = useCallback((h) => {
|
|
513
|
+
const startIntervalMorph = useCallback((h, durationMs) => {
|
|
505
514
|
const { ms, easing } = animRef.current;
|
|
515
|
+
const dur = durationMs ?? ms;
|
|
506
516
|
const start = performance.now();
|
|
507
517
|
const step = (now) => {
|
|
508
|
-
const p = Math.min(1, (now - start) /
|
|
518
|
+
const p = Math.min(1, (now - start) / dur);
|
|
509
519
|
h.setIntervalMorph(p < 1 ? ease(easing, p) : 1);
|
|
510
520
|
const pic = h.render();
|
|
511
521
|
if (pic) onFrameRef.current?.(pic);
|
|
@@ -513,6 +523,31 @@ function useChartCore(candles, size, visibleRange, defaultCandleWidth, chartType
|
|
|
513
523
|
};
|
|
514
524
|
intervalMorphRaf.current = requestAnimationFrame(step);
|
|
515
525
|
}, []);
|
|
526
|
+
const startLoadingHandoff = useCallback(
|
|
527
|
+
(h) => {
|
|
528
|
+
const { ms, easing } = animRef.current;
|
|
529
|
+
const half = ms / 2;
|
|
530
|
+
loadingHandoffRef.current = true;
|
|
531
|
+
h.beginLoadingMorph();
|
|
532
|
+
const start = performance.now();
|
|
533
|
+
const step = (now) => {
|
|
534
|
+
const p = Math.min(1, (now - start) / half);
|
|
535
|
+
h.setLoadingMorph(p < 1 ? ease(easing, p) : 1);
|
|
536
|
+
const pic = h.render();
|
|
537
|
+
if (pic) onFrameRef.current?.(pic);
|
|
538
|
+
if (p < 1) {
|
|
539
|
+
intervalMorphRaf.current = requestAnimationFrame(step);
|
|
540
|
+
return;
|
|
541
|
+
}
|
|
542
|
+
intervalMorphRaf.current = null;
|
|
543
|
+
loadingHandoffRef.current = false;
|
|
544
|
+
h.beginLoadingReveal();
|
|
545
|
+
startIntervalMorph(h, half);
|
|
546
|
+
};
|
|
547
|
+
intervalMorphRaf.current = requestAnimationFrame(step);
|
|
548
|
+
},
|
|
549
|
+
[startIntervalMorph]
|
|
550
|
+
);
|
|
516
551
|
const settleStream = useCallback((keepMorph = false) => {
|
|
517
552
|
if (streamRaf.current != null) {
|
|
518
553
|
cancelAnimationFrame(streamRaf.current);
|
|
@@ -582,6 +617,8 @@ function useChartCore(candles, size, visibleRange, defaultCandleWidth, chartType
|
|
|
582
617
|
const explicit = visibleRange != null;
|
|
583
618
|
const startMs = visibleRange?.startMs ?? 0;
|
|
584
619
|
const endMs = visibleRange?.endMs ?? 0;
|
|
620
|
+
const showLoadingLine = loading === true && candles.length === 0;
|
|
621
|
+
const lineUpRef = useRef(false);
|
|
585
622
|
const themeKey = theme ? JSON.stringify(theme) : "";
|
|
586
623
|
const rsiKey = rsi ? JSON.stringify(rsi) : "";
|
|
587
624
|
const macdKey = macd ? JSON.stringify(macd) : "";
|
|
@@ -604,6 +641,19 @@ function useChartCore(candles, size, visibleRange, defaultCandleWidth, chartType
|
|
|
604
641
|
defaultWidthAppliedRef.current = true;
|
|
605
642
|
}
|
|
606
643
|
let morphing = false;
|
|
644
|
+
if (showLoadingLine) {
|
|
645
|
+
if (!lineUpRef.current) {
|
|
646
|
+
endIntervalMorph();
|
|
647
|
+
settleStream();
|
|
648
|
+
h.setCandles(packCandles([]));
|
|
649
|
+
prevDataRef.current = null;
|
|
650
|
+
}
|
|
651
|
+
h.setLoading(true, !animRef.current.reduceMotion);
|
|
652
|
+
lineUpRef.current = true;
|
|
653
|
+
} else if (lineUpRef.current && candles.length === 0) {
|
|
654
|
+
h.setLoading(false, true);
|
|
655
|
+
lineUpRef.current = false;
|
|
656
|
+
}
|
|
607
657
|
if (candles.length > 0) {
|
|
608
658
|
const prev = prevDataRef.current;
|
|
609
659
|
const freshHandle = prev == null || prev.handle !== h;
|
|
@@ -611,6 +661,7 @@ function useChartCore(candles, size, visibleRange, defaultCandleWidth, chartType
|
|
|
611
661
|
const transitionKind = freshHandle ? "initial" : explicit ? "stream" : classifyTransition(prev.candles, candles, seriesKey !== prev.seriesKey);
|
|
612
662
|
let tfArgs = null;
|
|
613
663
|
let prevEnvelope = null;
|
|
664
|
+
let handOff = false;
|
|
614
665
|
let stream = null;
|
|
615
666
|
if (transitionKind === "stream" && prev != null && !explicit) {
|
|
616
667
|
const { stream: mode, streamMs, reduceMotion } = animRef.current;
|
|
@@ -660,6 +711,11 @@ function useChartCore(candles, size, visibleRange, defaultCandleWidth, chartType
|
|
|
660
711
|
} else if (transitionKind === "initial" || transitionKind === "reset") {
|
|
661
712
|
endIntervalMorph();
|
|
662
713
|
}
|
|
714
|
+
if (lineUpRef.current) {
|
|
715
|
+
lineUpRef.current = false;
|
|
716
|
+
handOff = animRef.current.ms > 0 && !animRef.current.reduceMotion && onFrameRef.current != null;
|
|
717
|
+
if (!handOff) h.setLoading(false, true);
|
|
718
|
+
}
|
|
663
719
|
h.setCandles(packCandles(candles));
|
|
664
720
|
if (transitionKind === "timeframe") {
|
|
665
721
|
const newStepMs = inferStepMs(candles);
|
|
@@ -681,6 +737,7 @@ function useChartCore(candles, size, visibleRange, defaultCandleWidth, chartType
|
|
|
681
737
|
} else if (transitionKind === "reset") {
|
|
682
738
|
h.resetView();
|
|
683
739
|
}
|
|
740
|
+
if (handOff) startLoadingHandoff(h);
|
|
684
741
|
prevDataRef.current = { handle: h, candles, seriesKey };
|
|
685
742
|
}
|
|
686
743
|
}
|
|
@@ -710,7 +767,7 @@ function useChartCore(candles, size, visibleRange, defaultCandleWidth, chartType
|
|
|
710
767
|
footprints?.prints.length ? footprintsToSpec(footprints) : EMPTY_FOOTPRINTS
|
|
711
768
|
);
|
|
712
769
|
if (!morphing) setPicture(h.render());
|
|
713
|
-
}, [candles, seriesKey, size.width, size.height, size.pxRatio, explicit, startMs, endMs, defaultCandleWidth, themeKey, rsiKey, macdKey, atrKey, maKey, vwapKey, bollingerKey, ichimokuKey, fvgKey, volumeKey, priceLinesKey, footprintsKey, startIntervalMorph, endIntervalMorph, startStreamAnim, settleStream]);
|
|
770
|
+
}, [candles, showLoadingLine, seriesKey, size.width, size.height, size.pxRatio, explicit, startMs, endMs, defaultCandleWidth, themeKey, rsiKey, macdKey, atrKey, maKey, vwapKey, bollingerKey, ichimokuKey, fvgKey, volumeKey, priceLinesKey, footprintsKey, startIntervalMorph, startLoadingHandoff, endIntervalMorph, startStreamAnim, settleStream]);
|
|
714
771
|
return { handle: handleRef.current, picture, volumeCollapseRef };
|
|
715
772
|
}
|
|
716
773
|
|
|
@@ -722,6 +779,7 @@ function isSkImage(frame) {
|
|
|
722
779
|
function VroomChart(props) {
|
|
723
780
|
const {
|
|
724
781
|
candles,
|
|
782
|
+
loading,
|
|
725
783
|
seriesKey,
|
|
726
784
|
width: widthProp,
|
|
727
785
|
height: heightProp,
|
|
@@ -839,8 +897,10 @@ function VroomChart(props) {
|
|
|
839
897
|
streamTransitionMs,
|
|
840
898
|
reduceMotion,
|
|
841
899
|
onFrame
|
|
842
|
-
}
|
|
900
|
+
},
|
|
901
|
+
loading
|
|
843
902
|
);
|
|
903
|
+
const showLoadingLine = loading === true && candles.length === 0;
|
|
844
904
|
const crosshairActive = useRef2(false);
|
|
845
905
|
const footprintActive = useRef2(false);
|
|
846
906
|
const lastCrosshairTime = useRef2(null);
|
|
@@ -1120,7 +1180,7 @@ function VroomChart(props) {
|
|
|
1120
1180
|
pane: null
|
|
1121
1181
|
});
|
|
1122
1182
|
};
|
|
1123
|
-
const pan = Gesture.Pan().runOnJS(true).maxPointers(1).onStart((e) => {
|
|
1183
|
+
const pan = Gesture.Pan().enabled(!showLoadingLine).runOnJS(true).maxPointers(1).onStart((e) => {
|
|
1124
1184
|
cancelDecay();
|
|
1125
1185
|
panMode.current = hitAxis(e.x, e.y);
|
|
1126
1186
|
priceDrag.current = null;
|
|
@@ -1215,7 +1275,7 @@ function VroomChart(props) {
|
|
|
1215
1275
|
enableX: false,
|
|
1216
1276
|
enableY: false
|
|
1217
1277
|
});
|
|
1218
|
-
const pinch = Gesture.Pinch().runOnJS(true).onTouchesDown((e) => {
|
|
1278
|
+
const pinch = Gesture.Pinch().enabled(!showLoadingLine).runOnJS(true).onTouchesDown((e) => {
|
|
1219
1279
|
if (e.numberOfTouches < 2) return;
|
|
1220
1280
|
dismissFootprint();
|
|
1221
1281
|
const [a, b] = e.allTouches;
|
|
@@ -1253,7 +1313,7 @@ function VroomChart(props) {
|
|
|
1253
1313
|
if (next) applyFrame(next);
|
|
1254
1314
|
maybeStartAnim();
|
|
1255
1315
|
});
|
|
1256
|
-
const longPress = Gesture.LongPress().runOnJS(true).onStart((e) => {
|
|
1316
|
+
const longPress = Gesture.LongPress().enabled(!showLoadingLine).runOnJS(true).onStart((e) => {
|
|
1257
1317
|
if (!handle) return;
|
|
1258
1318
|
if (hitAxis(e.x, e.y) !== "chart") return;
|
|
1259
1319
|
if (hitPriceLine(e.x, e.y)) return;
|
|
@@ -1273,7 +1333,7 @@ function VroomChart(props) {
|
|
|
1273
1333
|
reason: "show"
|
|
1274
1334
|
});
|
|
1275
1335
|
});
|
|
1276
|
-
const tap = Gesture.Tap().runOnJS(true).onStart((e) => {
|
|
1336
|
+
const tap = Gesture.Tap().enabled(!showLoadingLine).runOnJS(true).onStart((e) => {
|
|
1277
1337
|
if (!handle) return;
|
|
1278
1338
|
const prints = footprints ?? [];
|
|
1279
1339
|
const fp = prints.length ? handle.hitTestFootprint(e.x, e.y) : null;
|