react-native-vroom-chart 0.1.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.
Files changed (66) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +27 -0
  3. package/android/README.md +7 -0
  4. package/cpp/README.md +11 -0
  5. package/cpp/VroomChartHostObject.cpp +458 -0
  6. package/cpp/VroomChartHostObject.h +36 -0
  7. package/cpp/VroomJsiInstaller.cpp +69 -0
  8. package/cpp/VroomJsiInstaller.h +10 -0
  9. package/cpp/VroomSkiaContext.cpp +25 -0
  10. package/cpp/VroomSkiaContext.h +30 -0
  11. package/cpp/_core_include/vroom/vroom_chart.h +195 -0
  12. package/cpp/_core_src/candles.cpp +74 -0
  13. package/cpp/_core_src/candles.h +34 -0
  14. package/cpp/_core_src/chart.cpp +317 -0
  15. package/cpp/_core_src/chart.h +167 -0
  16. package/cpp/_core_src/chart_facade.cpp +570 -0
  17. package/cpp/_core_src/chart_internal.h +30 -0
  18. package/cpp/_core_src/crosshair.cpp +65 -0
  19. package/cpp/_core_src/crosshair.h +32 -0
  20. package/cpp/_core_src/fonts.cpp +22 -0
  21. package/cpp/_core_src/fonts.h +25 -0
  22. package/cpp/_core_src/labels.cpp +340 -0
  23. package/cpp/_core_src/labels.h +85 -0
  24. package/cpp/_core_src/ma.cpp +53 -0
  25. package/cpp/_core_src/ma.h +39 -0
  26. package/cpp/_core_src/ma_overlay.cpp +73 -0
  27. package/cpp/_core_src/ma_overlay.h +42 -0
  28. package/cpp/_core_src/macd.cpp +68 -0
  29. package/cpp/_core_src/macd.h +29 -0
  30. package/cpp/_core_src/macd_pane.cpp +199 -0
  31. package/cpp/_core_src/macd_pane.h +41 -0
  32. package/cpp/_core_src/price_indicator.cpp +106 -0
  33. package/cpp/_core_src/price_indicator.h +29 -0
  34. package/cpp/_core_src/rsi.cpp +70 -0
  35. package/cpp/_core_src/rsi.h +32 -0
  36. package/cpp/_core_src/rsi_pane.cpp +167 -0
  37. package/cpp/_core_src/rsi_pane.h +39 -0
  38. package/cpp/_core_src/theme.cpp +41 -0
  39. package/cpp/_core_src/theme.h +23 -0
  40. package/cpp/_core_src/ticks.cpp +49 -0
  41. package/cpp/_core_src/ticks.h +30 -0
  42. package/cpp/_core_src/viewport.cpp +141 -0
  43. package/cpp/_core_src/viewport.h +100 -0
  44. package/cpp/_core_src/volume.cpp +70 -0
  45. package/cpp/_core_src/volume.h +34 -0
  46. package/cpp/_core_src/vwap.cpp +51 -0
  47. package/cpp/_core_src/vwap.h +27 -0
  48. package/ios/README.md +7 -0
  49. package/ios/VroomChartModule.h +11 -0
  50. package/ios/VroomChartModule.mm +44 -0
  51. package/lib/index.d.mts +185 -0
  52. package/lib/index.d.ts +185 -0
  53. package/lib/index.js +429 -0
  54. package/lib/index.js.map +1 -0
  55. package/lib/index.mjs +396 -0
  56. package/lib/index.mjs.map +1 -0
  57. package/package.json +75 -0
  58. package/react-native-vroom-chart.podspec +79 -0
  59. package/src/NativeVroomChart.ts +12 -0
  60. package/src/VroomChart.tsx +382 -0
  61. package/src/index.ts +14 -0
  62. package/src/jsi.d.ts +128 -0
  63. package/src/packCandles.ts +24 -0
  64. package/src/theme.ts +43 -0
  65. package/src/types.ts +27 -0
  66. package/src/useChartCore.ts +135 -0
@@ -0,0 +1,135 @@
1
+ import { useEffect, useRef, useState } from 'react';
2
+ import type { SkPicture } from '@shopify/react-native-skia';
3
+
4
+ import NativeVroomChart from './NativeVroomChart';
5
+ import type { ChartHandle } from './jsi.d';
6
+ import { packCandles } from './packCandles';
7
+ import { applyTheme, parseColor } from './theme';
8
+ import type {
9
+ Candle,
10
+ MACDConfig,
11
+ MovingAverageOverlay,
12
+ RSIConfig,
13
+ VisibleRange,
14
+ VroomTheme,
15
+ VWAPConfig,
16
+ } from './types';
17
+
18
+ // Mirrors vroom::ma::Source order in packages/core/src/ma.h.
19
+ const MA_SOURCES = [
20
+ 'close',
21
+ 'open',
22
+ 'high',
23
+ 'low',
24
+ 'hl2',
25
+ 'hlc3',
26
+ 'ohlc4',
27
+ ] as const;
28
+
29
+ function overlayToNumeric(o: MovingAverageOverlay) {
30
+ const srcIdx = o.source ? MA_SOURCES.indexOf(o.source) : 0;
31
+ return {
32
+ kind: o.kind === 'ema' ? 1 : 0,
33
+ period: o.length,
34
+ source: srcIdx < 0 ? 0 : srcIdx,
35
+ color: (o.color != null ? parseColor(o.color) : null) ?? 0xff2962ff,
36
+ width: o.width ?? 1.5,
37
+ };
38
+ }
39
+
40
+ let installed = false;
41
+ function ensureInstalled(): void {
42
+ if (installed) return;
43
+ const ok = NativeVroomChart.install();
44
+ if (!ok) throw new Error('VroomChartModule.install() returned false');
45
+ if (typeof globalThis.VroomChartJSI === 'undefined') {
46
+ throw new Error('global.VroomChartJSI undefined after install()');
47
+ }
48
+ installed = true;
49
+ }
50
+
51
+ export type ChartCoreState = {
52
+ handle: ChartHandle | null;
53
+ /** Picture freshly rendered after the latest data/size/range push. */
54
+ picture: SkPicture | null;
55
+ };
56
+
57
+ // Owns a ChartHandle and produces an "initial" picture whenever data, size,
58
+ // or the externally-controlled visible range changes. Gesture-driven updates
59
+ // happen outside this hook by calling handle.pan(...) directly and assigning
60
+ // the result into a SharedValue.
61
+ export function useChartCore(
62
+ candles: Candle[],
63
+ size: { width: number; height: number; pxRatio?: number },
64
+ visibleRange?: VisibleRange,
65
+ theme?: VroomTheme,
66
+ rsi?: RSIConfig,
67
+ macd?: MACDConfig,
68
+ movingAverages?: MovingAverageOverlay[],
69
+ vwap?: VWAPConfig,
70
+ ): ChartCoreState {
71
+ const handleRef = useRef<ChartHandle | null>(null);
72
+ const [picture, setPicture] = useState<SkPicture | null>(null);
73
+
74
+ if (!handleRef.current && size.width > 0 && size.height > 0) {
75
+ ensureInstalled();
76
+ handleRef.current = globalThis.VroomChartJSI!.create();
77
+ }
78
+
79
+ // When no visibleRange is provided, leave the range entirely to the C++
80
+ // side (which defaults to a sensible recent window on first setCandles).
81
+ // Only push setVisibleRange when the caller is actively controlling it,
82
+ // so it doesn't clobber the default or fight gesture-driven pans.
83
+ const explicit = visibleRange != null;
84
+ const startMs = visibleRange?.startMs ?? 0;
85
+ const endMs = visibleRange?.endMs ?? 0;
86
+
87
+ // Stable deps so inline `theme={{...}}` / `rsi={{...}}` literals don't re-run
88
+ // the effect every render — only when the actual values change.
89
+ const themeKey = theme ? JSON.stringify(theme) : '';
90
+ const rsiKey = rsi ? JSON.stringify(rsi) : '';
91
+ const macdKey = macd ? JSON.stringify(macd) : '';
92
+ const maKey = movingAverages ? JSON.stringify(movingAverages) : '';
93
+ const vwapKey = vwap ? JSON.stringify(vwap) : '';
94
+
95
+ useEffect(() => {
96
+ const h = handleRef.current;
97
+ if (!h) return;
98
+ h.setSize(size.width, size.height, size.pxRatio ?? 1);
99
+ if (candles.length > 0) {
100
+ h.setCandles(packCandles(candles));
101
+ }
102
+ if (explicit) {
103
+ h.setVisibleRange(startMs, endMs);
104
+ }
105
+ if (theme) {
106
+ applyTheme(h, theme);
107
+ }
108
+ h.setRSI(
109
+ rsi?.enabled ?? false,
110
+ rsi?.period ?? 14,
111
+ rsi?.upperBand ?? 70,
112
+ rsi?.lowerBand ?? 30,
113
+ rsi?.maEnabled ?? true,
114
+ rsi?.maPeriod ?? 14,
115
+ );
116
+ h.setMACD(
117
+ macd?.enabled ?? false,
118
+ macd?.fast ?? 12,
119
+ macd?.slow ?? 26,
120
+ macd?.signal ?? 9,
121
+ );
122
+ h.setOverlays((movingAverages ?? []).map(overlayToNumeric));
123
+ h.setVWAP(
124
+ vwap?.enabled ?? false,
125
+ vwap?.resetMinutes ?? 0,
126
+ (vwap?.color != null ? parseColor(vwap.color) : null) ?? 0xff00bcd4,
127
+ vwap?.width ?? 1.5,
128
+ );
129
+ setPicture(h.render());
130
+ // theme/rsi/macd/movingAverages/vwap are represented by their *Key deps.
131
+ // eslint-disable-next-line react-hooks/exhaustive-deps
132
+ }, [candles, size.width, size.height, size.pxRatio, explicit, startMs, endMs, themeKey, rsiKey, macdKey, maKey, vwapKey]);
133
+
134
+ return { handle: handleRef.current, picture };
135
+ }