react-native-vroom-chart 0.1.2 → 0.1.3
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/_core_include/vroom/vroom_chart.h +66 -0
- package/cpp/_core_src/chart.cpp +8 -2
- package/cpp/_core_src/chart.h +25 -4
- package/cpp/_core_src/chart_facade.cpp +122 -38
- package/cpp/_core_src/drawings.cpp +108 -0
- package/cpp/_core_src/drawings.h +34 -0
- package/cpp/_core_src/labels.cpp +1 -1
- package/cpp/_core_src/viewport.cpp +33 -0
- package/cpp/_core_src/viewport.h +24 -0
- package/lib/index.d.mts +61 -0
- package/lib/index.d.ts +61 -0
- package/package.json +11 -10
- package/LICENSE +0 -21
|
@@ -49,6 +49,27 @@ typedef struct VroomOverlay {
|
|
|
49
49
|
float width; // stroke width in px
|
|
50
50
|
} VroomOverlay;
|
|
51
51
|
|
|
52
|
+
// A drawing anchor in data space (so a drawing tracks the candles on pan/zoom).
|
|
53
|
+
typedef struct VroomDrawPoint {
|
|
54
|
+
int64_t time_ms; // epoch milliseconds (not snapped to a candle slot)
|
|
55
|
+
double price;
|
|
56
|
+
} VroomDrawPoint;
|
|
57
|
+
|
|
58
|
+
// A committed line drawing: a two-point trendline on the price pane.
|
|
59
|
+
typedef struct VroomDrawing {
|
|
60
|
+
VroomDrawPoint a;
|
|
61
|
+
VroomDrawPoint b;
|
|
62
|
+
uint32_t color; // 0xAARRGGBB
|
|
63
|
+
float width; // stroke width in px
|
|
64
|
+
} VroomDrawing;
|
|
65
|
+
|
|
66
|
+
// A continuous data coordinate at a pixel position (no candle snapping). Used to
|
|
67
|
+
// translate a drawing-tool click into a data-space anchor.
|
|
68
|
+
typedef struct VroomCoord {
|
|
69
|
+
int64_t time_ms;
|
|
70
|
+
double price;
|
|
71
|
+
} VroomCoord;
|
|
72
|
+
|
|
52
73
|
// ---- Styling keys ---------------------------------------------------------
|
|
53
74
|
|
|
54
75
|
typedef enum {
|
|
@@ -109,6 +130,24 @@ void vroom_chart_set_size(VroomChart* chart, float width_px, float height_px, fl
|
|
|
109
130
|
// ---- Viewport -------------------------------------------------------------
|
|
110
131
|
|
|
111
132
|
void vroom_chart_set_visible_range(VroomChart* chart, int64_t start_ms, int64_t end_ms);
|
|
133
|
+
|
|
134
|
+
// Reads the current visible time window. Either out pointer may be null.
|
|
135
|
+
// Both are 0 when the window is still uninitialized.
|
|
136
|
+
void vroom_chart_get_visible_range(VroomChart* chart,
|
|
137
|
+
int64_t* out_start_ms, int64_t* out_end_ms);
|
|
138
|
+
|
|
139
|
+
// Reset to the fresh-mount view: frame the most recent ~80 candles and
|
|
140
|
+
// re-enable continuous y auto-fit (the price range follows the visible candles
|
|
141
|
+
// until the next manual y gesture). Use when the data series is wholesale
|
|
142
|
+
// replaced — e.g. switching assets. With no candles loaded, clears the window
|
|
143
|
+
// to 0/0 so the next set_candles applies the default framing.
|
|
144
|
+
void vroom_chart_reset_view(VroomChart* chart);
|
|
145
|
+
|
|
146
|
+
// Re-enable continuous y auto-fit only; the time window is untouched. Use
|
|
147
|
+
// after repositioning the window for a same-asset data swap (e.g. a timeframe
|
|
148
|
+
// switch) so the price scale re-fits the newly visible candles.
|
|
149
|
+
void vroom_chart_reset_price_scale(VroomChart* chart);
|
|
150
|
+
|
|
112
151
|
void vroom_chart_pan(VroomChart* chart, float dx_px, float dy_px);
|
|
113
152
|
// Directional zoom. scale_x scales the time window around focus_x_px (>1 =
|
|
114
153
|
// narrower window, wider candles); scale_y scales the price range around
|
|
@@ -212,6 +251,33 @@ void vroom_chart_set_overlays(VroomChart* chart, const VroomOverlay* overlays,
|
|
|
212
251
|
void vroom_chart_set_vwap(VroomChart* chart, bool enabled, int reset_offset_min,
|
|
213
252
|
uint32_t color, float width);
|
|
214
253
|
|
|
254
|
+
// ---- Drawings (line annotations) ------------------------------------------
|
|
255
|
+
|
|
256
|
+
// Replaces the full set of committed line drawings (data-anchored, so they track
|
|
257
|
+
// the candles on pan/zoom). Pass count 0 to clear. Drawings render on the price
|
|
258
|
+
// pane above the candles/overlays and below the axis labels & crosshair.
|
|
259
|
+
void vroom_chart_set_drawings(VroomChart* chart, const VroomDrawing* drawings,
|
|
260
|
+
size_t count);
|
|
261
|
+
|
|
262
|
+
// Sets the transient in-progress "draft" the drawing tool shows while the user
|
|
263
|
+
// places points. Node A is always shown; when `has_b`, node B is shown too.
|
|
264
|
+
// `guide != 0` also draws the guideline A->B (the live line preview); `guide == 0`
|
|
265
|
+
// draws node dots only (the committed segment already renders via set_drawings).
|
|
266
|
+
// `color`/`width` style the guideline to match the eventual line.
|
|
267
|
+
void vroom_chart_set_draft(VroomChart* chart, int64_t a_time, double a_price,
|
|
268
|
+
bool has_b, int64_t b_time, double b_price,
|
|
269
|
+
bool guide, uint32_t color, float width);
|
|
270
|
+
|
|
271
|
+
// Clears the draft (hides the in-progress node dots / guideline).
|
|
272
|
+
void vroom_chart_clear_draft(VroomChart* chart);
|
|
273
|
+
|
|
274
|
+
// Fills *out with the continuous data coordinate (time_ms, price) at pixel
|
|
275
|
+
// (x_px, y_px) using the free (non-snapped) mapping, and returns true. Returns
|
|
276
|
+
// false (leaving *out untouched) when there are no candles or the viewport is
|
|
277
|
+
// degenerate.
|
|
278
|
+
bool vroom_chart_coord_at(VroomChart* chart, float x_px, float y_px,
|
|
279
|
+
VroomCoord* out);
|
|
280
|
+
|
|
215
281
|
// ---- Rendering ------------------------------------------------------------
|
|
216
282
|
|
|
217
283
|
void vroom_chart_draw(VroomChart* chart, SkCanvas* canvas);
|
package/cpp/_core_src/chart.cpp
CHANGED
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
#include "candles.h"
|
|
22
22
|
#include "chart_internal.h"
|
|
23
23
|
#include "crosshair.h"
|
|
24
|
+
#include "drawings.h"
|
|
24
25
|
#include "labels.h"
|
|
25
26
|
#include "ma.h"
|
|
26
27
|
#include "ma_overlay.h"
|
|
@@ -116,9 +117,9 @@ void VroomChart::draw_chart(SkCanvas* canvas) {
|
|
|
116
117
|
if (n == 0) return;
|
|
117
118
|
const ::VroomCandle* visible = candles.data() + range.start;
|
|
118
119
|
|
|
119
|
-
const auto bounds =
|
|
120
|
+
const auto bounds = price_bounds_manual
|
|
120
121
|
? price_bounds
|
|
121
|
-
: vroom::
|
|
122
|
+
: vroom::auto_price_bounds(visible, n);
|
|
122
123
|
const int64_t window_ms = visible_end_ms - visible_start_ms;
|
|
123
124
|
|
|
124
125
|
const float candle_area_h = vroom::price_pane_bottom(lay);
|
|
@@ -176,6 +177,11 @@ void VroomChart::draw_chart(SkCanvas* canvas) {
|
|
|
176
177
|
}
|
|
177
178
|
}
|
|
178
179
|
|
|
180
|
+
// 5.7. Drawing annotations (committed line tools + the in-progress draft).
|
|
181
|
+
// On the price pane above the candles/overlays, below the axis labels.
|
|
182
|
+
vroom::drawings::draw(canvas, *this, lay, bounds, candle_right,
|
|
183
|
+
candle_area_h);
|
|
184
|
+
|
|
179
185
|
// 6. Axis backgrounds (mask any candle overflow). The x-axis separator
|
|
180
186
|
// line is intentionally omitted for now. The bottom strip anchors at
|
|
181
187
|
// x_axis_top (below any indicator pane) so it never paints over it.
|
package/cpp/_core_src/chart.h
CHANGED
|
@@ -46,7 +46,7 @@ struct VroomChart {
|
|
|
46
46
|
float height_px = 0.f;
|
|
47
47
|
float px_ratio = 1.f;
|
|
48
48
|
|
|
49
|
-
// 0/0 = uninitialized; set_candles defaults to last ~
|
|
49
|
+
// 0/0 = uninitialized; set_candles defaults to last ~80 candles.
|
|
50
50
|
int64_t visible_start_ms = 0;
|
|
51
51
|
int64_t visible_end_ms = 0;
|
|
52
52
|
|
|
@@ -55,10 +55,13 @@ struct VroomChart {
|
|
|
55
55
|
float axis_width_px = 0.f;
|
|
56
56
|
|
|
57
57
|
// --- price bounds (y-axis state) ---------------------------------------
|
|
58
|
-
//
|
|
59
|
-
//
|
|
58
|
+
// Two modes. Auto (price_bounds_manual == false, the default): the y-range
|
|
59
|
+
// continuously follows the visible candles each frame and `price_bounds`
|
|
60
|
+
// is ignored. Manual: the user has touched the y-axis (pinch zoom, axis
|
|
61
|
+
// drag, vertical drag-translate) and `price_bounds` is frozen until
|
|
62
|
+
// vroom_chart_reset_view / reset_price_scale re-enables auto mode.
|
|
60
63
|
vroom::PriceBounds price_bounds{0.0, 1.0};
|
|
61
|
-
bool
|
|
64
|
+
bool price_bounds_manual = false;
|
|
62
65
|
|
|
63
66
|
// --- crosshair (not yet drawn) -----------------------------------------
|
|
64
67
|
bool crosshair_active = false;
|
|
@@ -119,6 +122,24 @@ struct VroomChart {
|
|
|
119
122
|
std::vector<unsigned char> vwap_breaks;
|
|
120
123
|
bool vwap_dirty = true;
|
|
121
124
|
|
|
125
|
+
// --- drawings (line annotations) ---------------------------------------
|
|
126
|
+
// Committed two-point lines, anchored in data space so they track the
|
|
127
|
+
// candles on pan/zoom. Drawn on the price pane above candles/overlays.
|
|
128
|
+
std::vector<VroomDrawing> drawings;
|
|
129
|
+
|
|
130
|
+
// Transient in-progress "draft" the drawing tool shows while placing points.
|
|
131
|
+
// draft_a is always drawn (node dot); draft_b is drawn when draft_has_b.
|
|
132
|
+
// draft_guide draws the live guideline A->B; when false only node dots show
|
|
133
|
+
// (the committed segment renders via `drawings`). draft_color/draft_width
|
|
134
|
+
// style the guideline to match the eventual line.
|
|
135
|
+
bool draft_active = false;
|
|
136
|
+
VroomDrawPoint draft_a{};
|
|
137
|
+
bool draft_has_b = false;
|
|
138
|
+
VroomDrawPoint draft_b{};
|
|
139
|
+
bool draft_guide = false;
|
|
140
|
+
uint32_t draft_color = 0xff2962ff;
|
|
141
|
+
float draft_width = 2.f;
|
|
142
|
+
|
|
122
143
|
// --- theme --------------------------------------------------------------
|
|
123
144
|
vroom::Theme theme;
|
|
124
145
|
|
|
@@ -54,6 +54,33 @@ int64_t damp_future_delta(int64_t delta_ms, int64_t cur_future,
|
|
|
54
54
|
return static_cast<int64_t>(static_cast<double>(delta_ms) * resist);
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
+
// Frame the default view: the most recent ~80 candles — a narrower x-window
|
|
58
|
+
// so candles read wider. No-op when there are no candles.
|
|
59
|
+
void apply_default_framing(VroomChart* chart) {
|
|
60
|
+
if (chart->candles.empty()) return;
|
|
61
|
+
constexpr size_t kDefaultVisible = 80;
|
|
62
|
+
const size_t start_idx = chart->candles.size() > kDefaultVisible
|
|
63
|
+
? chart->candles.size() - kDefaultVisible
|
|
64
|
+
: 0;
|
|
65
|
+
chart->visible_start_ms = chart->candles[start_idx].time_ms;
|
|
66
|
+
chart->visible_end_ms = chart->candles.back().time_ms;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// On the first manual-y gesture, adopt the on-screen auto-fit bounds so the
|
|
70
|
+
// gesture continues from exactly what the user sees. No-op once manual.
|
|
71
|
+
void ensure_manual_price_bounds(VroomChart* chart) {
|
|
72
|
+
if (chart->price_bounds_manual) return;
|
|
73
|
+
const auto idx = vroom::visible_indices(
|
|
74
|
+
chart->candles.data(), chart->candles.size(),
|
|
75
|
+
chart->visible_start_ms, chart->visible_end_ms);
|
|
76
|
+
if (idx.end > idx.start) {
|
|
77
|
+
chart->price_bounds = vroom::auto_price_bounds(
|
|
78
|
+
chart->candles.data() + idx.start, idx.end - idx.start);
|
|
79
|
+
} // else: no visible candles — keep whatever bounds we had
|
|
80
|
+
chart->price_bounds_manual = true;
|
|
81
|
+
vroom::labels::recompute_axis_width(*chart);
|
|
82
|
+
}
|
|
83
|
+
|
|
57
84
|
} // namespace
|
|
58
85
|
|
|
59
86
|
// ---- Lifecycle -------------------------------------------------------------
|
|
@@ -85,40 +112,12 @@ extern "C" void vroom_chart_set_candles(VroomChart* chart, const VroomCandle* da
|
|
|
85
112
|
}
|
|
86
113
|
vroom::labels::recompute_axis_width(*chart);
|
|
87
114
|
|
|
88
|
-
// Default the visible window
|
|
89
|
-
//
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
? chart->candles.size() - kDefaultVisible
|
|
95
|
-
: 0;
|
|
96
|
-
chart->visible_start_ms = chart->candles[start_idx].time_ms;
|
|
97
|
-
chart->visible_end_ms = chart->candles.back().time_ms;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
// Snap the price (y-axis) bounds to whatever's visible — but only on the
|
|
101
|
-
// first load. After they're initialized, leave them alone so live data
|
|
102
|
-
// updates (new / updated candles) preserve the user's pan/scale; from then
|
|
103
|
-
// on only zoom / axis-drags / vertical translate change them.
|
|
104
|
-
if (!chart->candles.empty() && !chart->price_bounds_initialized) {
|
|
105
|
-
const auto idx = vroom::visible_indices(
|
|
106
|
-
chart->candles.data(), chart->candles.size(),
|
|
107
|
-
chart->visible_start_ms, chart->visible_end_ms);
|
|
108
|
-
if (idx.end > idx.start) {
|
|
109
|
-
auto b = vroom::price_bounds(
|
|
110
|
-
chart->candles.data() + idx.start, idx.end - idx.start);
|
|
111
|
-
// Widen the default y-window beyond the data's min/max so candles
|
|
112
|
-
// fill less vertical space (shorter candles, more headroom). 1.0 =
|
|
113
|
-
// snug; larger = wider. Only the default — zoom/axis-drag override.
|
|
114
|
-
constexpr double kDefaultYZoom = 1.5;
|
|
115
|
-
const double mid = (b.min + b.max) * 0.5;
|
|
116
|
-
const double half = (b.max - b.min) * 0.5 * kDefaultYZoom;
|
|
117
|
-
b.min = mid - half;
|
|
118
|
-
b.max = mid + half;
|
|
119
|
-
chart->price_bounds = b;
|
|
120
|
-
chart->price_bounds_initialized = true;
|
|
121
|
-
}
|
|
115
|
+
// Default the visible window when the consumer hasn't set one. The y-axis
|
|
116
|
+
// needs no equivalent: while the price scale is in auto mode the draw path
|
|
117
|
+
// fits it to the visible candles every frame, and once the user has taken
|
|
118
|
+
// it manual, live data updates must not disturb their pan/scale.
|
|
119
|
+
if (chart->visible_start_ms == 0 && chart->visible_end_ms == 0) {
|
|
120
|
+
apply_default_framing(chart);
|
|
122
121
|
}
|
|
123
122
|
|
|
124
123
|
chart->mark_dirty();
|
|
@@ -168,6 +167,35 @@ extern "C" void vroom_chart_set_visible_range(VroomChart* chart, int64_t start_m
|
|
|
168
167
|
chart->mark_dirty();
|
|
169
168
|
}
|
|
170
169
|
|
|
170
|
+
extern "C" void vroom_chart_get_visible_range(VroomChart* chart,
|
|
171
|
+
int64_t* out_start_ms,
|
|
172
|
+
int64_t* out_end_ms) {
|
|
173
|
+
if (!chart) return;
|
|
174
|
+
if (out_start_ms) *out_start_ms = chart->visible_start_ms;
|
|
175
|
+
if (out_end_ms) *out_end_ms = chart->visible_end_ms;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
extern "C" void vroom_chart_reset_view(VroomChart* chart) {
|
|
179
|
+
if (!chart) return;
|
|
180
|
+
chart->visible_start_ms = 0;
|
|
181
|
+
chart->visible_end_ms = 0;
|
|
182
|
+
chart->price_bounds_manual = false;
|
|
183
|
+
apply_default_framing(chart);
|
|
184
|
+
vroom::labels::recompute_axis_width(*chart);
|
|
185
|
+
if (chart->cb.on_viewport_changed) {
|
|
186
|
+
chart->cb.on_viewport_changed(chart->user_ctx, chart->visible_start_ms,
|
|
187
|
+
chart->visible_end_ms);
|
|
188
|
+
}
|
|
189
|
+
chart->mark_dirty();
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
extern "C" void vroom_chart_reset_price_scale(VroomChart* chart) {
|
|
193
|
+
if (!chart || !chart->price_bounds_manual) return;
|
|
194
|
+
chart->price_bounds_manual = false;
|
|
195
|
+
vroom::labels::recompute_axis_width(*chart);
|
|
196
|
+
chart->mark_dirty();
|
|
197
|
+
}
|
|
198
|
+
|
|
171
199
|
extern "C" void vroom_chart_pan(VroomChart* chart, float dx_px, float /*dy_px*/) {
|
|
172
200
|
if (!chart || dx_px == 0.f || chart->candles.empty()) return;
|
|
173
201
|
|
|
@@ -269,7 +297,8 @@ extern "C" void vroom_chart_translate(VroomChart* chart, float dx_px, float dy_p
|
|
|
269
297
|
// Vertical: shift price bounds by the price-equivalent of dy_px. Range
|
|
270
298
|
// stays constant. We divide by draw_h (the 90% slice of candle area
|
|
271
299
|
// that's actually used for price → y) so translation feels 1:1.
|
|
272
|
-
if (dy_px != 0.f && chart->
|
|
300
|
+
if (dy_px != 0.f && !chart->candles.empty()) {
|
|
301
|
+
ensure_manual_price_bounds(chart);
|
|
273
302
|
const float candle_area_h = vroom::price_pane_bottom(chart->layout());
|
|
274
303
|
const double draw_h = static_cast<double>(candle_area_h) * 0.9;
|
|
275
304
|
if (draw_h > 0.0) {
|
|
@@ -296,7 +325,7 @@ extern "C" void vroom_chart_translate(VroomChart* chart, float dx_px, float dy_p
|
|
|
296
325
|
|
|
297
326
|
extern "C" void vroom_chart_scale_price_axis(VroomChart* chart, float dy_px) {
|
|
298
327
|
if (!chart || dy_px == 0.f) return;
|
|
299
|
-
|
|
328
|
+
ensure_manual_price_bounds(chart);
|
|
300
329
|
|
|
301
330
|
const double range = chart->price_bounds.max - chart->price_bounds.min;
|
|
302
331
|
if (range <= 0.0) return;
|
|
@@ -417,7 +446,7 @@ extern "C" void vroom_chart_resize_indicator_pane(VroomChart* chart, float dy_px
|
|
|
417
446
|
// Preserve candle pixel scale: scale the price range by the price-pane
|
|
418
447
|
// height ratio, anchoring the top (max) price so existing candles stay put
|
|
419
448
|
// and the newly revealed space opens at the bottom.
|
|
420
|
-
if (chart->
|
|
449
|
+
if (chart->price_bounds_manual && old_pane_bottom > 0.f) {
|
|
421
450
|
const float new_pane_bottom = content_h - new_band;
|
|
422
451
|
const double scale = static_cast<double>(new_pane_bottom) /
|
|
423
452
|
static_cast<double>(old_pane_bottom);
|
|
@@ -502,7 +531,8 @@ extern "C" void vroom_chart_zoom(VroomChart* chart, float scale_x, float scale_y
|
|
|
502
531
|
|
|
503
532
|
// --- Y (price) zoom around fy ------------------------------------------
|
|
504
533
|
// scale_y > 1 (vertical pinch out) narrows the price range → taller candles.
|
|
505
|
-
if (scale_y > 0.f && scale_y != 1.f && chart->
|
|
534
|
+
if (scale_y > 0.f && scale_y != 1.f && !chart->candles.empty()) {
|
|
535
|
+
ensure_manual_price_bounds(chart);
|
|
506
536
|
const float candle_area_h = vroom::price_pane_bottom(chart->layout());
|
|
507
537
|
const double range = chart->price_bounds.max - chart->price_bounds.min;
|
|
508
538
|
if (candle_area_h > 0.f && range > 0.0) {
|
|
@@ -647,6 +677,60 @@ extern "C" bool vroom_chart_get_crosshair_info(VroomChart* chart,
|
|
|
647
677
|
return true;
|
|
648
678
|
}
|
|
649
679
|
|
|
680
|
+
// ---- Drawings (line annotations) ------------------------------------------
|
|
681
|
+
|
|
682
|
+
extern "C" void vroom_chart_set_drawings(VroomChart* chart,
|
|
683
|
+
const VroomDrawing* drawings,
|
|
684
|
+
size_t count) {
|
|
685
|
+
if (!chart) return;
|
|
686
|
+
chart->drawings.assign(drawings, drawings + count);
|
|
687
|
+
chart->mark_dirty();
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
extern "C" void vroom_chart_set_draft(VroomChart* chart, int64_t a_time,
|
|
691
|
+
double a_price, bool has_b, int64_t b_time,
|
|
692
|
+
double b_price, bool guide, uint32_t color,
|
|
693
|
+
float width) {
|
|
694
|
+
if (!chart) return;
|
|
695
|
+
chart->draft_active = true;
|
|
696
|
+
chart->draft_a = VroomDrawPoint{a_time, a_price};
|
|
697
|
+
chart->draft_has_b = has_b;
|
|
698
|
+
chart->draft_b = VroomDrawPoint{b_time, b_price};
|
|
699
|
+
chart->draft_guide = guide;
|
|
700
|
+
chart->draft_color = color;
|
|
701
|
+
chart->draft_width = width;
|
|
702
|
+
chart->mark_dirty();
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
extern "C" void vroom_chart_clear_draft(VroomChart* chart) {
|
|
706
|
+
if (!chart) return;
|
|
707
|
+
if (!chart->draft_active) return;
|
|
708
|
+
chart->draft_active = false;
|
|
709
|
+
chart->mark_dirty();
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
extern "C" bool vroom_chart_coord_at(VroomChart* chart, float x_px, float y_px,
|
|
713
|
+
VroomCoord* out) {
|
|
714
|
+
if (!chart || !out || chart->candles.empty()) return false;
|
|
715
|
+
const int64_t window_ms = chart->visible_end_ms - chart->visible_start_ms;
|
|
716
|
+
if (window_ms <= 0) return false;
|
|
717
|
+
const auto lay = chart->layout();
|
|
718
|
+
// Mirror draw_chart's bounds: the frozen manual scale, else the auto-fit
|
|
719
|
+
// over the visible slice — so y_to_price matches what's on screen.
|
|
720
|
+
const auto range = vroom::visible_indices(
|
|
721
|
+
chart->candles.data(), chart->candles.size(),
|
|
722
|
+
chart->visible_start_ms, chart->visible_end_ms);
|
|
723
|
+
const size_t n = range.end - range.start;
|
|
724
|
+
const auto bounds =
|
|
725
|
+
chart->price_bounds_manual
|
|
726
|
+
? chart->price_bounds
|
|
727
|
+
: vroom::auto_price_bounds(chart->candles.data() + range.start, n);
|
|
728
|
+
out->time_ms =
|
|
729
|
+
vroom::time_at_x(lay, chart->visible_start_ms, window_ms, x_px);
|
|
730
|
+
out->price = vroom::y_to_price(lay, bounds, y_px);
|
|
731
|
+
return true;
|
|
732
|
+
}
|
|
733
|
+
|
|
650
734
|
// ---- Indicators -----------------------------------------------------------
|
|
651
735
|
|
|
652
736
|
extern "C" void vroom_chart_set_rsi(VroomChart* chart, bool enabled, int period,
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
#include "drawings.h"
|
|
2
|
+
|
|
3
|
+
#pragma clang diagnostic push
|
|
4
|
+
#pragma clang diagnostic ignored "-Wdocumentation"
|
|
5
|
+
#include "include/core/SkCanvas.h"
|
|
6
|
+
#include "include/core/SkColor.h"
|
|
7
|
+
#include "include/core/SkPaint.h"
|
|
8
|
+
#include "include/core/SkPoint.h"
|
|
9
|
+
#include "include/core/SkRect.h"
|
|
10
|
+
#pragma clang diagnostic pop
|
|
11
|
+
|
|
12
|
+
#include "chart.h"
|
|
13
|
+
|
|
14
|
+
namespace vroom::drawings {
|
|
15
|
+
|
|
16
|
+
namespace {
|
|
17
|
+
// Node-dot styling (fixed for v1, not themed): a 4px black dot with a 2px blue
|
|
18
|
+
// ring around it. kNodeFillRadius is the black core; the blue stroke is centered
|
|
19
|
+
// at kNodeRingRadius so it sits just outside the core.
|
|
20
|
+
constexpr SkColor kNodeFill = 0xff000000; // black core
|
|
21
|
+
constexpr SkColor kNodeBorder = 0xff2962ff; // blue ring
|
|
22
|
+
constexpr float kNodeFillRadius = 2.f; // 4px diameter
|
|
23
|
+
constexpr float kNodeBorderWidth = 2.f;
|
|
24
|
+
constexpr float kNodeRingRadius = 3.f; // ring centered outside the core
|
|
25
|
+
|
|
26
|
+
// Maps a data-space point to pixels in the price pane.
|
|
27
|
+
SkPoint to_px(const VroomChart& chart, const Layout& lay, const PriceBounds& bounds,
|
|
28
|
+
int64_t window_ms, const VroomDrawPoint& p) {
|
|
29
|
+
const float x = vroom::x_at_time(lay, chart.visible_start_ms, window_ms, p.time_ms);
|
|
30
|
+
const float y = vroom::price_to_y(lay, bounds, p.price);
|
|
31
|
+
return SkPoint{x, y};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
void draw_node(SkCanvas* canvas, SkPoint pt) {
|
|
35
|
+
SkPaint fill;
|
|
36
|
+
fill.setAntiAlias(true);
|
|
37
|
+
fill.setColor(kNodeFill);
|
|
38
|
+
canvas->drawCircle(pt.fX, pt.fY, kNodeFillRadius, fill);
|
|
39
|
+
|
|
40
|
+
SkPaint border;
|
|
41
|
+
border.setAntiAlias(true);
|
|
42
|
+
border.setColor(kNodeBorder);
|
|
43
|
+
border.setStyle(SkPaint::kStroke_Style);
|
|
44
|
+
border.setStrokeWidth(kNodeBorderWidth);
|
|
45
|
+
canvas->drawCircle(pt.fX, pt.fY, kNodeRingRadius, border);
|
|
46
|
+
}
|
|
47
|
+
} // namespace
|
|
48
|
+
|
|
49
|
+
void draw(SkCanvas* canvas,
|
|
50
|
+
const VroomChart& chart,
|
|
51
|
+
const Layout& lay,
|
|
52
|
+
const PriceBounds& bounds,
|
|
53
|
+
float candle_right,
|
|
54
|
+
float candle_area_h) {
|
|
55
|
+
if (!canvas || candle_right <= 0.f || candle_area_h <= 0.f) return;
|
|
56
|
+
const int64_t window_ms = chart.visible_end_ms - chart.visible_start_ms;
|
|
57
|
+
if (window_ms <= 0) return;
|
|
58
|
+
|
|
59
|
+
const SkRect clip = SkRect::MakeLTRB(0.f, 0.f, candle_right, candle_area_h);
|
|
60
|
+
|
|
61
|
+
// 1. Committed line segments, clipped to the candle area.
|
|
62
|
+
if (!chart.drawings.empty()) {
|
|
63
|
+
canvas->save();
|
|
64
|
+
canvas->clipRect(clip);
|
|
65
|
+
for (const VroomDrawing& d : chart.drawings) {
|
|
66
|
+
const SkPoint a = to_px(chart, lay, bounds, window_ms, d.a);
|
|
67
|
+
const SkPoint b = to_px(chart, lay, bounds, window_ms, d.b);
|
|
68
|
+
SkPaint line;
|
|
69
|
+
line.setAntiAlias(true);
|
|
70
|
+
line.setColor(static_cast<SkColor>(d.color));
|
|
71
|
+
line.setStyle(SkPaint::kStroke_Style);
|
|
72
|
+
line.setStrokeWidth(d.width > 0.f ? d.width : 2.f);
|
|
73
|
+
canvas->drawLine(a, b, line);
|
|
74
|
+
}
|
|
75
|
+
canvas->restore();
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (!chart.draft_active) return;
|
|
79
|
+
|
|
80
|
+
const SkPoint a = to_px(chart, lay, bounds, window_ms, chart.draft_a);
|
|
81
|
+
const bool has_b = chart.draft_has_b;
|
|
82
|
+
const SkPoint b =
|
|
83
|
+
has_b ? to_px(chart, lay, bounds, window_ms, chart.draft_b) : a;
|
|
84
|
+
|
|
85
|
+
// 2. Guideline preview (A->B), clipped to the candle area. Only while the
|
|
86
|
+
// second point is still being placed (draft_guide); once committed, the
|
|
87
|
+
// solid segment comes from chart.drawings instead.
|
|
88
|
+
if (chart.draft_guide && has_b) {
|
|
89
|
+
canvas->save();
|
|
90
|
+
canvas->clipRect(clip);
|
|
91
|
+
SkPaint guide;
|
|
92
|
+
guide.setAntiAlias(true);
|
|
93
|
+
guide.setColor(static_cast<SkColor>(chart.draft_color));
|
|
94
|
+
guide.setStyle(SkPaint::kStroke_Style);
|
|
95
|
+
guide.setStrokeWidth(chart.draft_width > 0.f ? chart.draft_width : 2.f);
|
|
96
|
+
canvas->drawLine(a, b, guide);
|
|
97
|
+
canvas->restore();
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// 3. Node dots on top (not clipped, so an edge dot still renders fully).
|
|
101
|
+
// While guiding (placing the second point) only the anchor dot shows; the
|
|
102
|
+
// moving end is conveyed by the guideline. Once selected (committed) both
|
|
103
|
+
// endpoints show dots.
|
|
104
|
+
draw_node(canvas, a);
|
|
105
|
+
if (has_b && !chart.draft_guide) draw_node(canvas, b);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
} // namespace vroom::drawings
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// Drawing annotations — user-placed line tools rendered on the price pane.
|
|
2
|
+
//
|
|
3
|
+
// Two kinds of geometry are drawn here:
|
|
4
|
+
// * Committed lines (chart.drawings) — two-point trendlines anchored in data
|
|
5
|
+
// space, so they stay glued to the candles as the user pans/zooms.
|
|
6
|
+
// * The transient "draft" (chart.draft_*) — the in-progress node dots and the
|
|
7
|
+
// live guideline shown while the user is placing a line.
|
|
8
|
+
//
|
|
9
|
+
// Like ma_overlay / crosshair this is its own module so the chart orchestrator
|
|
10
|
+
// stays thin. Drawn after the overlays and before the axis backgrounds.
|
|
11
|
+
|
|
12
|
+
#pragma once
|
|
13
|
+
|
|
14
|
+
#include "viewport.h"
|
|
15
|
+
#include "vroom/vroom_chart.h"
|
|
16
|
+
|
|
17
|
+
class SkCanvas;
|
|
18
|
+
struct VroomChart;
|
|
19
|
+
|
|
20
|
+
namespace vroom::drawings {
|
|
21
|
+
|
|
22
|
+
// Draws the committed line drawings and the in-progress draft. `candle_right` is
|
|
23
|
+
// the x of the y-axis strip and `candle_area_h` the price-pane bottom; geometry
|
|
24
|
+
// is clipped to that rectangle so lines never bleed into the axis strips or the
|
|
25
|
+
// indicator panes below. Node dots are exempt from the clip so a dot placed at
|
|
26
|
+
// the very edge still renders fully.
|
|
27
|
+
void draw(SkCanvas* canvas,
|
|
28
|
+
const VroomChart& chart,
|
|
29
|
+
const vroom::Layout& lay,
|
|
30
|
+
const vroom::PriceBounds& bounds,
|
|
31
|
+
float candle_right,
|
|
32
|
+
float candle_area_h);
|
|
33
|
+
|
|
34
|
+
} // namespace vroom::drawings
|
package/cpp/_core_src/labels.cpp
CHANGED
|
@@ -318,7 +318,7 @@ void recompute_axis_width(VroomChart& chart) {
|
|
|
318
318
|
return;
|
|
319
319
|
}
|
|
320
320
|
double hi, lo;
|
|
321
|
-
if (chart.
|
|
321
|
+
if (chart.price_bounds_manual) {
|
|
322
322
|
hi = chart.price_bounds.max;
|
|
323
323
|
lo = chart.price_bounds.min;
|
|
324
324
|
} else if (!chart.candles.empty()) {
|
|
@@ -35,6 +35,31 @@ float candle_center_x(const Layout& layout,
|
|
|
35
35
|
return static_cast<float>(static_cast<double>(usable) * frac);
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
int64_t time_at_x(const Layout& layout,
|
|
39
|
+
int64_t visible_start_ms,
|
|
40
|
+
int64_t window_ms,
|
|
41
|
+
float x_px) {
|
|
42
|
+
const float usable =
|
|
43
|
+
layout.width_px - layout.y_axis_width_px - layout.right_padding_px;
|
|
44
|
+
if (usable <= 0.f || window_ms <= 0) return visible_start_ms;
|
|
45
|
+
const double frac = static_cast<double>(x_px) / static_cast<double>(usable);
|
|
46
|
+
return visible_start_ms +
|
|
47
|
+
static_cast<int64_t>(std::llround(frac * static_cast<double>(window_ms)));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
float x_at_time(const Layout& layout,
|
|
51
|
+
int64_t visible_start_ms,
|
|
52
|
+
int64_t window_ms,
|
|
53
|
+
int64_t time_ms) {
|
|
54
|
+
if (window_ms <= 0) return 0.f;
|
|
55
|
+
const float usable =
|
|
56
|
+
layout.width_px - layout.y_axis_width_px - layout.right_padding_px;
|
|
57
|
+
const double frac =
|
|
58
|
+
static_cast<double>(time_ms - visible_start_ms) /
|
|
59
|
+
static_cast<double>(window_ms);
|
|
60
|
+
return static_cast<float>(static_cast<double>(usable) * frac);
|
|
61
|
+
}
|
|
62
|
+
|
|
38
63
|
size_t snap_index_to_candle(const Layout& layout,
|
|
39
64
|
const ::VroomCandle* candles,
|
|
40
65
|
size_t count,
|
|
@@ -180,6 +205,14 @@ PriceBounds price_bounds(const ::VroomCandle* candles, size_t count) {
|
|
|
180
205
|
return b;
|
|
181
206
|
}
|
|
182
207
|
|
|
208
|
+
PriceBounds auto_price_bounds(const ::VroomCandle* candles, size_t count) {
|
|
209
|
+
PriceBounds b = price_bounds(candles, count);
|
|
210
|
+
if (count == 0) return b;
|
|
211
|
+
const double mid = (b.min + b.max) * 0.5;
|
|
212
|
+
const double half = (b.max - b.min) * 0.5 * kAutoYZoom;
|
|
213
|
+
return {mid - half, mid + half};
|
|
214
|
+
}
|
|
215
|
+
|
|
183
216
|
float price_to_y(const Layout& layout,
|
|
184
217
|
const PriceBounds& bounds,
|
|
185
218
|
double price) {
|
package/cpp/_core_src/viewport.h
CHANGED
|
@@ -113,9 +113,33 @@ float snap_x_to_candle(const Layout& layout,
|
|
|
113
113
|
int64_t window_ms,
|
|
114
114
|
float x_px);
|
|
115
115
|
|
|
116
|
+
// Free (non-snapped, non-candle-centered) mapping between time and pixel x,
|
|
117
|
+
// used for drawing-tool endpoints that can sit anywhere — not just on a candle
|
|
118
|
+
// slot. `x_at_time` is the exact inverse of `time_at_x`:
|
|
119
|
+
// frac = (time - start) / window; x = usable * frac
|
|
120
|
+
// where `usable` is the candle area width (width - y-axis - right padding).
|
|
121
|
+
// Returns 0 / visible_start_ms respectively for a degenerate window/usable.
|
|
122
|
+
int64_t time_at_x(const Layout& layout,
|
|
123
|
+
int64_t visible_start_ms,
|
|
124
|
+
int64_t window_ms,
|
|
125
|
+
float x_px);
|
|
126
|
+
float x_at_time(const Layout& layout,
|
|
127
|
+
int64_t visible_start_ms,
|
|
128
|
+
int64_t window_ms,
|
|
129
|
+
int64_t time_ms);
|
|
130
|
+
|
|
116
131
|
// Min/max of (low..high) across the given range.
|
|
117
132
|
PriceBounds price_bounds(const ::VroomCandle* candles, size_t count);
|
|
118
133
|
|
|
134
|
+
// Widening applied to auto-fit price bounds so candles keep some headroom
|
|
135
|
+
// instead of touching the pane edges. 1.0 = snug; larger = wider.
|
|
136
|
+
constexpr double kAutoYZoom = 1.5;
|
|
137
|
+
|
|
138
|
+
// price_bounds() widened about its midpoint by kAutoYZoom. This is the y-range
|
|
139
|
+
// used whenever the price scale is in auto (follow-the-data) mode. Returns the
|
|
140
|
+
// {0, 1} sentinel when count == 0 (callers keep their previous bounds).
|
|
141
|
+
PriceBounds auto_price_bounds(const ::VroomCandle* candles, size_t count);
|
|
142
|
+
|
|
119
143
|
// Map a price to y in pixels. y=0 is top of the chart.
|
|
120
144
|
float price_to_y(const Layout& layout, const PriceBounds& bounds, double price);
|
|
121
145
|
|
package/lib/index.d.mts
CHANGED
|
@@ -84,6 +84,38 @@ type VisibleRange = {
|
|
|
84
84
|
/** Window end (inclusive), Unix epoch milliseconds. */
|
|
85
85
|
endMs: number;
|
|
86
86
|
};
|
|
87
|
+
/**
|
|
88
|
+
* Chart interaction mode.
|
|
89
|
+
* 'pan' — default: drag to pan, pinch/wheel to zoom, hover/long-press crosshair.
|
|
90
|
+
* 'draw' — left-clicks place drawing points; panning/zooming are suppressed.
|
|
91
|
+
*/
|
|
92
|
+
type ChartMode = 'pan' | 'draw';
|
|
93
|
+
/** Active drawing tool while in `draw` mode. `null` draws nothing. */
|
|
94
|
+
type DrawTool = null | 'line';
|
|
95
|
+
/** A drawing anchor in data space, so it stays glued to the candles on pan/zoom. */
|
|
96
|
+
type DrawPoint = {
|
|
97
|
+
/** Anchor time as Unix epoch milliseconds (not snapped to a candle slot). */
|
|
98
|
+
timeMs: number;
|
|
99
|
+
/** Anchor price. */
|
|
100
|
+
price: number;
|
|
101
|
+
};
|
|
102
|
+
/**
|
|
103
|
+
* A committed drawing. Pass an array of these via the `drawings` prop to render
|
|
104
|
+
* persisted annotations; the chart appends a new one (via `onDrawingComplete`)
|
|
105
|
+
* each time the user finishes drawing. For now only the `'line'` (two-point
|
|
106
|
+
* trendline) type exists.
|
|
107
|
+
*/
|
|
108
|
+
type Drawing = {
|
|
109
|
+
/** Stable unique id (the chart generates one for drawings it creates). */
|
|
110
|
+
id: string;
|
|
111
|
+
type: 'line';
|
|
112
|
+
/** The two endpoints, in data space. */
|
|
113
|
+
points: [DrawPoint, DrawPoint];
|
|
114
|
+
/** Line color (hex string or packed ARGB number). Default solid blue. */
|
|
115
|
+
color?: VroomColor;
|
|
116
|
+
/** Stroke width in px. Default 2. */
|
|
117
|
+
width?: number;
|
|
118
|
+
};
|
|
87
119
|
/** RSI indicator config. Rendered in a pane below the candles when enabled. */
|
|
88
120
|
type RSIConfig = {
|
|
89
121
|
enabled?: boolean;
|
|
@@ -147,6 +179,14 @@ type MACDConfig = {
|
|
|
147
179
|
type VroomChartCoreProps = {
|
|
148
180
|
/** OHLCV bars to render. The only required prop. */
|
|
149
181
|
candles: Candle[];
|
|
182
|
+
/**
|
|
183
|
+
* Identity of the data series (e.g. "BTC-USD"). When it changes between
|
|
184
|
+
* renders the chart resets to the default view (most recent candles + price
|
|
185
|
+
* auto-fit), regardless of what the data heuristics conclude — the escape
|
|
186
|
+
* hatch for ambiguous switches like two assets trading at similar prices.
|
|
187
|
+
* Omit to rely on automatic detection from the candle data alone.
|
|
188
|
+
*/
|
|
189
|
+
seriesKey?: string;
|
|
150
190
|
/**
|
|
151
191
|
* Explicit size overrides in logical px. When omitted, the chart fills its
|
|
152
192
|
* parent (measured at runtime). Prefer layout-driven sizing via the
|
|
@@ -171,6 +211,27 @@ type VroomChartCoreProps = {
|
|
|
171
211
|
* touch x. Default 40.
|
|
172
212
|
*/
|
|
173
213
|
crosshairOffset?: number;
|
|
214
|
+
/**
|
|
215
|
+
* Interaction mode. Default `'pan'`. Set to `'draw'` (with a `tool`) to let
|
|
216
|
+
* the user place drawing points; panning/zooming are suppressed while drawing.
|
|
217
|
+
*/
|
|
218
|
+
mode?: ChartMode;
|
|
219
|
+
/** Active drawing tool while in `draw` mode. Default `null` (draws nothing). */
|
|
220
|
+
tool?: DrawTool;
|
|
221
|
+
/**
|
|
222
|
+
* Committed drawings to render, anchored to data so they track the candles on
|
|
223
|
+
* pan/zoom. This is a controlled prop: append the value the chart hands you in
|
|
224
|
+
* `onDrawingComplete` to persist it.
|
|
225
|
+
*/
|
|
226
|
+
drawings?: Drawing[];
|
|
227
|
+
/** Fired with the finished drawing when the user completes one. */
|
|
228
|
+
onDrawingComplete?: (drawing: Drawing) => void;
|
|
229
|
+
/**
|
|
230
|
+
* Fired when the chart wants the mode changed — e.g. it requests `'pan'` after
|
|
231
|
+
* the user clicks away from a just-drawn line. Since `mode` is controlled, the
|
|
232
|
+
* host should apply the requested mode.
|
|
233
|
+
*/
|
|
234
|
+
onModeChange?: (mode: ChartMode) => void;
|
|
174
235
|
onCrosshair?: (e: CrosshairEvent) => void;
|
|
175
236
|
onViewportChange?: (startMs: number, endMs: number) => void;
|
|
176
237
|
};
|
package/lib/index.d.ts
CHANGED
|
@@ -84,6 +84,38 @@ type VisibleRange = {
|
|
|
84
84
|
/** Window end (inclusive), Unix epoch milliseconds. */
|
|
85
85
|
endMs: number;
|
|
86
86
|
};
|
|
87
|
+
/**
|
|
88
|
+
* Chart interaction mode.
|
|
89
|
+
* 'pan' — default: drag to pan, pinch/wheel to zoom, hover/long-press crosshair.
|
|
90
|
+
* 'draw' — left-clicks place drawing points; panning/zooming are suppressed.
|
|
91
|
+
*/
|
|
92
|
+
type ChartMode = 'pan' | 'draw';
|
|
93
|
+
/** Active drawing tool while in `draw` mode. `null` draws nothing. */
|
|
94
|
+
type DrawTool = null | 'line';
|
|
95
|
+
/** A drawing anchor in data space, so it stays glued to the candles on pan/zoom. */
|
|
96
|
+
type DrawPoint = {
|
|
97
|
+
/** Anchor time as Unix epoch milliseconds (not snapped to a candle slot). */
|
|
98
|
+
timeMs: number;
|
|
99
|
+
/** Anchor price. */
|
|
100
|
+
price: number;
|
|
101
|
+
};
|
|
102
|
+
/**
|
|
103
|
+
* A committed drawing. Pass an array of these via the `drawings` prop to render
|
|
104
|
+
* persisted annotations; the chart appends a new one (via `onDrawingComplete`)
|
|
105
|
+
* each time the user finishes drawing. For now only the `'line'` (two-point
|
|
106
|
+
* trendline) type exists.
|
|
107
|
+
*/
|
|
108
|
+
type Drawing = {
|
|
109
|
+
/** Stable unique id (the chart generates one for drawings it creates). */
|
|
110
|
+
id: string;
|
|
111
|
+
type: 'line';
|
|
112
|
+
/** The two endpoints, in data space. */
|
|
113
|
+
points: [DrawPoint, DrawPoint];
|
|
114
|
+
/** Line color (hex string or packed ARGB number). Default solid blue. */
|
|
115
|
+
color?: VroomColor;
|
|
116
|
+
/** Stroke width in px. Default 2. */
|
|
117
|
+
width?: number;
|
|
118
|
+
};
|
|
87
119
|
/** RSI indicator config. Rendered in a pane below the candles when enabled. */
|
|
88
120
|
type RSIConfig = {
|
|
89
121
|
enabled?: boolean;
|
|
@@ -147,6 +179,14 @@ type MACDConfig = {
|
|
|
147
179
|
type VroomChartCoreProps = {
|
|
148
180
|
/** OHLCV bars to render. The only required prop. */
|
|
149
181
|
candles: Candle[];
|
|
182
|
+
/**
|
|
183
|
+
* Identity of the data series (e.g. "BTC-USD"). When it changes between
|
|
184
|
+
* renders the chart resets to the default view (most recent candles + price
|
|
185
|
+
* auto-fit), regardless of what the data heuristics conclude — the escape
|
|
186
|
+
* hatch for ambiguous switches like two assets trading at similar prices.
|
|
187
|
+
* Omit to rely on automatic detection from the candle data alone.
|
|
188
|
+
*/
|
|
189
|
+
seriesKey?: string;
|
|
150
190
|
/**
|
|
151
191
|
* Explicit size overrides in logical px. When omitted, the chart fills its
|
|
152
192
|
* parent (measured at runtime). Prefer layout-driven sizing via the
|
|
@@ -171,6 +211,27 @@ type VroomChartCoreProps = {
|
|
|
171
211
|
* touch x. Default 40.
|
|
172
212
|
*/
|
|
173
213
|
crosshairOffset?: number;
|
|
214
|
+
/**
|
|
215
|
+
* Interaction mode. Default `'pan'`. Set to `'draw'` (with a `tool`) to let
|
|
216
|
+
* the user place drawing points; panning/zooming are suppressed while drawing.
|
|
217
|
+
*/
|
|
218
|
+
mode?: ChartMode;
|
|
219
|
+
/** Active drawing tool while in `draw` mode. Default `null` (draws nothing). */
|
|
220
|
+
tool?: DrawTool;
|
|
221
|
+
/**
|
|
222
|
+
* Committed drawings to render, anchored to data so they track the candles on
|
|
223
|
+
* pan/zoom. This is a controlled prop: append the value the chart hands you in
|
|
224
|
+
* `onDrawingComplete` to persist it.
|
|
225
|
+
*/
|
|
226
|
+
drawings?: Drawing[];
|
|
227
|
+
/** Fired with the finished drawing when the user completes one. */
|
|
228
|
+
onDrawingComplete?: (drawing: Drawing) => void;
|
|
229
|
+
/**
|
|
230
|
+
* Fired when the chart wants the mode changed — e.g. it requests `'pan'` after
|
|
231
|
+
* the user clicks away from a just-drawn line. Since `mode` is controlled, the
|
|
232
|
+
* host should apply the requested mode.
|
|
233
|
+
*/
|
|
234
|
+
onModeChange?: (mode: ChartMode) => void;
|
|
174
235
|
onCrosshair?: (e: CrosshairEvent) => void;
|
|
175
236
|
onViewportChange?: (startMs: number, endMs: number) => void;
|
|
176
237
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-vroom-chart",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "Mobile-first Skia candlestick chart for React Native",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Darion Welch",
|
|
@@ -36,6 +36,13 @@
|
|
|
36
36
|
"!**/*.test.ts",
|
|
37
37
|
"!**/.*"
|
|
38
38
|
],
|
|
39
|
+
"scripts": {
|
|
40
|
+
"typecheck": "tsc --noEmit",
|
|
41
|
+
"test": "vitest run",
|
|
42
|
+
"build": "tsup",
|
|
43
|
+
"vendor:core": "node scripts/vendor-core.mjs",
|
|
44
|
+
"prepack": "node scripts/vendor-core.mjs && tsup"
|
|
45
|
+
},
|
|
39
46
|
"codegenConfig": {
|
|
40
47
|
"name": "VroomChartSpec",
|
|
41
48
|
"type": "modules",
|
|
@@ -56,6 +63,7 @@
|
|
|
56
63
|
},
|
|
57
64
|
"devDependencies": {
|
|
58
65
|
"@types/react": "~19.1.0",
|
|
66
|
+
"@vroomchart/types": "workspace:*",
|
|
59
67
|
"react": "19.1.0",
|
|
60
68
|
"react-native": "0.81.5",
|
|
61
69
|
"typescript": "~5.9.2",
|
|
@@ -63,13 +71,6 @@
|
|
|
63
71
|
"react-native-gesture-handler": "~2.28.0",
|
|
64
72
|
"react-native-reanimated": "~4.1.1",
|
|
65
73
|
"tsup": "^8.5.1",
|
|
66
|
-
"vitest": "^2.1.9"
|
|
67
|
-
"@vroomchart/types": "0.0.1"
|
|
68
|
-
},
|
|
69
|
-
"scripts": {
|
|
70
|
-
"typecheck": "tsc --noEmit",
|
|
71
|
-
"test": "vitest run",
|
|
72
|
-
"build": "tsup",
|
|
73
|
-
"vendor:core": "node scripts/vendor-core.mjs"
|
|
74
|
+
"vitest": "^2.1.9"
|
|
74
75
|
}
|
|
75
|
-
}
|
|
76
|
+
}
|
package/LICENSE
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 Darion Welch
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|