react-native-vroom-chart 0.13.1 → 0.15.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 +133 -8
- package/cpp/_core_include/vroom/vroom_chart.h +90 -7
- package/cpp/_core_src/candles.h +7 -5
- package/cpp/_core_src/chart.cpp +287 -152
- package/cpp/_core_src/chart.h +29 -3
- package/cpp/_core_src/chart_facade.cpp +113 -1
- package/cpp/_core_src/footprints.cpp +226 -0
- package/cpp/_core_src/footprints.h +45 -0
- package/cpp/_core_src/footprints_layout.cpp +140 -0
- package/cpp/_core_src/footprints_layout.h +94 -0
- package/cpp/_core_src/tip_pulse.h +4 -4
- package/cpp/_core_src/viewport.h +4 -0
- package/lib/index.d.mts +186 -6
- package/lib/index.d.ts +186 -6
- package/lib/index.js +89 -7
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +89 -7
- package/lib/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/VroomChart.tsx +89 -5
- package/src/index.ts +7 -0
- package/src/jsi.d.ts +45 -8
- package/src/types.ts +7 -0
- package/src/useChartCore.ts +56 -5
|
@@ -42,7 +42,7 @@ ChartHostObject::~ChartHostObject() {
|
|
|
42
42
|
std::vector<jsi::PropNameID> ChartHostObject::getPropertyNames(
|
|
43
43
|
jsi::Runtime& rt) {
|
|
44
44
|
std::vector<jsi::PropNameID> out;
|
|
45
|
-
out.reserve(
|
|
45
|
+
out.reserve(42);
|
|
46
46
|
out.push_back(jsi::PropNameID::forAscii(rt, "setCandles"));
|
|
47
47
|
out.push_back(jsi::PropNameID::forAscii(rt, "setSize"));
|
|
48
48
|
out.push_back(jsi::PropNameID::forAscii(rt, "setColor"));
|
|
@@ -82,6 +82,9 @@ std::vector<jsi::PropNameID> ChartHostObject::getPropertyNames(
|
|
|
82
82
|
out.push_back(jsi::PropNameID::forAscii(rt, "hitTestPriceLine"));
|
|
83
83
|
out.push_back(jsi::PropNameID::forAscii(rt, "setPriceLineHover"));
|
|
84
84
|
out.push_back(jsi::PropNameID::forAscii(rt, "setPriceLineDrag"));
|
|
85
|
+
out.push_back(jsi::PropNameID::forAscii(rt, "setFootprints"));
|
|
86
|
+
out.push_back(jsi::PropNameID::forAscii(rt, "hitTestFootprint"));
|
|
87
|
+
out.push_back(jsi::PropNameID::forAscii(rt, "setFootprintHover"));
|
|
85
88
|
out.push_back(jsi::PropNameID::forAscii(rt, "render"));
|
|
86
89
|
return out;
|
|
87
90
|
}
|
|
@@ -484,17 +487,25 @@ jsi::Value ChartHostObject::get(jsi::Runtime& rt,
|
|
|
484
487
|
}
|
|
485
488
|
|
|
486
489
|
if (name == "beginIntervalMorph") {
|
|
487
|
-
// beginIntervalMorph() — capture the visible candle geometry so the
|
|
488
|
-
// setCandles can
|
|
490
|
+
// beginIntervalMorph(mode?) — capture the visible candle geometry so the
|
|
491
|
+
// next setCandles can animate. Optional string `'fade'` or `'transform'`
|
|
492
|
+
// (default). Call before setCandles.
|
|
489
493
|
return jsi::Function::createFromHostFunction(
|
|
490
494
|
rt,
|
|
491
495
|
jsi::PropNameID::forAscii(rt, "beginIntervalMorph"),
|
|
492
|
-
|
|
493
|
-
[this](jsi::Runtime&
|
|
496
|
+
1,
|
|
497
|
+
[this](jsi::Runtime& rt2,
|
|
494
498
|
const jsi::Value& /*thisVal*/,
|
|
495
|
-
const jsi::Value*
|
|
496
|
-
size_t
|
|
497
|
-
|
|
499
|
+
const jsi::Value* args,
|
|
500
|
+
size_t count) -> jsi::Value {
|
|
501
|
+
int32_t mode = 0;
|
|
502
|
+
if (count >= 1 && args[0].isString()) {
|
|
503
|
+
const auto s = args[0].asString(rt2).utf8(rt2);
|
|
504
|
+
mode = s == "fade" ? 1 : 0;
|
|
505
|
+
} else if (count >= 1 && args[0].isNumber()) {
|
|
506
|
+
mode = args[0].asNumber() != 0 ? 1 : 0;
|
|
507
|
+
}
|
|
508
|
+
vroom_chart_begin_interval_morph(chart_, mode);
|
|
498
509
|
return jsi::Value::undefined();
|
|
499
510
|
});
|
|
500
511
|
}
|
|
@@ -1181,6 +1192,120 @@ jsi::Value ChartHostObject::get(jsi::Runtime& rt,
|
|
|
1181
1192
|
});
|
|
1182
1193
|
}
|
|
1183
1194
|
|
|
1195
|
+
if (name == "setFootprints") {
|
|
1196
|
+
// setFootprints({ prints: [{ timeMs, side }, ...], radiusPx, gapPx, marginPx,
|
|
1197
|
+
// hoverBoost }) — replaces the full set of executed-trade badges. The core
|
|
1198
|
+
// buckets them onto candles itself, so raw fill times are what to pass. No
|
|
1199
|
+
// render; the next render() picks it up.
|
|
1200
|
+
return jsi::Function::createFromHostFunction(
|
|
1201
|
+
rt,
|
|
1202
|
+
jsi::PropNameID::forAscii(rt, "setFootprints"),
|
|
1203
|
+
1,
|
|
1204
|
+
[this](jsi::Runtime& rt2,
|
|
1205
|
+
const jsi::Value& /*thisVal*/,
|
|
1206
|
+
const jsi::Value* args,
|
|
1207
|
+
size_t count) -> jsi::Value {
|
|
1208
|
+
if (count < 1 || !args[0].isObject()) return jsi::Value::undefined();
|
|
1209
|
+
auto cfg = args[0].asObject(rt2);
|
|
1210
|
+
auto prints_val = cfg.getProperty(rt2, "prints");
|
|
1211
|
+
if (!prints_val.isObject()) return jsi::Value::undefined();
|
|
1212
|
+
auto prints_obj = prints_val.asObject(rt2);
|
|
1213
|
+
if (!prints_obj.isArray(rt2)) return jsi::Value::undefined();
|
|
1214
|
+
auto arr = prints_obj.asArray(rt2);
|
|
1215
|
+
const size_t len = arr.size(rt2);
|
|
1216
|
+
std::vector<VroomFootprint> prints(len);
|
|
1217
|
+
for (size_t i = 0; i < len; ++i) {
|
|
1218
|
+
auto f = arr.getValueAtIndex(rt2, i).asObject(rt2);
|
|
1219
|
+
prints[i].time_ms =
|
|
1220
|
+
static_cast<int64_t>(f.getProperty(rt2, "timeMs").asNumber());
|
|
1221
|
+
prints[i].side =
|
|
1222
|
+
static_cast<int32_t>(f.getProperty(rt2, "side").asNumber());
|
|
1223
|
+
}
|
|
1224
|
+
VroomFootprintStyle style{};
|
|
1225
|
+
style.radius_px = static_cast<float>(
|
|
1226
|
+
cfg.getProperty(rt2, "radiusPx").asNumber());
|
|
1227
|
+
style.gap_px = static_cast<float>(
|
|
1228
|
+
cfg.getProperty(rt2, "gapPx").asNumber());
|
|
1229
|
+
style.margin_px = static_cast<float>(
|
|
1230
|
+
cfg.getProperty(rt2, "marginPx").asNumber());
|
|
1231
|
+
style.hover_boost = static_cast<float>(
|
|
1232
|
+
cfg.getProperty(rt2, "hoverBoost").asNumber());
|
|
1233
|
+
vroom_chart_set_footprints(chart_, prints.data(), prints.size(), &style);
|
|
1234
|
+
return jsi::Value::undefined();
|
|
1235
|
+
});
|
|
1236
|
+
}
|
|
1237
|
+
|
|
1238
|
+
if (name == "hitTestFootprint") {
|
|
1239
|
+
// hitTestFootprint(x, y) -> { side, candleTimeMs, x, y, radius, pane,
|
|
1240
|
+
// indices } | null. `indices` addresses the array last passed to
|
|
1241
|
+
// setFootprints and covers *both* sides of that candle, so one call fills a
|
|
1242
|
+
// tooltip; `pane` is the plot rect, for deciding which side of the badge that
|
|
1243
|
+
// tooltip fits on. No rendering.
|
|
1244
|
+
return jsi::Function::createFromHostFunction(
|
|
1245
|
+
rt,
|
|
1246
|
+
jsi::PropNameID::forAscii(rt, "hitTestFootprint"),
|
|
1247
|
+
2,
|
|
1248
|
+
[this](jsi::Runtime& rt2,
|
|
1249
|
+
const jsi::Value& /*thisVal*/,
|
|
1250
|
+
const jsi::Value* args,
|
|
1251
|
+
size_t count) -> jsi::Value {
|
|
1252
|
+
if (count < 2) return jsi::Value::null();
|
|
1253
|
+
VroomFootprintHit hit{};
|
|
1254
|
+
if (!vroom_chart_hit_test_footprint(
|
|
1255
|
+
chart_, static_cast<float>(args[0].asNumber()),
|
|
1256
|
+
static_cast<float>(args[1].asNumber()), &hit)) {
|
|
1257
|
+
return jsi::Value::null();
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1260
|
+
const int32_t n =
|
|
1261
|
+
vroom_chart_footprints_at(chart_, hit.candle_time_ms, nullptr, 0);
|
|
1262
|
+
std::vector<int32_t> idx(static_cast<size_t>(n > 0 ? n : 0));
|
|
1263
|
+
if (n > 0) {
|
|
1264
|
+
vroom_chart_footprints_at(chart_, hit.candle_time_ms, idx.data(), n);
|
|
1265
|
+
}
|
|
1266
|
+
jsi::Array indices(rt2, idx.size());
|
|
1267
|
+
for (size_t i = 0; i < idx.size(); ++i) {
|
|
1268
|
+
indices.setValueAtIndex(rt2, i, jsi::Value(idx[i]));
|
|
1269
|
+
}
|
|
1270
|
+
|
|
1271
|
+
jsi::Object pane(rt2);
|
|
1272
|
+
pane.setProperty(rt2, "left", hit.pane_left);
|
|
1273
|
+
pane.setProperty(rt2, "top", hit.pane_top);
|
|
1274
|
+
pane.setProperty(rt2, "right", hit.pane_right);
|
|
1275
|
+
pane.setProperty(rt2, "bottom", hit.pane_bottom);
|
|
1276
|
+
|
|
1277
|
+
jsi::Object obj(rt2);
|
|
1278
|
+
obj.setProperty(rt2, "side", hit.side);
|
|
1279
|
+
obj.setProperty(rt2, "candleTimeMs",
|
|
1280
|
+
static_cast<double>(hit.candle_time_ms));
|
|
1281
|
+
obj.setProperty(rt2, "x", hit.center_x);
|
|
1282
|
+
obj.setProperty(rt2, "y", hit.center_y);
|
|
1283
|
+
obj.setProperty(rt2, "radius", hit.radius);
|
|
1284
|
+
obj.setProperty(rt2, "pane", std::move(pane));
|
|
1285
|
+
obj.setProperty(rt2, "indices", std::move(indices));
|
|
1286
|
+
return obj;
|
|
1287
|
+
});
|
|
1288
|
+
}
|
|
1289
|
+
|
|
1290
|
+
if (name == "setFootprintHover") {
|
|
1291
|
+
// setFootprintHover(candleTimeMs, side) — highlight one badge; side -1
|
|
1292
|
+
// clears. Touch has no hover, so on RN this tracks the tapped badge.
|
|
1293
|
+
return jsi::Function::createFromHostFunction(
|
|
1294
|
+
rt,
|
|
1295
|
+
jsi::PropNameID::forAscii(rt, "setFootprintHover"),
|
|
1296
|
+
2,
|
|
1297
|
+
[this](jsi::Runtime& /*rt2*/,
|
|
1298
|
+
const jsi::Value& /*thisVal*/,
|
|
1299
|
+
const jsi::Value* args,
|
|
1300
|
+
size_t count) -> jsi::Value {
|
|
1301
|
+
if (count < 2) return jsi::Value::undefined();
|
|
1302
|
+
vroom_chart_set_footprint_hover(
|
|
1303
|
+
chart_, static_cast<int64_t>(args[0].asNumber()),
|
|
1304
|
+
static_cast<int32_t>(args[1].asNumber()));
|
|
1305
|
+
return jsi::Value::undefined();
|
|
1306
|
+
});
|
|
1307
|
+
}
|
|
1308
|
+
|
|
1184
1309
|
if (name == "render") {
|
|
1185
1310
|
return jsi::Function::createFromHostFunction(
|
|
1186
1311
|
rt,
|
|
@@ -257,6 +257,53 @@ typedef struct VroomPriceLineStyle {
|
|
|
257
257
|
float hover_boost; // brightness multiplier for the hovered segment (1 = flat)
|
|
258
258
|
} VroomPriceLineStyle;
|
|
259
259
|
|
|
260
|
+
// ---- Footprints (executed-trade badges) -----------------------------------
|
|
261
|
+
|
|
262
|
+
typedef enum {
|
|
263
|
+
VROOM_FOOTPRINT_BUY = 0, // position entry — "+" badge in the bull color
|
|
264
|
+
VROOM_FOOTPRINT_SELL = 1, // position exit — "-" badge in the bear color
|
|
265
|
+
} VroomFootprintSide;
|
|
266
|
+
|
|
267
|
+
// A single executed trade, drawn as a circular badge above the candle it fell in.
|
|
268
|
+
//
|
|
269
|
+
// `time_ms` is the raw execution time, *not* a bar-open time: the core buckets
|
|
270
|
+
// each footprint into whichever candle's window contains it, so one array renders
|
|
271
|
+
// correctly at every interval and re-groups by itself when the candles change.
|
|
272
|
+
// Order is irrelevant — the core sorts within each bucket.
|
|
273
|
+
//
|
|
274
|
+
// Only the fields the renderer needs live here; a host's per-trade payload (id,
|
|
275
|
+
// price, size) stays on the host side and is rejoined via the indices reported by
|
|
276
|
+
// vroom_chart_footprints_at.
|
|
277
|
+
typedef struct VroomFootprint {
|
|
278
|
+
int64_t time_ms;
|
|
279
|
+
int32_t side; // VroomFootprintSide
|
|
280
|
+
} VroomFootprint;
|
|
281
|
+
|
|
282
|
+
// Layout/style shared by every footprint badge.
|
|
283
|
+
typedef struct VroomFootprintStyle {
|
|
284
|
+
float radius_px; // badge radius; <= 0 falls back to 9
|
|
285
|
+
float gap_px; // vertical gap between the two stacked badges; < 0 => 4
|
|
286
|
+
float margin_px; // gap between the candle's high and the first badge; < 0 => 8
|
|
287
|
+
float hover_boost; // brightness multiplier for the hovered badge (1 = flat)
|
|
288
|
+
} VroomFootprintStyle;
|
|
289
|
+
|
|
290
|
+
// The badge under a pixel, as reported by vroom_chart_hit_test_footprint.
|
|
291
|
+
typedef struct VroomFootprintHit {
|
|
292
|
+
int64_t candle_time_ms; // bar-open time of the candle the badge sits on
|
|
293
|
+
int32_t side; // VroomFootprintSide — which of the candle's two badges
|
|
294
|
+
float center_x; // badge center, in the same px space as the hit test
|
|
295
|
+
float center_y;
|
|
296
|
+
float radius;
|
|
297
|
+
// The plot rect the badge was clipped to — same px space, axis strips
|
|
298
|
+
// excluded. Reported because a host placing its own tooltip has no other way
|
|
299
|
+
// to know it: the surface it measures includes the price and time axes, so
|
|
300
|
+
// sizing against that overstates the room next to a badge near the edge.
|
|
301
|
+
float pane_left;
|
|
302
|
+
float pane_top;
|
|
303
|
+
float pane_right;
|
|
304
|
+
float pane_bottom;
|
|
305
|
+
} VroomFootprintHit;
|
|
306
|
+
|
|
260
307
|
// A continuous data coordinate at a pixel position (no candle snapping). Used to
|
|
261
308
|
// translate a drawing-tool click into a data-space anchor.
|
|
262
309
|
typedef struct VroomCoord {
|
|
@@ -420,14 +467,13 @@ void vroom_chart_preserve_price_envelope(VroomChart* chart,
|
|
|
420
467
|
double prev_low, double prev_high);
|
|
421
468
|
|
|
422
469
|
// Captures the currently visible candle geometry so the next data swap can be
|
|
423
|
-
// animated
|
|
424
|
-
//
|
|
470
|
+
// animated. `mode` 0 (transform) lerps each visible column into its counterpart,
|
|
471
|
+
// paired by slot counting back from the right edge. `mode` 1 (fade) fades the
|
|
472
|
+
// capture out then the new scene in on the same envelope the axes already use.
|
|
425
473
|
//
|
|
426
|
-
//
|
|
427
|
-
//
|
|
428
|
-
|
|
429
|
-
// No-op when nothing is visible.
|
|
430
|
-
void vroom_chart_begin_interval_morph(VroomChart* chart);
|
|
474
|
+
// Call before set_candles, then drive vroom_chart_set_interval_morph from 0
|
|
475
|
+
// to 1. No-op when nothing is visible.
|
|
476
|
+
void vroom_chart_begin_interval_morph(VroomChart* chart, int32_t mode);
|
|
431
477
|
|
|
432
478
|
// Advances the interval morph started by vroom_chart_begin_interval_morph. `t`
|
|
433
479
|
// (clamped to 0..1) is the eased progress: 0 renders the captured geometry
|
|
@@ -690,6 +736,43 @@ void vroom_chart_set_price_line_hover(VroomChart* chart, int32_t index,
|
|
|
690
736
|
void vroom_chart_set_price_line_drag(VroomChart* chart, int32_t index,
|
|
691
737
|
double price);
|
|
692
738
|
|
|
739
|
+
// Replaces the full set of footprints and their shared style. Pass count 0 to
|
|
740
|
+
// clear; `style` may be null when count is 0.
|
|
741
|
+
//
|
|
742
|
+
// Footprints are grouped onto candles by timestamp, so at most two badges render
|
|
743
|
+
// per candle: one for that bar's buys and one for its sells, however many trades
|
|
744
|
+
// went into each. When a candle has both, they stack upward with `gap_px` between
|
|
745
|
+
// them, the side whose latest trade came first sitting nearest the bar. Badges sit
|
|
746
|
+
// above the candle's high, clipped to the price pane, and re-group on their own
|
|
747
|
+
// whenever the candles change (a new interval, more history) — the host never
|
|
748
|
+
// re-buckets anything.
|
|
749
|
+
void vroom_chart_set_footprints(VroomChart* chart, const VroomFootprint* prints,
|
|
750
|
+
size_t count,
|
|
751
|
+
const VroomFootprintStyle* style);
|
|
752
|
+
|
|
753
|
+
// Hit-tests pixel (x_px, y_px) against the footprint badges. On a hit fills *out
|
|
754
|
+
// with the badge's candle, side and pixel geometry and returns true; returns false
|
|
755
|
+
// on a miss (out untouched). `out` may be null to test without reading the hit.
|
|
756
|
+
// When two badges overlap the nearest center wins.
|
|
757
|
+
bool vroom_chart_hit_test_footprint(VroomChart* chart, float x_px, float y_px,
|
|
758
|
+
VroomFootprintHit* out);
|
|
759
|
+
|
|
760
|
+
// Fills `out_indices` with the indices — into the array last passed to
|
|
761
|
+
// vroom_chart_set_footprints — of every footprint bucketed into the candle opening
|
|
762
|
+
// at `candle_time_ms`, *both* sides, ascending by time. Returns the total count,
|
|
763
|
+
// which may exceed `max` (only the first `max` are written), or 0 when that candle
|
|
764
|
+
// has no footprints. Pass a null `out_indices` with max 0 to size the buffer first.
|
|
765
|
+
//
|
|
766
|
+
// This is how a host rejoins a hit badge to its own trade objects: hit-test to get
|
|
767
|
+
// the candle, then map these indices back through the array it supplied.
|
|
768
|
+
int32_t vroom_chart_footprints_at(VroomChart* chart, int64_t candle_time_ms,
|
|
769
|
+
int32_t* out_indices, int32_t max);
|
|
770
|
+
|
|
771
|
+
// Marks one footprint badge as hovered so it renders highlighted. `side` -1
|
|
772
|
+
// clears the hover; `candle_time_ms` and `side` match vroom_chart_hit_test_footprint.
|
|
773
|
+
void vroom_chart_set_footprint_hover(VroomChart* chart, int64_t candle_time_ms,
|
|
774
|
+
int32_t side);
|
|
775
|
+
|
|
693
776
|
// Sets the transient in-progress "draft" the drawing tool shows while the user
|
|
694
777
|
// places points. Node A is always shown; when `has_b`, node B is shown too.
|
|
695
778
|
// `guide != 0` also draws the live preview (a guideline for a line, or a preview
|
package/cpp/_core_src/candles.h
CHANGED
|
@@ -28,11 +28,13 @@ namespace vroom::candles {
|
|
|
28
28
|
// body/wick heights and width shrink to the line). `opacity` (0..1) fades the
|
|
29
29
|
// whole candle layer out as the line fades in. Both default to a no-op.
|
|
30
30
|
//
|
|
31
|
-
// `from` / `from_n` is the outgoing geometry of an interval
|
|
32
|
-
// the right of the visible slice (slot 0 = newest), and `morph_t` (0..1)
|
|
33
|
-
// eased progress toward `visible`. Each slot's wick and body interpolate
|
|
34
|
-
// the two; slots present on only one side fade in or out.
|
|
35
|
-
//
|
|
31
|
+
// `from` / `from_n` is the outgoing geometry of an interval *transform*, indexed
|
|
32
|
+
// from the right of the visible slice (slot 0 = newest), and `morph_t` (0..1)
|
|
33
|
+
// is the eased progress toward `visible`. Each slot's wick and body interpolate
|
|
34
|
+
// between the two; slots present on only one side fade in or out. A host-chosen
|
|
35
|
+
// fade (see interval_morph_fade) skips this lerp: the chart draws the capture
|
|
36
|
+
// then the new scene via interval_phase instead. `morph_t == 1` (the default)
|
|
37
|
+
// draws `visible` alone.
|
|
36
38
|
void draw(SkCanvas* canvas,
|
|
37
39
|
const ::VroomCandle* visible,
|
|
38
40
|
std::size_t n,
|