@obitrain/charts 0.10.0 → 0.10.2

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 (148) hide show
  1. package/README.md +79 -0
  2. package/lib/commonjs/Charts/BottomAxis/AxisLine.js +5 -5
  3. package/lib/commonjs/Charts/BottomAxis/AxisLine.js.map +1 -1
  4. package/lib/commonjs/Charts/BottomAxis/BottomAxis.js +3 -3
  5. package/lib/commonjs/Charts/BottomAxis/BottomAxis.js.map +1 -1
  6. package/lib/commonjs/Charts/BottomAxis/Tick.js +2 -2
  7. package/lib/commonjs/Charts/BottomAxis/Tick.js.map +1 -1
  8. package/lib/commonjs/Charts/BottomAxis/index.js +3 -3
  9. package/lib/commonjs/Charts/Cursor.js +5 -6
  10. package/lib/commonjs/Charts/Cursor.js.map +1 -1
  11. package/lib/commonjs/Charts/Linechart/index.js +2 -0
  12. package/lib/commonjs/Charts/Linechart/index.js.map +1 -1
  13. package/lib/commonjs/Charts/ZoomableLinechart/ScalablePath.js +4 -11
  14. package/lib/commonjs/Charts/ZoomableLinechart/ScalablePath.js.map +1 -1
  15. package/lib/commonjs/Charts/ZoomableLinechart/index.js +1 -1
  16. package/lib/commonjs/Charts/gesture.js +28 -34
  17. package/lib/commonjs/Charts/gesture.js.map +1 -1
  18. package/lib/commonjs/Charts/graphUtils.js +25 -22
  19. package/lib/commonjs/Charts/graphUtils.js.map +1 -1
  20. package/lib/commonjs/Charts/index.js +13 -13
  21. package/lib/commonjs/Charts/index.js.map +1 -1
  22. package/lib/commonjs/Charts/maths.js.map +1 -1
  23. package/lib/commonjs/dateUtils.js +11 -15
  24. package/lib/commonjs/dateUtils.js.map +1 -1
  25. package/lib/commonjs/index.js +6 -6
  26. package/lib/commonjs/index.js.map +1 -1
  27. package/lib/module/Charts/BottomAxis/AxisLine.js +5 -5
  28. package/lib/module/Charts/BottomAxis/AxisLine.js.map +1 -1
  29. package/lib/module/Charts/BottomAxis/BottomAxis.js +3 -3
  30. package/lib/module/Charts/BottomAxis/BottomAxis.js.map +1 -1
  31. package/lib/module/Charts/BottomAxis/Tick.js +2 -2
  32. package/lib/module/Charts/BottomAxis/Tick.js.map +1 -1
  33. package/lib/module/Charts/BottomAxis/index.js +3 -3
  34. package/lib/module/Charts/BottomAxis/index.js.map +1 -1
  35. package/lib/module/Charts/Cursor.js +5 -6
  36. package/lib/module/Charts/Cursor.js.map +1 -1
  37. package/lib/module/Charts/Linechart/index.js +2 -0
  38. package/lib/module/Charts/Linechart/index.js.map +1 -1
  39. package/lib/module/Charts/ZoomableLinechart/ScalablePath.js +4 -11
  40. package/lib/module/Charts/ZoomableLinechart/ScalablePath.js.map +1 -1
  41. package/lib/module/Charts/ZoomableLinechart/index.js +1 -1
  42. package/lib/module/Charts/ZoomableLinechart/index.js.map +1 -1
  43. package/lib/module/Charts/gesture.js +29 -35
  44. package/lib/module/Charts/gesture.js.map +1 -1
  45. package/lib/module/Charts/graphUtils.js +26 -22
  46. package/lib/module/Charts/graphUtils.js.map +1 -1
  47. package/lib/module/Charts/index.js +7 -7
  48. package/lib/module/Charts/index.js.map +1 -1
  49. package/lib/module/Charts/maths.js.map +1 -1
  50. package/lib/module/dateUtils.js +10 -14
  51. package/lib/module/dateUtils.js.map +1 -1
  52. package/lib/module/index.js +3 -3
  53. package/lib/module/index.js.map +1 -1
  54. package/lib/module/package.json +1 -0
  55. package/lib/typescript/commonjs/package.json +1 -0
  56. package/lib/typescript/commonjs/src/Charts/BottomAxis/AxisLine.d.ts.map +1 -0
  57. package/lib/typescript/commonjs/src/Charts/BottomAxis/BottomAxis.d.ts.map +1 -0
  58. package/lib/typescript/commonjs/src/Charts/BottomAxis/Tick.d.ts.map +1 -0
  59. package/lib/typescript/commonjs/src/Charts/BottomAxis/index.d.ts.map +1 -0
  60. package/lib/typescript/{src → commonjs/src}/Charts/Cursor.d.ts +1 -1
  61. package/lib/typescript/commonjs/src/Charts/Cursor.d.ts.map +1 -0
  62. package/lib/typescript/{src → commonjs/src}/Charts/Linechart/index.d.ts +10 -4
  63. package/lib/typescript/commonjs/src/Charts/Linechart/index.d.ts.map +1 -0
  64. package/lib/typescript/commonjs/src/Charts/ZoomableLinechart/ScalablePath.d.ts.map +1 -0
  65. package/lib/typescript/commonjs/src/Charts/ZoomableLinechart/index.d.ts.map +1 -0
  66. package/lib/typescript/commonjs/src/Charts/gesture.d.ts.map +1 -0
  67. package/lib/typescript/{src → commonjs/src}/Charts/graphUtils.d.ts +5 -3
  68. package/lib/typescript/commonjs/src/Charts/graphUtils.d.ts.map +1 -0
  69. package/lib/typescript/{src → commonjs/src}/Charts/index.d.ts +4 -3
  70. package/lib/typescript/commonjs/src/Charts/index.d.ts.map +1 -0
  71. package/lib/typescript/{src → commonjs/src}/Charts/maths.d.ts +1 -2
  72. package/lib/typescript/commonjs/src/Charts/maths.d.ts.map +1 -0
  73. package/lib/typescript/commonjs/src/Charts/types.d.ts.map +1 -0
  74. package/lib/typescript/commonjs/src/dateUtils.d.ts.map +1 -0
  75. package/lib/typescript/commonjs/src/index.d.ts.map +1 -0
  76. package/lib/typescript/commonjs/src/textUtils.d.ts.map +1 -0
  77. package/lib/typescript/module/package.json +1 -0
  78. package/lib/typescript/module/src/Charts/BottomAxis/AxisLine.d.ts +15 -0
  79. package/lib/typescript/module/src/Charts/BottomAxis/AxisLine.d.ts.map +1 -0
  80. package/lib/typescript/module/src/Charts/BottomAxis/BottomAxis.d.ts +17 -0
  81. package/lib/typescript/module/src/Charts/BottomAxis/BottomAxis.d.ts.map +1 -0
  82. package/lib/typescript/module/src/Charts/BottomAxis/Tick.d.ts +14 -0
  83. package/lib/typescript/module/src/Charts/BottomAxis/Tick.d.ts.map +1 -0
  84. package/lib/typescript/module/src/Charts/BottomAxis/index.d.ts +4 -0
  85. package/lib/typescript/module/src/Charts/BottomAxis/index.d.ts.map +1 -0
  86. package/lib/typescript/module/src/Charts/Cursor.d.ts +14 -0
  87. package/lib/typescript/module/src/Charts/Cursor.d.ts.map +1 -0
  88. package/lib/typescript/module/src/Charts/Linechart/index.d.ts +31 -0
  89. package/lib/typescript/module/src/Charts/Linechart/index.d.ts.map +1 -0
  90. package/lib/typescript/module/src/Charts/ZoomableLinechart/ScalablePath.d.ts +14 -0
  91. package/lib/typescript/module/src/Charts/ZoomableLinechart/ScalablePath.d.ts.map +1 -0
  92. package/lib/typescript/module/src/Charts/ZoomableLinechart/index.d.ts +23 -0
  93. package/lib/typescript/module/src/Charts/ZoomableLinechart/index.d.ts.map +1 -0
  94. package/lib/typescript/module/src/Charts/gesture.d.ts +54 -0
  95. package/lib/typescript/module/src/Charts/gesture.d.ts.map +1 -0
  96. package/lib/typescript/module/src/Charts/graphUtils.d.ts +45 -0
  97. package/lib/typescript/module/src/Charts/graphUtils.d.ts.map +1 -0
  98. package/lib/typescript/module/src/Charts/index.d.ts +15 -0
  99. package/lib/typescript/module/src/Charts/index.d.ts.map +1 -0
  100. package/lib/typescript/module/src/Charts/maths.d.ts +18 -0
  101. package/lib/typescript/module/src/Charts/maths.d.ts.map +1 -0
  102. package/lib/typescript/module/src/Charts/types.d.ts +14 -0
  103. package/lib/typescript/module/src/Charts/types.d.ts.map +1 -0
  104. package/lib/typescript/module/src/dateUtils.d.ts +37 -0
  105. package/lib/typescript/module/src/dateUtils.d.ts.map +1 -0
  106. package/lib/typescript/module/src/index.d.ts +5 -0
  107. package/lib/typescript/module/src/index.d.ts.map +1 -0
  108. package/lib/typescript/module/src/textUtils.d.ts +3 -0
  109. package/lib/typescript/module/src/textUtils.d.ts.map +1 -0
  110. package/package.json +53 -41
  111. package/src/Charts/BottomAxis/AxisLine.tsx +4 -4
  112. package/src/Charts/BottomAxis/BottomAxis.tsx +1 -1
  113. package/src/Charts/BottomAxis/Tick.tsx +10 -13
  114. package/src/Charts/Cursor.tsx +15 -16
  115. package/src/Charts/Linechart/index.tsx +8 -4
  116. package/src/Charts/ZoomableLinechart/ScalablePath.tsx +9 -17
  117. package/src/Charts/gesture.ts +40 -39
  118. package/src/Charts/graphUtils.ts +32 -27
  119. package/src/Charts/index.tsx +22 -3
  120. package/src/Charts/maths.ts +5 -3
  121. package/src/dateUtils.ts +9 -16
  122. package/lib/typescript/src/Charts/BottomAxis/AxisLine.d.ts.map +0 -1
  123. package/lib/typescript/src/Charts/BottomAxis/BottomAxis.d.ts.map +0 -1
  124. package/lib/typescript/src/Charts/BottomAxis/Tick.d.ts.map +0 -1
  125. package/lib/typescript/src/Charts/BottomAxis/index.d.ts.map +0 -1
  126. package/lib/typescript/src/Charts/Cursor.d.ts.map +0 -1
  127. package/lib/typescript/src/Charts/Linechart/index.d.ts.map +0 -1
  128. package/lib/typescript/src/Charts/ZoomableLinechart/ScalablePath.d.ts.map +0 -1
  129. package/lib/typescript/src/Charts/ZoomableLinechart/index.d.ts.map +0 -1
  130. package/lib/typescript/src/Charts/gesture.d.ts.map +0 -1
  131. package/lib/typescript/src/Charts/graphUtils.d.ts.map +0 -1
  132. package/lib/typescript/src/Charts/index.d.ts.map +0 -1
  133. package/lib/typescript/src/Charts/maths.d.ts.map +0 -1
  134. package/lib/typescript/src/Charts/types.d.ts.map +0 -1
  135. package/lib/typescript/src/dateUtils.d.ts.map +0 -1
  136. package/lib/typescript/src/index.d.ts.map +0 -1
  137. package/lib/typescript/src/textUtils.d.ts.map +0 -1
  138. /package/lib/typescript/{src → commonjs/src}/Charts/BottomAxis/AxisLine.d.ts +0 -0
  139. /package/lib/typescript/{src → commonjs/src}/Charts/BottomAxis/BottomAxis.d.ts +0 -0
  140. /package/lib/typescript/{src → commonjs/src}/Charts/BottomAxis/Tick.d.ts +0 -0
  141. /package/lib/typescript/{src → commonjs/src}/Charts/BottomAxis/index.d.ts +0 -0
  142. /package/lib/typescript/{src → commonjs/src}/Charts/ZoomableLinechart/ScalablePath.d.ts +0 -0
  143. /package/lib/typescript/{src → commonjs/src}/Charts/ZoomableLinechart/index.d.ts +0 -0
  144. /package/lib/typescript/{src → commonjs/src}/Charts/gesture.d.ts +0 -0
  145. /package/lib/typescript/{src → commonjs/src}/Charts/types.d.ts +0 -0
  146. /package/lib/typescript/{src → commonjs/src}/dateUtils.d.ts +0 -0
  147. /package/lib/typescript/{src → commonjs/src}/index.d.ts +0 -0
  148. /package/lib/typescript/{src → commonjs/src}/textUtils.d.ts +0 -0
package/package.json CHANGED
@@ -1,12 +1,26 @@
1
1
  {
2
2
  "name": "@obitrain/charts",
3
- "version": "0.10.0",
3
+ "version": "0.10.2",
4
4
  "description": "Charting library for React Native",
5
- "main": "lib/commonjs/index",
6
- "module": "lib/module/index",
7
- "types": "lib/typescript/src/index.d.ts",
5
+ "main": "lib/commonjs/index.js",
6
+ "module": "lib/module/index.js",
7
+ "types": "lib/typescript/commonjs/src/index.d.ts",
8
8
  "react-native": "src/index",
9
9
  "source": "src/index",
10
+ "exports": {
11
+ ".": {
12
+ "source": "./src/index.tsx",
13
+ "import": {
14
+ "types": "./lib/typescript/module/src/index.d.ts",
15
+ "default": "./lib/module/index.js"
16
+ },
17
+ "require": {
18
+ "types": "./lib/typescript/commonjs/src/index.d.ts",
19
+ "default": "./lib/commonjs/index.js"
20
+ }
21
+ },
22
+ "./package.json": "./package.json"
23
+ },
10
24
  "files": [
11
25
  "src",
12
26
  "lib",
@@ -25,6 +39,7 @@
25
39
  "!**/__mocks__",
26
40
  "!**/.*"
27
41
  ],
42
+ "sideEffects": false,
28
43
  "scripts": {
29
44
  "example": "yarn workspace obi-chart-example",
30
45
  "test": "jest",
@@ -32,9 +47,8 @@
32
47
  "lint": "eslint \"**/*.{js,ts,tsx}\"",
33
48
  "clean": "del-cli lib",
34
49
  "prepare": "bob build",
35
- "release": "./bin/release.sh",
36
50
  "gifs": "./bin/capture-gifs.sh",
37
- "check-deps": "npx @rnx-kit/align-deps@latest --diff-mode allow-subset package.json"
51
+ "check-deps": "rnx-align-deps --diff-mode allow-subset package.json"
38
52
  },
39
53
  "keywords": [
40
54
  "react-native",
@@ -55,6 +69,10 @@
55
69
  "access": "public",
56
70
  "registry": "https://registry.npmjs.org/"
57
71
  },
72
+ "dependencies": {
73
+ "@types/d3-scale": "^4.0.5",
74
+ "@types/d3-shape": "^3.1.3"
75
+ },
58
76
  "devDependencies": {
59
77
  "@commitlint/config-conventional": "^17.0.2",
60
78
  "@evilmartians/lefthook": "^1.5.0",
@@ -65,11 +83,8 @@
65
83
  "@react-native/eslint-config": "^0.86.0",
66
84
  "@react-native/jest-preset": "^0.86.0",
67
85
  "@react-native/metro-config": "^0.86.0",
68
- "@release-it/conventional-changelog": "^5.0.0",
69
86
  "@rnx-kit/align-deps": "^4.0.6",
70
87
  "@shopify/react-native-skia": "2.6.2",
71
- "@types/d3-scale": "^4.0.5",
72
- "@types/d3-shape": "^3.1.3",
73
88
  "@types/jest": "^29.2.1",
74
89
  "@types/react": "^19.2.0",
75
90
  "commitlint": "^17.0.2",
@@ -91,23 +106,17 @@
91
106
  "react-native-reanimated": "~4.5.1",
92
107
  "react-native-worklets": "^0.10.1",
93
108
  "react-test-renderer": "19.2.3",
94
- "release-it": "^15.0.0",
95
109
  "typescript": "^5.0.2"
96
110
  },
97
111
  "peerDependencies": {
98
112
  "@shopify/react-native-skia": ">=2.0.0 <3.0.0",
99
113
  "d3-scale": ">=4.0.2 <5.0.0",
100
114
  "d3-shape": ">=3.2.0 <4.0.0",
101
- "react": "16.9.0 || 16.11.0 || 16.13.1 || 17.0.1 || 17.0.2 || 18.0.0 || 18.1.0 || 18.2.0 || ^18.2.0 || 18.3.1 || 19.0.0 || 19.1.0 || 19.1.4 || ^16.9.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || 19.2.3",
102
- "react-native": "^0.61.5 || ^0.62.3 || ^0.63.2 || ^0.64.2 || ^0.65.0 || ^0.66.0 || ^0.67.0 || ^0.68.0 || ^0.69.0 || ^0.70.0 || ^0.71.0 || ^0.72.0 || ^0.73.0 || ^0.74.0 || ^0.75.0 || ^0.76.0 || ^0.77.0 || ^0.78.0 || ^0.79.0 || ^0.80.0 || ^0.81.6 || ^0.82.0 || ^0.83.0 || ^0.84.0 || ^0.85.0 || ^0.86.0 || ^0.87.0",
103
- "react-native-gesture-handler": "^1.9.0 || ^1.10.3 || ^2.3.2 || ^2.5.0 || ^2.6.0 || ^2.9.0 || ^2.12.0 || ^2.14.0 || ^2.18.1 || ^2.20.0 || ^2.22.0 || ^2.24.0 || ^2.26.0 || ^2.28.0 || ^2.29.1 || ^2.30.0 || ^2.31.1 || ~2.32.0 || ^3.1.0",
104
- "react-native-reanimated": "^1.13.3 || ^2.1.0 || ^2.2.1 || ^2.2.3 || ^2.2.4 || ^2.5.0 || ^2.9.0 || ^2.10.0 || ^2.14.1 || ^3.3.0 || ^3.6.0 || ^3.9.0 || ^3.15.0 || ^3.16.1 || ^3.16.7 || ^3.17.0 || ^3.17.5 || ^3.18.0 || ^3.19.0 || ^4.2.0 || ~4.2.0 || ^4.2.2 || ^4.4.3 || ~4.5.1 || ^4.5.3",
105
- "react-native-worklets": ">=0.10.0"
106
- },
107
- "peerDependenciesMeta": {
108
- "react-native-worklets": {
109
- "optional": true
110
- }
115
+ "react": "^16.9.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
116
+ "react-native": "^0.79.0 || ^0.80.0 || ^0.81.6 || ^0.82.0 || ^0.83.0 || ^0.84.0 || ^0.85.0 || ^0.86.0 || ^0.87.0",
117
+ "react-native-gesture-handler": "^2.26.0 || ^2.28.0 || ^2.29.1 || ^2.30.0 || ^2.31.1 || ~2.32.0 || ^3.1.0",
118
+ "react-native-reanimated": "^4.0.0 || ~4.5.1",
119
+ "react-native-worklets": ">=0.5.0"
111
120
  },
112
121
  "workspaces": [
113
122
  "example"
@@ -122,6 +131,17 @@
122
131
  },
123
132
  "jest": {
124
133
  "preset": "@react-native/jest-preset",
134
+ "moduleNameMapper": {
135
+ "^react-native-worklets$": "react-native-worklets/src/mock"
136
+ },
137
+ "setupFiles": [
138
+ "<rootDir>/jest.setup.js",
139
+ "@shopify/react-native-skia/jestSetup.js",
140
+ "react-native-gesture-handler/jestSetup.js"
141
+ ],
142
+ "transformIgnorePatterns": [
143
+ "node_modules/(?!((jest-)?react-native|@react-native(-community)?|@shopify/react-native-skia|react-native-reanimated|react-native-worklets|react-native-gesture-handler|d3-.*|internmap)/)"
144
+ ],
125
145
  "modulePathIgnorePatterns": [
126
146
  "<rootDir>/example/node_modules",
127
147
  "<rootDir>/lib/"
@@ -132,24 +152,6 @@
132
152
  "@commitlint/config-conventional"
133
153
  ]
134
154
  },
135
- "release-it": {
136
- "git": {
137
- "commitMessage": "chore: release ${version}",
138
- "tagName": "v${version}"
139
- },
140
- "npm": {
141
- "publish": true,
142
- "skipChecks": true
143
- },
144
- "github": {
145
- "release": true
146
- },
147
- "plugins": {
148
- "@release-it/conventional-changelog": {
149
- "preset": "angular"
150
- }
151
- }
152
- },
153
155
  "eslintConfig": {
154
156
  "root": true,
155
157
  "extends": [
@@ -185,8 +187,18 @@
185
187
  "source": "src",
186
188
  "output": "lib",
187
189
  "targets": [
188
- "commonjs",
189
- "module",
190
+ [
191
+ "commonjs",
192
+ {
193
+ "esm": true
194
+ }
195
+ ],
196
+ [
197
+ "module",
198
+ {
199
+ "esm": true
200
+ }
201
+ ],
190
202
  [
191
203
  "typescript",
192
204
  {
@@ -207,7 +219,7 @@
207
219
  "react-native@0.86"
208
220
  ],
209
221
  "production": [
210
- "react-native@*"
222
+ "react-native@>=0.79"
211
223
  ]
212
224
  },
213
225
  "capabilities": [
@@ -27,12 +27,12 @@ const AxisLine: FC<AxisLineProps> = function (props) {
27
27
  const p1 = useDerivedValue(() => {
28
28
  const p1X = getPositionWl(0, focalX.value, scale.value, offsetX.value);
29
29
  return vec(p1X, offsetY);
30
- }, []);
30
+ });
31
31
 
32
32
  const p2 = useDerivedValue(() => {
33
- const p1X = getPositionWl(width, focalX.value, scale.value, offsetX.value);
34
- return vec(p1X, offsetY);
35
- }, [width]);
33
+ const p2X = getPositionWl(width, focalX.value, scale.value, offsetX.value);
34
+ return vec(p2X, offsetY);
35
+ });
36
36
 
37
37
  return <Line {...{ p1, p2, color, strokeWidth }} />;
38
38
  };
@@ -21,7 +21,7 @@ export type BottomAxisProps = {
21
21
  const BottomAxis: FC<BottomAxisProps> = function (props) {
22
22
  const { labels, scale, focalX, offsetX, style, width, font } = props;
23
23
  const offsetY = props.offsetY ?? 0;
24
- const tickInterval = width / (labels.length - 1);
24
+ const tickInterval = labels.length > 1 ? width / (labels.length - 1) : 0;
25
25
 
26
26
  return (
27
27
  <Canvas style={style}>
@@ -22,19 +22,16 @@ export type TickProps = {
22
22
  export const Tick: React.FC<TickProps> = (props) => {
23
23
  const { label, scale, focalX, offsetX, initPosition, font } = props;
24
24
  const offsetY = props.offsetY ?? 0;
25
- const transform = useDerivedValue(
26
- () => [
27
- {
28
- translateX: getPositionWl(
29
- initPosition,
30
- focalX.value,
31
- scale.value,
32
- offsetX.value
33
- ),
34
- },
35
- ],
36
- [initPosition, offsetX]
37
- );
25
+ const transform = useDerivedValue(() => [
26
+ {
27
+ translateX: getPositionWl(
28
+ initPosition,
29
+ focalX.value,
30
+ scale.value,
31
+ offsetX.value
32
+ ),
33
+ },
34
+ ]);
38
35
  const width = font
39
36
  .getGlyphWidths(font.getGlyphIDs(label))
40
37
  .reduce((a, b) => a + b, 0);
@@ -10,7 +10,7 @@ export type CursorProps = {
10
10
  positionX: SharedValue<number>;
11
11
  size?: number;
12
12
  color?: string;
13
- currentValue?: SharedValue<number> | SharedValue<undefined>;
13
+ currentValue?: SharedValue<number> | SharedValue<number | undefined>;
14
14
  translateY?: SharedValue<number | undefined>;
15
15
  };
16
16
 
@@ -23,23 +23,22 @@ const Cursor: FC<CursorProps> = function ({
23
23
  size = CURSOR_SIZE,
24
24
  }) {
25
25
  if (currentValue !== undefined && translateY !== undefined) {
26
- console.warn('Current value as no effect when translateY is set');
26
+ console.warn('currentValue has no effect when translateY is set');
27
27
  }
28
28
 
29
- const _translateY = translateY
30
- ? translateY
31
- : // eslint-disable-next-line react-hooks/rules-of-hooks
32
- useDerivedValue(() => {
33
- const _commands = commands?.value;
34
- if (_commands === undefined) {
35
- return 0;
36
- }
37
- const _value = getYForX(_commands, positionX.value) ?? 0;
38
- if (currentValue !== undefined) {
39
- currentValue.value = _value;
40
- }
41
- return _value;
42
- });
29
+ const derivedTranslateY = useDerivedValue(() => {
30
+ const _commands = commands?.value;
31
+ if (_commands === undefined) {
32
+ return 0;
33
+ }
34
+ const _value = getYForX(_commands, positionX.value) ?? 0;
35
+ if (translateY === undefined && currentValue !== undefined) {
36
+ currentValue.value = _value;
37
+ }
38
+ return _value;
39
+ });
40
+
41
+ const _translateY = translateY ?? derivedTranslateY;
43
42
 
44
43
  const transform = useDerivedValue(() => [
45
44
  { translateX: positionX.value },
@@ -10,19 +10,23 @@ export type LinePath = {
10
10
  id?: string;
11
11
  };
12
12
 
13
- export type LineChartProps = {
14
- path?: SkPath | SharedValue<SkPath>;
15
- paths?: LinePath[];
13
+ type LineChartBaseProps = {
16
14
  height: number;
17
15
  width: number;
18
16
  style?: StyleProp<ViewStyle>;
19
- color?: string;
20
17
  offsetY?: number;
21
18
  offsetX?: number;
22
19
  background?: React.ReactNode;
23
20
  children?: React.ReactNode;
24
21
  };
25
22
 
23
+ // Require at least one of `path` / `paths` at compile time
24
+ export type LineChartProps = LineChartBaseProps &
25
+ (
26
+ | { path: SkPath | SharedValue<SkPath>; paths?: LinePath[]; color?: string }
27
+ | { paths: LinePath[]; path?: SkPath | SharedValue<SkPath>; color?: string }
28
+ );
29
+
26
30
  const LineChart: FC<LineChartProps> = function (props) {
27
31
  const {
28
32
  width,
@@ -1,12 +1,6 @@
1
- import {
2
- Path,
3
- Skia,
4
- type PathCommand,
5
- type SkPath,
6
- } from '@shopify/react-native-skia';
1
+ import { Path, Skia, type SkPath } from '@shopify/react-native-skia';
7
2
  import { type FC } from 'react';
8
3
  import { useDerivedValue, type SharedValue } from 'react-native-reanimated';
9
- import { scaleCommands } from '../graphUtils';
10
4
 
11
5
  export type ScalablePathProps = {
12
6
  path: SharedValue<SkPath>;
@@ -21,17 +15,15 @@ const ScalablePath: FC<ScalablePathProps> = function (props) {
21
15
  const { path, scale, focalX, offsetX, pathProps, color = 'red' } = props;
22
16
 
23
17
  const animatedPath = useDerivedValue(() => {
24
- let _cmds: PathCommand[] = [];
25
- try {
26
- _cmds = scaleCommands(path.value?.toCmds() ?? [], scale, focalX, offsetX);
27
- } catch (e) {
28
- console.error('Got error while scaling path: ', typeof e);
29
- _cmds = [];
30
- }
31
- const _path = Skia.Path.MakeFromCmds(_cmds);
32
- if (!_path) throw new Error('Path is null');
18
+ // Affine equivalent of getPositionWl: x' = scale * x + focalX * (1 - scale) + offsetX
19
+ const _path = path.value.copy();
20
+ _path.transform(
21
+ Skia.Matrix()
22
+ .translate(focalX.value * (1 - scale.value) + offsetX.value, 0)
23
+ .scale(scale.value, 1)
24
+ );
33
25
  return _path;
34
- }, [scale]);
26
+ });
35
27
 
36
28
  return (
37
29
  <Path
@@ -2,13 +2,12 @@ import { clamp } from '@shopify/react-native-skia';
2
2
  import { useCallback } from 'react';
3
3
  import { Gesture, type PanGesture, type PinchGesture } from 'react-native-gesture-handler';
4
4
  import {
5
- runOnJS,
6
5
  useAnimatedReaction,
7
- useDerivedValue,
8
6
  useSharedValue,
9
7
  withTiming,
10
8
  type SharedValue,
11
9
  } from 'react-native-reanimated';
10
+ import { scheduleOnRN } from 'react-native-worklets';
12
11
  import type { DataPoint } from './types';
13
12
 
14
13
  /**
@@ -75,11 +74,6 @@ export const useScalableGesture = (props: AxisGestureProps): ScalableGesture =>
75
74
  startScale,
76
75
  ]);
77
76
 
78
- const animateFocalPoint = (newFocalX: number) => {
79
- 'worklet';
80
- focalX.value = withTiming(newFocalX, { duration: 300 }); // Smooth transition with duration
81
- };
82
-
83
77
  const panGesture = Gesture.Pan()
84
78
  .onUpdate((event) => {
85
79
  const newOffsetX = lastOffsetX.value + event.translationX;
@@ -105,15 +99,12 @@ export const useScalableGesture = (props: AxisGestureProps): ScalableGesture =>
105
99
  let newOffset;
106
100
 
107
101
  if (leftBound > startOffset) {
108
- // console.log(`Left Boundary reached`);
109
102
  newOffset = offsetX.value - leftBound + startOffset;
110
- } else if (rightBound < width) {
111
- // console.log(`Right Boundary reached`);
103
+ } else if (rightBound < width + startOffset) {
112
104
  newOffset = offsetX.value + width - rightBound + startOffset;
113
105
  } else {
114
106
  newOffset = offsetX.value;
115
107
  }
116
- if (newOffset === undefined) throw new Error('newOffset is undefined');
117
108
 
118
109
  offsetX.value = withTiming(newOffset, { duration: 300 });
119
110
  lastOffsetX.value = newOffset;
@@ -121,13 +112,15 @@ export const useScalableGesture = (props: AxisGestureProps): ScalableGesture =>
121
112
 
122
113
  const pinchGesture = Gesture.Pinch()
123
114
  .onUpdate((event) => {
124
- const newScale = lastScale.value * event.scale;
125
- scale.value = clamp(newScale, 1, Infinity); // Clamp the scale value
126
- animateFocalPoint(event.focalX);
115
+ // Rebase offsetX so moving the focal point doesn't shift the content
116
+ offsetX.value += (focalX.value - event.focalX) * (1 - scale.value);
117
+ focalX.value = event.focalX;
118
+ scale.value = clamp(lastScale.value * event.scale, 1, Infinity);
127
119
  })
128
120
  .onEnd(() => {
129
121
  lastScale.value = scale.value;
130
122
  lastFocalX.value = focalX.value;
123
+ lastOffsetX.value = offsetX.value;
131
124
  });
132
125
 
133
126
  return {
@@ -165,12 +158,11 @@ export const useUpdateAxis = function (props: UpdateAxisProps) {
165
158
  currentIndex.value !== i
166
159
  ) {
167
160
  currentIndex.value = i;
168
- if (onScaleChange !== undefined) runOnJS(onScaleChange)(i);
161
+ if (onScaleChange !== undefined) scheduleOnRN(onScaleChange, i);
169
162
  break;
170
163
  }
171
164
  }
172
- },
173
- []
165
+ }
174
166
  );
175
167
 
176
168
  return { currentIndex };
@@ -221,34 +213,43 @@ export const useCursorGesture = function (props: UseCursorGestureProps) {
221
213
  isContinuous = true,
222
214
  } = props;
223
215
 
224
- const xPosition = useSharedValue(0);
225
- const yPosition = useSharedValue(height); // GRAPH_HEIGHT
216
+ if (!isContinuous && points === undefined)
217
+ console.warn('Points must be defined for non-continuous mode');
226
218
 
227
- const panGesture = Gesture.Pan()
228
- .onBegin((event) => {
229
- xPosition.value = clamp(event.x, 0, width);
230
- yPosition.value = clamp(event.y, 0, height);
231
- })
232
- .onUpdate((event) => {
233
- xPosition.value = clamp(event.x, 0, width);
234
- yPosition.value = clamp(event.y, 0, height);
235
- });
236
-
237
- const tapGesture = Gesture.Tap().onBegin((event) => {
238
- xPosition.value = clamp(event.x, 0, width);
239
- yPosition.value = clamp(event.y, 0, height);
240
- });
219
+ const xPosition = useSharedValue(0);
220
+ const yPosition = useSharedValue(height);
241
221
 
242
- useDerivedValue(() => {
243
- if (isContinuous) return;
244
- if (points === undefined) {
245
- console.warn('Points must be defined for non-continuous mode');
222
+ const setPosition = (x: number, y: number) => {
223
+ 'worklet';
224
+ yPosition.value = clamp(y, 0, height);
225
+ if (isContinuous || points === undefined) {
226
+ xPosition.value = clamp(x, 0, width);
246
227
  return;
247
228
  }
248
- const _closestDot = getClosestPoint(xPosition.value, points.value);
229
+ const _closestDot = getClosestPoint(clamp(x, 0, width), points.value);
249
230
  if (closestDataPoint !== undefined) closestDataPoint.value = _closestDot;
250
231
  xPosition.value = _closestDot.x;
251
- }, [xPosition, isContinuous]);
232
+ };
233
+
234
+ const panGesture = Gesture.Pan()
235
+ .onBegin((event) => setPosition(event.x, event.y))
236
+ .onUpdate((event) => setPosition(event.x, event.y));
237
+
238
+ const tapGesture = Gesture.Tap().onBegin((event) =>
239
+ setPosition(event.x, event.y)
240
+ );
241
+
242
+ // Re-snap the cursor when the data points change (e.g. switching graphs)
243
+ useAnimatedReaction(
244
+ () => points?.value,
245
+ (_points) => {
246
+ if (isContinuous || _points === undefined || _points.length === 0)
247
+ return;
248
+ const _closestDot = getClosestPoint(xPosition.value, _points);
249
+ if (closestDataPoint !== undefined) closestDataPoint.value = _closestDot;
250
+ xPosition.value = _closestDot.x;
251
+ }
252
+ );
252
253
 
253
254
  return { panGesture, tapGesture, xPosition, yPosition };
254
255
  };
@@ -15,7 +15,7 @@ import { getPositionWl } from './gesture';
15
15
  import { getYForX } from './maths';
16
16
  import type { AnimatedDot, DataPoint } from './types';
17
17
 
18
- export type Config = {
18
+ export type BuildGraphConfig = {
19
19
  minX?: number;
20
20
  maxX?: number;
21
21
  minY?: number;
@@ -24,8 +24,11 @@ export type Config = {
24
24
  curve?: shape.CurveFactory | shape.CurveFactoryLineOnly;
25
25
  };
26
26
 
27
+ /** @deprecated Use {@link BuildGraphConfig} instead */
28
+ export type Config = BuildGraphConfig;
29
+
27
30
  export type GraphData = {
28
- data: [number, number][];
31
+ data: [x: number, y: number][];
29
32
  minY: number;
30
33
  maxY: number;
31
34
  path: string;
@@ -36,38 +39,40 @@ export type GraphData = {
36
39
  };
37
40
 
38
41
  export const buildGraph = function (
39
- data: [number, number][],
42
+ data: [x: number, y: number][],
40
43
  width: number,
41
44
  height: number,
42
- config?: Config
45
+ config?: BuildGraphConfig
43
46
  ): GraphData {
44
- const minX = config?.minX ?? Math.min(...data.map((x) => x[0]));
45
- const maxX = config?.maxX ?? Math.max(...data.map((x) => x[0]));
47
+ if (data.length === 0)
48
+ throw new Error('buildGraph requires at least one data point');
49
+
50
+ const minX = config?.minX ?? Math.min(...data.map((d) => d[0]));
51
+ const maxX = config?.maxX ?? Math.max(...data.map((d) => d[0]));
46
52
  const scaleX = scaleLinear().domain([minX, maxX]).range([0, width]);
47
53
 
48
- const minY = config?.minY ?? Math.min(...data.map((x) => x[1]));
49
- const maxY = config?.maxY ?? Math.max(...data.map((x) => x[1]));
54
+ const minY = config?.minY ?? Math.min(...data.map((d) => d[1]));
55
+ const maxY = config?.maxY ?? Math.max(...data.map((d) => d[1]));
50
56
  const scaleY = scaleLinear().domain([minY, maxY]).range([height, 0]);
51
57
 
52
- const fmtValues = data.map((x) => [x[1], x[0]] as [number, number]);
53
-
54
58
  const path = shape
55
- .line()
56
- .x(([, x]) => scaleX(x))
57
- .y(([y]) => scaleY(y))
58
- .curve(config?.curve ?? shape.curveBasis)(fmtValues) as string;
59
+ .line<[number, number]>()
60
+ .x(([x]) => scaleX(x))
61
+ .y(([, y]) => scaleY(y))
62
+ .curve(config?.curve ?? shape.curveBasis)(data);
63
+ if (path === null) throw new Error('Failed to build the line path');
59
64
 
60
- const dataPoints = fmtValues.map(([y, x]) => ({
65
+ const dataPoints = data.map(([x, y]) => ({
61
66
  x: scaleX(x),
62
67
  y: scaleY(y),
63
68
  value: y,
64
69
  }));
65
70
 
66
71
  const skiaPath = Skia.Path.MakeFromSVGString(path);
67
- if (skiaPath == null) throw new Error('Path not found');
72
+ if (skiaPath == null) throw new Error('Failed to parse the SVG path');
68
73
 
69
74
  return {
70
- data: fmtValues,
75
+ data,
71
76
  minY,
72
77
  maxY,
73
78
  path,
@@ -136,7 +141,6 @@ export const scaleCommands = function (
136
141
  ];
137
142
  }
138
143
  if (commandType === PathVerb.Close) return command;
139
- if (commandType === PathVerb.Move) return command;
140
144
  throw new Error(`Unsupported command type ${commandType}`);
141
145
  });
142
146
  };
@@ -173,25 +177,26 @@ export const useDotsTransition = function (props: UseDotAnimationProps) {
173
177
  () => ({
174
178
  _currentGraph: currentGraph.value,
175
179
  _currentCommands: path.value.toCmds(),
180
+ // Track the animating x values so y stays glued to the curve
181
+ // even when the path is swapped instantly or tweens on another duration
182
+ _xs: dots.map((d) => d.x.value),
176
183
  }),
177
184
  ({ _currentGraph, _currentCommands }) => {
178
185
  const newDataPoints = dataPoints[_currentGraph];
179
186
  if (newDataPoints === undefined)
180
187
  throw new Error('Data points cannot be undefined');
181
- dots.map((_dot, i) => {
188
+ dots.forEach((_dot, i) => {
182
189
  const _newDot = newDataPoints[i];
183
190
  if (!_newDot) {
184
191
  _dot.opacity.value = opacityWl(0);
185
192
  return;
186
- } else {
187
- _dot.x.value = translateWl(_newDot.x);
188
- const newY = getYForX(_currentCommands, _dot.x.value);
189
- if (newY !== undefined) {
190
- _dot.y.value = newY;
191
- }
192
- // _dot.y.value = withTiming(newDots[i]!.y, { duration: 1000 });
193
- _dot.opacity.value = opacityWl(1);
194
193
  }
194
+ _dot.x.value = translateWl(_newDot.x);
195
+ const newY = getYForX(_currentCommands, _dot.x.value);
196
+ if (newY !== undefined) {
197
+ _dot.y.value = newY;
198
+ }
199
+ _dot.opacity.value = opacityWl(1);
195
200
  });
196
201
  }
197
202
  );
@@ -1,10 +1,18 @@
1
1
  export { AxisLine, BottomAxis, Tick } from './BottomAxis';
2
+ export type {
3
+ AxisLineProps,
4
+ BottomAxisProps,
5
+ TickProps,
6
+ } from './BottomAxis';
2
7
  export { Cursor } from './Cursor';
3
8
  export type { CursorProps } from './Cursor';
4
9
  export { LineChart } from './Linechart';
5
10
  export type { LineChartProps, LinePath } from './Linechart';
6
11
  export { ScalablePath, ZoomableLineChart } from './ZoomableLinechart';
7
- export type { ZoomableLineChartProps } from './ZoomableLinechart';
12
+ export type {
13
+ ScalablePathProps,
14
+ ZoomableLineChartProps,
15
+ } from './ZoomableLinechart';
8
16
  export {
9
17
  getClosestPoint,
10
18
  getPositionWl,
@@ -12,7 +20,12 @@ export {
12
20
  useScalableGesture,
13
21
  useUpdateAxis,
14
22
  } from './gesture';
15
- export type { UseCursorGestureProps } from './gesture';
23
+ export type {
24
+ AxisGestureProps,
25
+ ScalableGesture,
26
+ UpdateAxisProps,
27
+ UseCursorGestureProps,
28
+ } from './gesture';
16
29
  export {
17
30
  buildGraph,
18
31
  defaultOpacityTransitionWl,
@@ -20,7 +33,13 @@ export {
20
33
  scaleCommands,
21
34
  useDotsTransition,
22
35
  } from './graphUtils';
23
- export type { Config, GraphData, UseDotAnimationProps } from './graphUtils';
36
+ export type {
37
+ BuildGraphConfig,
38
+ // eslint-disable-next-line deprecation/deprecation
39
+ Config,
40
+ GraphData,
41
+ UseDotAnimationProps,
42
+ } from './graphUtils';
24
43
  export {
25
44
  commandsToBezier,
26
45
  cubicBezierYForX,