react-native-vroom-chart 0.5.0 → 0.6.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/android/CMakeLists.txt +143 -0
- package/android/README.md +60 -5
- package/android/build.gradle +115 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/cpp/VroomChartJni.cpp +24 -0
- package/android/src/main/java/com/vroom/chart/VroomChartModule.kt +31 -0
- package/android/src/main/java/com/vroom/chart/VroomChartPackage.kt +31 -0
- package/cpp/VroomChartHostObject.cpp +218 -1
- package/cpp/VroomJsiInstaller.cpp +11 -1
- package/cpp/VroomSkiaContext.cpp +15 -7
- package/cpp/_core_include/vroom/vroom_chart.h +70 -0
- package/cpp/_core_src/chart.cpp +7 -0
- package/cpp/_core_src/chart.h +27 -0
- package/cpp/_core_src/chart_facade.cpp +91 -0
- package/cpp/_core_src/price_line_layout.cpp +87 -0
- package/cpp/_core_src/price_line_layout.h +80 -0
- package/cpp/_core_src/price_lines.cpp +428 -0
- package/cpp/_core_src/price_lines.h +56 -0
- package/lib/index.d.mts +104 -1
- package/lib/index.d.ts +104 -1
- package/lib/index.js +98 -7
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +98 -7
- package/lib/index.mjs.map +1 -1
- package/package.json +6 -5
- package/src/VroomChart.tsx +93 -8
- package/src/index.ts +2 -0
- package/src/jsi.d.ts +48 -0
- package/src/types.ts +2 -0
- package/src/useChartCore.ts +65 -3
package/src/jsi.d.ts
CHANGED
|
@@ -162,6 +162,54 @@ export interface ChartHandle {
|
|
|
162
162
|
fillEnabled: boolean;
|
|
163
163
|
fillOpacity: number;
|
|
164
164
|
}): void;
|
|
165
|
+
/**
|
|
166
|
+
* The continuous data coordinate at pixel (x, y) — not snapped to a candle
|
|
167
|
+
* slot. Null when there are no candles or the viewport is degenerate. Cheap to
|
|
168
|
+
* call at gesture rate (no rendering).
|
|
169
|
+
*/
|
|
170
|
+
coordAt(x: number, y: number): { timeMs: number; price: number } | null;
|
|
171
|
+
/**
|
|
172
|
+
* Replaces the full set of price status lines (plus their shared style).
|
|
173
|
+
* lineStyle: 0=solid,1=dotted,2=dashed; color/bodyBg are packed 0xAARRGGBB;
|
|
174
|
+
* flags is a bitmask (1=draggable, 2=closable, 4=axis label, 8=extend left);
|
|
175
|
+
* align: 0=left,1=center,2=right. Pass an empty `lines` array to clear.
|
|
176
|
+
*/
|
|
177
|
+
setPriceLines(spec: {
|
|
178
|
+
lines: {
|
|
179
|
+
price: number;
|
|
180
|
+
color: number;
|
|
181
|
+
width: number;
|
|
182
|
+
lineStyle: number;
|
|
183
|
+
text: string;
|
|
184
|
+
quantity: string;
|
|
185
|
+
flags: number;
|
|
186
|
+
}[];
|
|
187
|
+
bodyBg: number;
|
|
188
|
+
fontSizePx: number;
|
|
189
|
+
lineLengthFrac: number;
|
|
190
|
+
align: number;
|
|
191
|
+
hoverBoost: number;
|
|
192
|
+
}): void;
|
|
193
|
+
/**
|
|
194
|
+
* Hit-tests pixel (x, y) against the price lines. `part` is 0 for the line or
|
|
195
|
+
* its label body (the drag target) and 1 for the close button; close buttons
|
|
196
|
+
* win over lines and the nearest in y wins among several candidates. Only
|
|
197
|
+
* draggable lines report part 0 and only closable lines report part 1. Cheap
|
|
198
|
+
* to call at gesture rate (no rendering).
|
|
199
|
+
*/
|
|
200
|
+
hitTestPriceLine(x: number, y: number): { index: number; part: number } | null;
|
|
201
|
+
/**
|
|
202
|
+
* Marks a price line's segment as hovered so it renders highlighted; -1 clears.
|
|
203
|
+
* `part` matches hitTestPriceLine. Touch has no hover state, so this is here
|
|
204
|
+
* for pointer devices and web parity.
|
|
205
|
+
*/
|
|
206
|
+
setPriceLineHover(index: number, part: number): void;
|
|
207
|
+
/**
|
|
208
|
+
* Drives the live drag preview: the line, its label and its badge render at
|
|
209
|
+
* `price` with a ghost at the committed one. Pass -1 to end the preview. The
|
|
210
|
+
* committed price is untouched — restate setPriceLines to apply the move.
|
|
211
|
+
*/
|
|
212
|
+
setPriceLineDrag(index: number, price: number): void;
|
|
165
213
|
/** True while any axis-label fade is still in progress. Drives a RAF loop. */
|
|
166
214
|
isAnimating(): boolean;
|
|
167
215
|
render(): SkPicture | null;
|
package/src/types.ts
CHANGED
package/src/useChartCore.ts
CHANGED
|
@@ -11,6 +11,8 @@ import type {
|
|
|
11
11
|
ChartType,
|
|
12
12
|
MACDConfig,
|
|
13
13
|
MovingAverageOverlay,
|
|
14
|
+
PriceLine,
|
|
15
|
+
PriceLinesStyle,
|
|
14
16
|
RSIConfig,
|
|
15
17
|
VisibleRange,
|
|
16
18
|
VroomTheme,
|
|
@@ -68,6 +70,61 @@ function bollingerToSpec(cfg: BollingerBandsConfig | undefined) {
|
|
|
68
70
|
};
|
|
69
71
|
}
|
|
70
72
|
|
|
73
|
+
// Price-line defaults: a soft red dotted rule with a dark translucent label,
|
|
74
|
+
// close in weight to the current-price indicator it sits beside.
|
|
75
|
+
const DEFAULT_PRICE_LINE_COLOR = 0xffef5350;
|
|
76
|
+
const DEFAULT_PRICE_LINE_BODY_BG = 0xd91c2128;
|
|
77
|
+
const DEFAULT_PRICE_LINE_HOVER_BOOST = 1.25;
|
|
78
|
+
|
|
79
|
+
const LINE_STYLES = { solid: 0, dotted: 1, dashed: 2 } as const;
|
|
80
|
+
|
|
81
|
+
// Mirrors VroomPriceLineFlags in packages/core/include/vroom/vroom_chart.h.
|
|
82
|
+
const PRICE_LINE_DRAGGABLE = 1 << 0;
|
|
83
|
+
const PRICE_LINE_CLOSABLE = 1 << 1;
|
|
84
|
+
const PRICE_LINE_AXIS_LABEL = 1 << 2;
|
|
85
|
+
const PRICE_LINE_EXTEND_LEFT = 1 << 3;
|
|
86
|
+
|
|
87
|
+
/** The price lines + their shared style, as the chart's props express them. */
|
|
88
|
+
export type PriceLinesProp = {
|
|
89
|
+
lines: PriceLine[];
|
|
90
|
+
style?: PriceLinesStyle;
|
|
91
|
+
/**
|
|
92
|
+
* Whether the host supplied a close handler. The close button is
|
|
93
|
+
* callback-gated, so with nothing for it to do it isn't drawn at all.
|
|
94
|
+
*/
|
|
95
|
+
hasCloseHandler: boolean;
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
function priceLinesToSpec(cfg: PriceLinesProp) {
|
|
99
|
+
return {
|
|
100
|
+
lines: cfg.lines.map((l) => ({
|
|
101
|
+
price: l.price,
|
|
102
|
+
color:
|
|
103
|
+
(l.color != null ? parseColor(l.color) : null) ?? DEFAULT_PRICE_LINE_COLOR,
|
|
104
|
+
width: l.width ?? 1,
|
|
105
|
+
lineStyle: LINE_STYLES[l.lineStyle ?? 'dotted'],
|
|
106
|
+
text: l.text ?? '',
|
|
107
|
+
quantity: l.quantity ?? '',
|
|
108
|
+
flags:
|
|
109
|
+
(l.draggable ? PRICE_LINE_DRAGGABLE : 0) |
|
|
110
|
+
(cfg.hasCloseHandler && l.closable !== false ? PRICE_LINE_CLOSABLE : 0) |
|
|
111
|
+
(l.axisLabel !== false ? PRICE_LINE_AXIS_LABEL : 0) |
|
|
112
|
+
(l.extendLeft !== false ? PRICE_LINE_EXTEND_LEFT : 0),
|
|
113
|
+
})),
|
|
114
|
+
bodyBg:
|
|
115
|
+
(cfg.style?.bodyBackground != null ? parseColor(cfg.style.bodyBackground) : null) ??
|
|
116
|
+
DEFAULT_PRICE_LINE_BODY_BG,
|
|
117
|
+
fontSizePx: cfg.style?.fontSize ?? 0,
|
|
118
|
+
lineLengthFrac: cfg.style?.inset ?? 0,
|
|
119
|
+
align: cfg.style?.align === 'left' ? 0 : cfg.style?.align === 'center' ? 1 : 2,
|
|
120
|
+
hoverBoost: cfg.style?.hoverBoost ?? DEFAULT_PRICE_LINE_HOVER_BOOST,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Cleared overlay: no lines (the style values are irrelevant, but the spec shape
|
|
125
|
+
// requires them).
|
|
126
|
+
const EMPTY_PRICE_LINES = priceLinesToSpec({ lines: [], hasCloseHandler: false });
|
|
127
|
+
|
|
71
128
|
let installed = false;
|
|
72
129
|
function ensureInstalled(): void {
|
|
73
130
|
if (installed) return;
|
|
@@ -101,6 +158,7 @@ export function useChartCore(
|
|
|
101
158
|
movingAverages?: MovingAverageOverlay[],
|
|
102
159
|
vwap?: VWAPConfig,
|
|
103
160
|
bollingerBands?: BollingerBandsConfig,
|
|
161
|
+
priceLines?: PriceLinesProp,
|
|
104
162
|
): ChartCoreState {
|
|
105
163
|
const handleRef = useRef<ChartHandle | null>(null);
|
|
106
164
|
// Push setDefaultCandleWidth only once (first load): setCandles re-runs on
|
|
@@ -130,6 +188,7 @@ export function useChartCore(
|
|
|
130
188
|
const maKey = movingAverages ? JSON.stringify(movingAverages) : '';
|
|
131
189
|
const vwapKey = vwap ? JSON.stringify(vwap) : '';
|
|
132
190
|
const bollingerKey = bollingerBands ? JSON.stringify(bollingerBands) : '';
|
|
191
|
+
const priceLinesKey = priceLines ? JSON.stringify(priceLines) : '';
|
|
133
192
|
|
|
134
193
|
useEffect(() => {
|
|
135
194
|
const h = handleRef.current;
|
|
@@ -180,13 +239,16 @@ export function useChartCore(
|
|
|
180
239
|
vwap?.width ?? 1.5,
|
|
181
240
|
);
|
|
182
241
|
h.setBollinger(bollingerToSpec(bollingerBands));
|
|
242
|
+
h.setPriceLines(
|
|
243
|
+
priceLines?.lines.length ? priceLinesToSpec(priceLines) : EMPTY_PRICE_LINES,
|
|
244
|
+
);
|
|
183
245
|
// TODO(rn-parity): mirror the web `liquidity` overlay here (setLiquidity +
|
|
184
246
|
// the VroomBand structs in the JSI handle) — web-only for now.
|
|
185
247
|
setPicture(h.render());
|
|
186
|
-
// theme/rsi/macd/movingAverages/vwap/bollingerBands are
|
|
187
|
-
// their *Key deps.
|
|
248
|
+
// theme/rsi/macd/movingAverages/vwap/bollingerBands/priceLines are
|
|
249
|
+
// represented by their *Key deps.
|
|
188
250
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
189
|
-
}, [candles, size.width, size.height, size.pxRatio, explicit, startMs, endMs, defaultCandleWidth, themeKey, rsiKey, macdKey, maKey, vwapKey, bollingerKey]);
|
|
251
|
+
}, [candles, size.width, size.height, size.pxRatio, explicit, startMs, endMs, defaultCandleWidth, themeKey, rsiKey, macdKey, maKey, vwapKey, bollingerKey, priceLinesKey]);
|
|
190
252
|
|
|
191
253
|
return { handle: handleRef.current, picture };
|
|
192
254
|
}
|