react-native-vroom-chart 0.12.0 → 0.13.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.
@@ -2,6 +2,7 @@
2
2
 
3
3
  #include <algorithm>
4
4
  #include <cmath>
5
+ #include <cstddef>
5
6
  #include <cstdio>
6
7
 
7
8
  namespace vroom {
@@ -15,6 +16,38 @@ constexpr size_t kPlainCap = 340;
15
16
  constexpr char kGroupSeparator = ',';
16
17
  constexpr int kGroupSize = 3;
17
18
 
19
+ constexpr double kMillion = 1e6;
20
+ constexpr double kBillion = 1e9;
21
+ constexpr double kTrillion = 1e12;
22
+
23
+ double compact_divisor(CompactScale scale) {
24
+ switch (scale) {
25
+ case CompactScale::Million: return kMillion;
26
+ case CompactScale::Billion: return kBillion;
27
+ case CompactScale::Trillion: return kTrillion;
28
+ case CompactScale::None: return 1.0;
29
+ }
30
+ return 1.0;
31
+ }
32
+
33
+ char compact_suffix(CompactScale scale) {
34
+ switch (scale) {
35
+ case CompactScale::Million: return 'M';
36
+ case CompactScale::Billion: return 'B';
37
+ case CompactScale::Trillion: return 'T';
38
+ case CompactScale::None: return '\0';
39
+ }
40
+ return '\0';
41
+ }
42
+
43
+ CompactScale compact_scale_for(double reference) {
44
+ const double r = std::fabs(reference);
45
+ if (!std::isfinite(r) || r < kMillion) return CompactScale::None;
46
+ if (r >= kTrillion) return CompactScale::Trillion;
47
+ if (r >= kBillion) return CompactScale::Billion;
48
+ return CompactScale::Million;
49
+ }
50
+
18
51
  } // namespace
19
52
 
20
53
  int significant_decimals(double reference) {
@@ -28,7 +61,8 @@ int significant_decimals(double reference) {
28
61
  }
29
62
 
30
63
  PriceFormat price_format_for(double reference) {
31
- return PriceFormat{significant_decimals(reference), true};
64
+ return PriceFormat{significant_decimals(reference), true,
65
+ compact_scale_for(reference)};
32
66
  }
33
67
 
34
68
  int price_decimals(double interval) {
@@ -40,8 +74,13 @@ int price_decimals(double interval) {
40
74
  }
41
75
 
42
76
  PriceFormat with_tick_guard(const PriceFormat& fmt, double interval) {
43
- return PriceFormat{std::max(fmt.decimals, price_decimals(interval)),
44
- fmt.group};
77
+ const double divisor = compact_divisor(fmt.compact);
78
+ const double display_interval =
79
+ (divisor != 1.0 && interval > 0.0 && std::isfinite(interval))
80
+ ? interval / divisor
81
+ : interval;
82
+ return PriceFormat{std::max(fmt.decimals, price_decimals(display_interval)),
83
+ fmt.group, fmt.compact};
45
84
  }
46
85
 
47
86
  void format_price(char* buf, size_t buf_size, double price,
@@ -49,11 +88,23 @@ void format_price(char* buf, size_t buf_size, double price,
49
88
  if (!buf || buf_size == 0) return;
50
89
  const int decimals = std::clamp(fmt.decimals, 0, kPriceMaxDecimals);
51
90
 
91
+ const double divisor = compact_divisor(fmt.compact);
92
+ const double display = (divisor != 1.0) ? price / divisor : price;
93
+
52
94
  char plain[kPlainCap];
53
- if (std::snprintf(plain, sizeof(plain), "%.*f", decimals, price) < 0) {
95
+ if (std::snprintf(plain, sizeof(plain), "%.*f", decimals, display) < 0) {
54
96
  buf[0] = '\0';
55
97
  return;
56
98
  }
99
+
100
+ const char suffix = compact_suffix(fmt.compact);
101
+ if (suffix != '\0') {
102
+ // Compact form is already short; grouping would only fire if a tick
103
+ // wandered across a suffix boundary (1000.00M). Skip it.
104
+ std::snprintf(buf, buf_size, "%s%c", plain, suffix);
105
+ return;
106
+ }
107
+
57
108
  if (!fmt.group) {
58
109
  std::snprintf(buf, buf_size, "%s", plain);
59
110
  return;
@@ -13,6 +13,16 @@
13
13
  // 0.023397 -> 6 decimals 0.023397
14
14
  // 80285.20 -> 2 decimals 80,285.20 (floor)
15
15
  // 2513.92 -> 2 decimals 2,513.92 (floor)
16
+ // 1.59e6 -> compact 1.59M
17
+ // 3.219e7 -> compact 32.19M
18
+ // 3.454e10 -> compact 34.54B
19
+ // 1.2e12 -> compact 1.20T
20
+ //
21
+ // Past a million the integer digits eat the axis, so the format switches to a
22
+ // suffix (M / B / T) with two decimal places. The suffix is keyed off the
23
+ // asset's own price, not each tick, so every label on a market-cap chart
24
+ // shares a column and a zoomed-in 32.1M–32.2M range does not mix "32.15M"
25
+ // with "32,150,000.00".
16
26
  //
17
27
  // The reference is the asset's own price, not the visible range, so the
18
28
  // precision holds steady while the user pans and zooms. A range-derived count
@@ -32,18 +42,31 @@ namespace vroom {
32
42
  inline constexpr int kPriceSigDigits = 5;
33
43
 
34
44
  // Prices at or above ~1 unit read as currency, where fewer than two decimals
35
- // looks broken (a "$84,000" axis next to a "$80,285.20" last price).
45
+ // looks broken (a "$84,000" axis next to a "$80,285.20" last price). Compact
46
+ // suffixes use the same floor: "32.19M", not "32.2M".
36
47
  inline constexpr int kPriceMinDecimals = 2;
37
48
 
38
49
  // Past this the digits are noise, and %.*f starts printing the binary
39
50
  // representation's tail rather than anything the feed meant.
40
51
  inline constexpr int kPriceMaxDecimals = 12;
41
52
 
53
+ // Compact suffix for assets priced in the millions and up. Keyed off the
54
+ // reference, then applied to every label so the column stays uniform. Nothing
55
+ // below a million is abbreviated — no K.
56
+ enum class CompactScale {
57
+ None,
58
+ Million, // |ref| >= 1e6
59
+ Billion, // |ref| >= 1e9
60
+ Trillion, // |ref| >= 1e12
61
+ };
62
+
42
63
  // How to render a price. `group` inserts thousands separators, which only ever
43
- // affects the integer part.
64
+ // affects the integer part of a non-compact format. `compact` scales the value
65
+ // and appends M / B / T; grouping is skipped in that path.
44
66
  struct PriceFormat {
45
- int decimals = kPriceMinDecimals;
46
- bool group = true;
67
+ int decimals = kPriceMinDecimals;
68
+ bool group = true;
69
+ CompactScale compact = CompactScale::None;
47
70
  };
48
71
 
49
72
  // Decimals giving kPriceSigDigits significant digits for an asset priced around
@@ -51,7 +74,8 @@ struct PriceFormat {
51
74
  // non-finite reference falls back to the floor.
52
75
  int significant_decimals(double reference);
53
76
 
54
- // The format for an asset priced around `reference`.
77
+ // The format for an asset priced around `reference`, including the compact
78
+ // suffix when |reference| is at least a million.
55
79
  PriceFormat price_format_for(double reference);
56
80
 
57
81
  // Decimal places needed so adjacent ticks `interval` apart don't collapse to
@@ -60,6 +84,9 @@ int price_decimals(double interval);
60
84
 
61
85
  // `fmt` raised, if need be, so ticks `interval` apart stay distinct. The asset's
62
86
  // precision is the floor; only a zoom deeper than that precision adds to it.
87
+ // `interval` is in the data's units; when `fmt` is compact the guard converts
88
+ // it into display units (interval / 1e6 for millions, etc.) so a 1,000-wide
89
+ // step on a 32M chart still gets enough decimals to print as 32.192M vs 32.193M.
63
90
  PriceFormat with_tick_guard(const PriceFormat& fmt, double interval);
64
91
 
65
92
  // Writes `price` into `buf` per `fmt`, truncating rather than overrunning.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-vroom-chart",
3
- "version": "0.12.0",
3
+ "version": "0.13.0",
4
4
  "description": "Mobile-first Skia candlestick chart for React Native",
5
5
  "license": "MIT",
6
6
  "author": "Darion Welch",