@bashem/rn-charts 0.0.3 → 0.0.5

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 (79) hide show
  1. package/README.md +1 -1
  2. package/lib/module/skia/AreaChart/AreaChart.js +60 -51
  3. package/lib/module/skia/AreaChart/AreaChart.js.map +1 -1
  4. package/lib/module/skia/AreaChart/useAreaChart.js +18 -14
  5. package/lib/module/skia/AreaChart/useAreaChart.js.map +1 -1
  6. package/lib/module/skia/BarChart/BarChart.js +156 -69
  7. package/lib/module/skia/BarChart/BarChart.js.map +1 -1
  8. package/lib/module/skia/BarChart/useBarChart.js +53 -41
  9. package/lib/module/skia/BarChart/useBarChart.js.map +1 -1
  10. package/lib/module/skia/Common/HorizontalLabelView.js +121 -0
  11. package/lib/module/skia/Common/HorizontalLabelView.js.map +1 -0
  12. package/lib/module/skia/Common/VerticalLabelView.js +100 -0
  13. package/lib/module/skia/Common/VerticalLabelView.js.map +1 -0
  14. package/lib/module/skia/Common/useComponentLayout.js +13 -0
  15. package/lib/module/skia/Common/useComponentLayout.js.map +1 -0
  16. package/lib/module/skia/HeatMap/DateHeatMap.js +472 -0
  17. package/lib/module/skia/HeatMap/DateHeatMap.js.map +1 -0
  18. package/lib/module/skia/HeatMap/HeatMap.js +121 -33
  19. package/lib/module/skia/HeatMap/HeatMap.js.map +1 -1
  20. package/lib/module/skia/HeatMap/useHeatMap.js +132 -48
  21. package/lib/module/skia/HeatMap/useHeatMap.js.map +1 -1
  22. package/lib/module/skia/PieChart/PieChart.js +21 -17
  23. package/lib/module/skia/PieChart/PieChart.js.map +1 -1
  24. package/lib/module/skia/PieChart/usePieChart.js +241 -30
  25. package/lib/module/skia/PieChart/usePieChart.js.map +1 -1
  26. package/lib/module/skia/Popup.js +7 -5
  27. package/lib/module/skia/Popup.js.map +1 -1
  28. package/lib/module/skia/common.js +4 -41
  29. package/lib/module/skia/common.js.map +1 -1
  30. package/lib/typescript/src/index.d.ts +1 -0
  31. package/lib/typescript/src/index.d.ts.map +1 -1
  32. package/lib/typescript/src/skia/AreaChart/AreaChart.d.ts +15 -3
  33. package/lib/typescript/src/skia/AreaChart/AreaChart.d.ts.map +1 -1
  34. package/lib/typescript/src/skia/AreaChart/useAreaChart.d.ts +13 -14
  35. package/lib/typescript/src/skia/AreaChart/useAreaChart.d.ts.map +1 -1
  36. package/lib/typescript/src/skia/BarChart/BarChart.d.ts +16 -2
  37. package/lib/typescript/src/skia/BarChart/BarChart.d.ts.map +1 -1
  38. package/lib/typescript/src/skia/BarChart/useBarChart.d.ts +17 -5
  39. package/lib/typescript/src/skia/BarChart/useBarChart.d.ts.map +1 -1
  40. package/lib/typescript/src/skia/Common/HorizontalLabelView.d.ts +33 -0
  41. package/lib/typescript/src/skia/Common/HorizontalLabelView.d.ts.map +1 -0
  42. package/lib/typescript/src/skia/Common/VerticalLabelView.d.ts +24 -0
  43. package/lib/typescript/src/skia/Common/VerticalLabelView.d.ts.map +1 -0
  44. package/lib/typescript/src/skia/Common/useComponentLayout.d.ts +4 -0
  45. package/lib/typescript/src/skia/Common/useComponentLayout.d.ts.map +1 -0
  46. package/lib/typescript/src/skia/HeatMap/DateHeatMap.d.ts +1 -0
  47. package/lib/typescript/src/skia/HeatMap/DateHeatMap.d.ts.map +1 -0
  48. package/lib/typescript/src/skia/HeatMap/HeatMap.d.ts +28 -12
  49. package/lib/typescript/src/skia/HeatMap/HeatMap.d.ts.map +1 -1
  50. package/lib/typescript/src/skia/HeatMap/useHeatMap.d.ts +15 -4
  51. package/lib/typescript/src/skia/HeatMap/useHeatMap.d.ts.map +1 -1
  52. package/lib/typescript/src/skia/PieChart/PieChart.d.ts +5 -1
  53. package/lib/typescript/src/skia/PieChart/PieChart.d.ts.map +1 -1
  54. package/lib/typescript/src/skia/PieChart/usePieChart.d.ts +6 -1
  55. package/lib/typescript/src/skia/PieChart/usePieChart.d.ts.map +1 -1
  56. package/lib/typescript/src/skia/Popup.d.ts.map +1 -1
  57. package/lib/typescript/src/skia/common.d.ts +3 -10
  58. package/lib/typescript/src/skia/common.d.ts.map +1 -1
  59. package/package.json +11 -8
  60. package/src/index.tsx +6 -4
  61. package/src/skia/AreaChart/AreaChart.tsx +85 -62
  62. package/src/skia/AreaChart/useAreaChart.ts +25 -26
  63. package/src/skia/BarChart/BarChart.tsx +163 -95
  64. package/src/skia/BarChart/useBarChart.ts +55 -44
  65. package/src/skia/Common/HorizontalLabelView.tsx +153 -0
  66. package/src/skia/Common/VerticalLabelView.tsx +113 -0
  67. package/src/skia/Common/useComponentLayout.ts +14 -0
  68. package/src/skia/HeatMap/DateHeatMap.tsx +470 -0
  69. package/src/skia/HeatMap/HeatMap.tsx +168 -54
  70. package/src/skia/HeatMap/useHeatMap.ts +139 -65
  71. package/src/skia/PieChart/PieChart.tsx +16 -11
  72. package/src/skia/PieChart/usePieChart.ts +316 -66
  73. package/src/skia/Popup.tsx +38 -36
  74. package/src/skia/common.ts +8 -46
  75. package/lib/module/skia/Common/VerticalLabel.js +0 -73
  76. package/lib/module/skia/Common/VerticalLabel.js.map +0 -1
  77. package/lib/typescript/src/skia/Common/VerticalLabel.d.ts +0 -17
  78. package/lib/typescript/src/skia/Common/VerticalLabel.d.ts.map +0 -1
  79. package/src/skia/Common/VerticalLabel.tsx +0 -91
@@ -1,18 +1,175 @@
1
- import { useState } from "react";
2
- import type { PieChartProps, PieChartStyles, PieSlice, PopupData } from "./PieChart";
3
- import { rect, Skia } from "@shopify/react-native-skia";
1
+ import { useMemo, useState } from "react";
2
+ import type { PieChartProps, PopupData } from "./PieChart";
3
+ import { rect, Skia, type SkPath } from "@shopify/react-native-skia";
4
4
  import { getRandomRGBColor } from "../common";
5
5
 
6
- function deegreesToRadians(degrees: number): number {
6
+ function degreesToRadians(degrees: number): number {
7
7
  return (degrees * Math.PI) / 180;
8
8
  }
9
9
 
10
10
  function ypoint(angle: number, radius: number, cy: number): number {
11
- return cy - radius * Math.sin(deegreesToRadians(angle));
11
+ return cy - radius * Math.sin(degreesToRadians(angle));
12
12
  }
13
13
 
14
14
  function xpoint(angle: number, radius: number, cx: number): number {
15
- return cx - radius * Math.cos(deegreesToRadians(angle));
15
+ return cx - radius * Math.cos(degreesToRadians(angle));
16
+ }
17
+
18
+ type Point = { x: number; y: number; };
19
+
20
+ function euclideanDistance(dx: number, dy: number) {
21
+ return Math.hypot(dx, dy);
22
+ }
23
+
24
+ function getProportionPoint(
25
+ point: Point,
26
+ segment: number,
27
+ length: number,
28
+ dx: number,
29
+ dy: number
30
+ ): Point {
31
+ const factor = segment / length;
32
+
33
+ return {
34
+ x: point.x - dx * factor,
35
+ y: point.y - dy * factor,
36
+ };
37
+ }
38
+
39
+ function angle(cx: number, cy: number, x: number, y: number) {
40
+ return (Math.atan2(y - cy, x - cx) * (180 / Math.PI) + 360) % 360;
41
+ }
42
+
43
+ // https://stackoverflow.com/a/24780108/13509919
44
+ function drawRoundedCorner(
45
+ path: SkPath,
46
+ angularPoint: Point,
47
+ p1: Point,
48
+ p2: Point,
49
+ radius: number
50
+ ) {
51
+ // Vector 1
52
+ const dx1 = angularPoint.x - p1.x;
53
+ const dy1 = angularPoint.y - p1.y;
54
+
55
+ // Vector 2
56
+ const dx2 = angularPoint.x - p2.x;
57
+ const dy2 = angularPoint.y - p2.y;
58
+
59
+ // Angle / 2
60
+ let angleHalf =
61
+ (Math.atan2(dy1, dx1) - Math.atan2(dy2, dx2)) / 2;
62
+
63
+ const tan = Math.abs(Math.tan(angleHalf));
64
+ if (tan === 0) return;
65
+
66
+ let segment = radius / tan;
67
+
68
+ // Lengths
69
+ const length1 = euclideanDistance(dx1, dy1);
70
+ const length2 = euclideanDistance(dx2, dy2);
71
+
72
+ const length = Math.min(length1, length2);
73
+
74
+ // Clamp
75
+ if (segment > length) {
76
+ segment = length;
77
+ radius = length * tan;
78
+ }
79
+
80
+ // Trimmed points
81
+ const p1Cross = getProportionPoint(
82
+ angularPoint,
83
+ segment,
84
+ length1,
85
+ dx1,
86
+ dy1
87
+ );
88
+
89
+ const p2Cross = getProportionPoint(
90
+ angularPoint,
91
+ segment,
92
+ length2,
93
+ dx2,
94
+ dy2
95
+ );
96
+
97
+ // Circle center
98
+ const dx = angularPoint.x * 2 - p1Cross.x - p2Cross.x;
99
+ const dy = angularPoint.y * 2 - p1Cross.y - p2Cross.y;
100
+
101
+ const L = euclideanDistance(dx, dy);
102
+ const d = Math.hypot(segment, radius);
103
+
104
+ const circlePoint = getProportionPoint(
105
+ angularPoint,
106
+ d,
107
+ L,
108
+ dx,
109
+ dy
110
+ );
111
+
112
+ // Angles (degrees for Skia)
113
+ let startAngle = angle(
114
+ circlePoint.x,
115
+ circlePoint.y,
116
+ p1Cross.x,
117
+ p1Cross.y
118
+ );
119
+
120
+ let endAngle = angle(
121
+ circlePoint.x,
122
+ circlePoint.y,
123
+ p2Cross.x,
124
+ p2Cross.y
125
+ );
126
+
127
+ let sweepAngle = endAngle - startAngle;
128
+
129
+ // Normalize
130
+ if (sweepAngle < 0) {
131
+ const temp = startAngle;
132
+ startAngle = endAngle;
133
+ sweepAngle = temp - endAngle;
134
+ }
135
+
136
+ if (sweepAngle > 180) {
137
+ sweepAngle = 180 - sweepAngle;
138
+ }
139
+
140
+ path.moveTo(p1Cross.x, p1Cross.y);
141
+
142
+ // arc
143
+ path.addArc(
144
+ rect(
145
+ circlePoint.x - radius,
146
+ circlePoint.y - radius,
147
+ radius * 2,
148
+ radius * 2
149
+ ),
150
+ startAngle,
151
+ sweepAngle
152
+ );
153
+ path.lineTo(p1Cross.x, p1Cross.y);
154
+ path.close();
155
+
156
+ drawLines(path, [
157
+ { x: p1.x, y: p1.y },
158
+ { x: p1Cross.x, y: p1Cross.y },
159
+ { x: p2Cross.x, y: p2Cross.y },
160
+ { x: p2.x, y: p2.y },
161
+ { x: p1.x, y: p1.y },
162
+ ]);
163
+ }
164
+
165
+ function drawLines(path: SkPath, points: Point[]) {
166
+ if (points.length === 0) return;
167
+
168
+ path.moveTo(points[0]!.x, points[0]!.y);
169
+ for (let i = 1; i < points.length; i++) {
170
+ path.lineTo(points[i]!.x, points[i]!.y);
171
+ }
172
+ path.close();
16
173
  }
17
174
 
18
175
  function getCircularPoints(
@@ -30,6 +187,9 @@ function getCircularPoints(
30
187
  return [x1, y1, x2, y2];
31
188
  }
32
189
 
190
+ // FIXME: Doesn't work innerradius is set to 0, need to investigate why. If it is set to a very small number, it works fine. COPILOT: This is a known issue in Skia when the path has self-intersection. Issue also occurs when rounding is set and innerRadius is small.
191
+ // QUICKFIX: If innerRadius is 0, we can set it to a very small number like 0.001 to avoid the issue.
192
+ // TODO: Verify the rounding of corners throughly
33
193
  export function usePieChart({
34
194
  slices,
35
195
  style,
@@ -40,64 +200,151 @@ export function usePieChart({
40
200
 
41
201
  const radius = style.radius ?? 150;
42
202
  const diameter = radius * 2;
43
- const innerRadius = style.innerRadius ?? 100;
44
- const cx = radius;
45
- const cy = radius;
46
-
47
- const total = slices.reduce((sum, slice) => sum + slice.value, 0);
48
-
49
- let startAngle = 0;
50
-
51
- const paths = slices.map(({ value, color }, index) => {
52
- const sweepAngle = (value / total) * 360;
53
-
54
- let [x1, y1, x2, y2] = getCircularPoints(
55
- startAngle,
56
- radius,
57
- sweepAngle,
58
- cx,
59
- cy
60
- );
61
- let [cx1, cy1, cx2, cy2] = getCircularPoints(
62
- startAngle,
63
- innerRadius,
64
- sweepAngle,
65
- cx,
66
- cy
67
- );
68
-
69
- const path = Skia.Path.Make();
70
- path.moveTo(cx1, cy1);
71
- path.lineTo(x1, y1);
72
- path.addArc(
73
- rect(
74
- cx - radius,
75
- cy - radius,
76
- radius * 2,
77
- radius * 2
78
- ),
79
- startAngle + 180,
80
- sweepAngle
81
- );
82
- path.lineTo(cx2, cy2);
83
-
84
- path.addArc(
85
- rect(
86
- cx - innerRadius,
87
- cy - innerRadius,
88
- innerRadius * 2,
89
- innerRadius * 2
90
- ),
91
- startAngle + 180 + sweepAngle,
92
- -sweepAngle
93
- );
94
- path.lineTo(x1, y1);
95
- path.close();
96
-
97
- startAngle += sweepAngle;
98
-
99
- return { path, color: color ?? getRandomRGBColor() };
100
- });
203
+ const width = diameter + 30;
204
+ const height = width;
205
+ const innerRadius = Math.max(0.0001, style.innerRadius ?? 100);
206
+ const interSliceGap = style.interSliceGap ?? 20;
207
+ const cx = width / 2;
208
+ const cy = height / 2;
209
+
210
+ const { paths, total } = useMemo(() => {
211
+ const total = slices.reduce((sum, slice) => sum + slice.value, 0);
212
+ let startAngle = style.startAngle ?? 0;
213
+
214
+ const paths = slices.map(({ value, color, radius: givenRoundRadius = 0 }, index) => {
215
+ const sweepAngleTobeAdded = (value / total) * 360;
216
+ let currentStartAngle = startAngle;
217
+ let sweepAngle = sweepAngleTobeAdded;
218
+ startAngle += sweepAngleTobeAdded;
219
+
220
+ const outerCircleLength = 2 * Math.PI * radius;
221
+ const innerCircleLength = 2 * Math.PI * innerRadius;
222
+ const roundRadius = Math.min(givenRoundRadius, (radius - innerRadius) / 2, innerCircleLength / 2);
223
+
224
+ let angleReductionForGap = !interSliceGap ? 0 : (interSliceGap / outerCircleLength) * 360;
225
+ let angleReductionForRounding = (roundRadius / outerCircleLength) * 360 * 2;
226
+ let angleReductionForInnerCircle = (roundRadius / innerCircleLength) * 360 * 2;
227
+
228
+ currentStartAngle += angleReductionForGap / 2;
229
+ sweepAngle -= angleReductionForGap;
230
+
231
+ let innerCircleStartAngle = currentStartAngle;
232
+ let innerCircleSweepAngle = sweepAngle;
233
+
234
+ const boundaryCircleStartingAngle = currentStartAngle + angleReductionForRounding / 2;
235
+ const boundaryCircleSweepAngle = sweepAngle - angleReductionForRounding;
236
+
237
+ const innerCircleBoundaryStartingAngle = innerCircleStartAngle + angleReductionForInnerCircle / 2;
238
+ const innerCircleBoundarySweepAngle = innerCircleSweepAngle - angleReductionForInnerCircle;
239
+ // Outer Circle
240
+ let [x1, y1, x2, y2] = getCircularPoints(
241
+ boundaryCircleStartingAngle,
242
+ radius,
243
+ boundaryCircleSweepAngle,
244
+ cx,
245
+ cy
246
+ );
247
+
248
+ let [cx1, cy1, cx2, cy2] = getCircularPoints(
249
+ currentStartAngle,
250
+ radius,
251
+ sweepAngle,
252
+ cx,
253
+ cy
254
+ );
255
+
256
+ let [rx1, ry1, rx2, ry2] = getCircularPoints(
257
+ currentStartAngle,
258
+ radius - roundRadius,
259
+ sweepAngle,
260
+ cx,
261
+ cy
262
+ );
263
+
264
+ // Inner circle
265
+ let [ix1, iy1, ix2, iy2] = getCircularPoints(
266
+ innerCircleBoundaryStartingAngle,
267
+ innerRadius,
268
+ innerCircleBoundarySweepAngle,
269
+ cx,
270
+ cy
271
+ );
272
+
273
+ let [cix1, ciy1, cix2, ciy2] = getCircularPoints(
274
+ innerCircleStartAngle,
275
+ innerRadius,
276
+ innerCircleSweepAngle,
277
+ cx,
278
+ cy
279
+ );
280
+ let [rix1, riy1, rix2, riy2] = getCircularPoints(
281
+ innerCircleStartAngle,
282
+ innerRadius + roundRadius,
283
+ innerCircleSweepAngle,
284
+ cx,
285
+ cy
286
+ );
287
+
288
+ let path = Skia.Path.Make();
289
+ drawRoundedCorner(path, { x: cx2, y: cy2 }, { x: x2, y: y2 }, { x: rx2, y: ry2 }, roundRadius);
290
+ drawRoundedCorner(path, { x: cix2, y: ciy2 }, { x: rix2, y: riy2 }, { x: ix2, y: iy2 }, roundRadius);
291
+ drawLines(path, [
292
+ { x: x2, y: y2 },
293
+ { x: rx2, y: ry2 },
294
+ { x: rix2, y: riy2 },
295
+ { x: ix2, y: iy2 },
296
+ { x: x2, y: y2 },
297
+ ]);
298
+
299
+ path.moveTo(x1, y1);
300
+ path.addArc(
301
+ rect(
302
+ cx - radius,
303
+ cy - radius,
304
+ radius * 2,
305
+ radius * 2
306
+ ),
307
+ boundaryCircleStartingAngle + 180,
308
+ boundaryCircleSweepAngle
309
+ );
310
+
311
+ path.lineTo(ix2, iy2);
312
+
313
+ path.addArc(
314
+ rect(
315
+ cx - innerRadius,
316
+ cy - innerRadius,
317
+ innerRadius * 2,
318
+ innerRadius * 2
319
+ ),
320
+ innerCircleBoundaryStartingAngle + 180 + innerCircleBoundarySweepAngle,
321
+ -innerCircleBoundarySweepAngle
322
+ );
323
+ path.lineTo(x1, y1);
324
+ path.close();
325
+
326
+ drawRoundedCorner(path, { x: cix1, y: ciy1 }, { x: ix1, y: iy1 }, { x: rix1, y: riy1 }, roundRadius);
327
+ drawRoundedCorner(path, { x: cx1, y: cy1 }, { x: rx1, y: ry1 }, { x: x1, y: y1 }, roundRadius);
328
+ drawLines(path, [
329
+ { x: ix1, y: iy1 },
330
+ { x: rix1, y: riy1 },
331
+ { x: rx1, y: ry1 },
332
+ { x: x1, y: y1 },
333
+ { x: ix1, y: iy1 },
334
+ ]);
335
+
336
+ return { path, color: color ?? getRandomRGBColor() };
337
+ });
338
+ return { paths, total };
339
+ }, [
340
+ slices,
341
+ radius,
342
+ innerRadius,
343
+ interSliceGap,
344
+ cx,
345
+ cy,
346
+ style.startAngle
347
+ ]);
101
348
 
102
349
  const touchHandler = (locationX: number, locationY: number) => {
103
350
  if (!onSliceTouch || locationX < 0 || locationY < 0 || locationX >= diameter || locationY >= diameter) {
@@ -114,8 +361,6 @@ export function usePieChart({
114
361
 
115
362
  let lastAngle = (slice.value / total) * 360;
116
363
  if (path.contains(locationX, locationY)) {
117
- const label = slice.label || 'Slice';
118
-
119
364
  const outerX = xpoint(angles + lastAngle / 2, radius, cx);
120
365
  const innerX = xpoint(angles + lastAngle / 2, innerRadius, cx);
121
366
 
@@ -145,12 +390,17 @@ export function usePieChart({
145
390
  setPopupData(undefined);
146
391
  }
147
392
  };
393
+
148
394
  return {
149
395
  paths,
396
+ height,
397
+ width,
150
398
  diameter,
151
399
  innerRadius,
152
400
  radius,
153
401
  popupData,
154
402
  touchHandler,
403
+ cx,
404
+ cy
155
405
  };
156
406
  }
@@ -2,9 +2,9 @@ import React from 'react';
2
2
  import { Modal, View } from 'react-native';
3
3
 
4
4
  export interface PopupStyle<T> {
5
- width?: number;
6
- height?: number;
7
- renderPopup?: (data: T) => React.ReactNode;
5
+ width?: number;
6
+ height?: number;
7
+ renderPopup?: (data: T) => React.ReactNode;
8
8
  }
9
9
 
10
10
  interface PopupData<T> {
@@ -19,7 +19,7 @@ interface PopupProps<T> {
19
19
  totalHeight: number;
20
20
  touchHandler?: (x: number, y: number) => void;
21
21
  onTouchOutside?: () => void;
22
- popupStyle?: PopupStyle<T>;
22
+ popupStyle?: PopupStyle<T>;
23
23
  viewOffset: {
24
24
  x: number;
25
25
  y: number;
@@ -63,13 +63,13 @@ export default function Popup<T>({
63
63
  >
64
64
  {popupData && !Array.isArray(popupData) && (
65
65
  <View
66
- style={[
66
+ style={
67
67
  {
68
68
  position: 'absolute',
69
69
  left: Math.max(
70
70
  0,
71
71
  Math.min(popupData.x, totalWidth - (popupStyle?.width ?? 0)) +
72
- viewOffset.x
72
+ viewOffset.x
73
73
  ),
74
74
  top: Math.max(
75
75
  0,
@@ -78,8 +78,10 @@ export default function Popup<T>({
78
78
  totalHeight - (popupStyle?.height ?? 0)
79
79
  ) + viewOffset.y
80
80
  ),
81
- },
82
- ]}
81
+ width: popupStyle.width,
82
+ height: popupStyle.height
83
+ }
84
+ }
83
85
  onTouchStart={(e) => e.stopPropagation()}
84
86
  >
85
87
  {popupStyle?.renderPopup(popupData.data)}
@@ -88,34 +90,34 @@ export default function Popup<T>({
88
90
 
89
91
  {popupData &&
90
92
  Array.isArray(popupData) &&
91
- popupData.map((popupItem, index) =>
92
- (
93
- <View
94
- key={index}
95
- style={[
96
- {
97
- position: 'absolute',
98
- left: Math.max(
99
- 0,
100
- Math.min(
101
- popupItem.x,
102
- totalWidth - (popupStyle?.width ?? 0)
103
- ) + viewOffset.x
104
- ),
105
- top: Math.max(
106
- 0,
107
- Math.min(
108
- popupItem.y,
109
- totalHeight - (popupStyle?.height ?? 0)
110
- ) + viewOffset.y
111
- ),
112
- },
113
- ]}
114
- onTouchStart={(e) => e.stopPropagation()}
115
- >
116
- {popupStyle?.renderPopup?.(popupItem.data)}
117
- </View>
118
- )
93
+ popupData.map((popupItem, index) =>
94
+ (
95
+ <View
96
+ key={index}
97
+ style={
98
+ {
99
+ position: 'absolute',
100
+ left: Math.max(
101
+ 0,
102
+ Math.min(
103
+ popupItem.x,
104
+ totalWidth - (popupStyle?.width ?? 0)
105
+ ) + viewOffset.x
106
+ ),
107
+ top: Math.max(
108
+ 0,
109
+ Math.min(
110
+ popupItem.y,
111
+ totalHeight - (popupStyle?.height ?? 0)
112
+ ) + viewOffset.y
113
+ ),
114
+ }
115
+ }
116
+ onTouchStart={(e) => e.stopPropagation()}
117
+ >
118
+ {popupStyle?.renderPopup?.(popupItem.data)}
119
+ </View>
120
+ )
119
121
  )}
120
122
  </View>
121
123
  </Modal>
@@ -1,5 +1,4 @@
1
- import { listFontFamilies, matchFont, Skia, TextAlign, type SkFont, type SkParagraph, type SkTextStyle } from "@shopify/react-native-skia";
2
- import { Platform } from "react-native";
1
+ import { I18nManager } from "react-native";
3
2
 
4
3
  export interface CommonStyle {
5
4
  padding?: number;
@@ -11,21 +10,15 @@ export interface CommonStyle {
11
10
  paddingRight?: number;
12
11
  backgroundColor?: string;
13
12
  disableRTL?: boolean;
14
- font?: SkFont;
15
- fontSize?: number;
16
- }
17
-
18
- export function getCommonStyleFont(style?: CommonStyle) {
19
- const fontSize = style?.font?.getSize() ?? style?.fontSize ?? 12;
20
- const font = style?.font ?? getFont(fontSize);
21
- return { font, fontSize };
22
13
  }
23
14
 
24
15
  export function getPaddings(style?: CommonStyle) {
25
16
  const paddingTop = style?.paddingTop ?? style?.padding ?? 0;
26
17
  const paddingBottom = style?.paddingBottom ?? style?.padding ?? 0;
27
- const paddingLeft = style?.paddingLeft ?? style?.paddingStart ?? style?.padding ?? 0;
28
- const paddingRight = style?.paddingRight ?? style?.paddingEnd ?? style?.padding ?? 0;
18
+ const isRTL = I18nManager.isRTL && !(style?.disableRTL ?? false)
19
+
20
+ const paddingLeft = style?.paddingLeft ?? (isRTL ? style?.paddingEnd : style?.paddingStart) ?? style?.padding ?? 0;
21
+ const paddingRight = style?.paddingRight ?? (isRTL ? style?.paddingStart : style?.paddingEnd) ?? style?.padding ?? 0;
29
22
  const paddingHorizontal = paddingLeft + paddingRight;
30
23
  const paddingVertical = paddingTop + paddingBottom;
31
24
 
@@ -46,37 +39,6 @@ export function getRandomRGBColor() {
46
39
  return `rgb(${r},${g},${b})`;
47
40
  };
48
41
 
49
- export const systemFontFamilies = Platform.select({
50
- ios: ["Helvetica", "Arial", "Courier"],
51
- android: ["roboto-flex", "sans-serif", "Roboto", "serif", "monospace"],
52
- default: ["sans-serif", "serif"],
53
- });
54
-
55
- export function getFont(size: number = 14): SkFont {
56
- const fontFamily = systemFontFamilies[0];
57
- // console.log("Available system font families:", listFontFamilies());
58
- // console.log("Using font family:", fontFamily, systemFontFamilies);
59
- const font = matchFont({
60
- fontFamily,
61
- fontSize: size,
62
- fontStyle: "normal",
63
- fontWeight: "normal",
64
- });
65
- return font;
66
- }
67
-
68
- export const font = getFont();
69
-
70
- function createParagraph(text: string): SkParagraph {
71
- const paragraphStyle = {
72
- textAlign: TextAlign.Center,
73
- };
74
-
75
- const fontStyle: SkTextStyle = {
76
- fontFamilies: systemFontFamilies,
77
- fontSize: 14,
78
- };
79
- const paragraph = Skia.ParagraphBuilder.Make(paragraphStyle).pushStyle(fontStyle).addText(text).pop().build();
80
-
81
- return paragraph;
82
- }
42
+ export interface HandleOutSideTouch {
43
+ touchedOutside: () => void;
44
+ }
@@ -1,73 +0,0 @@
1
- "use strict";
2
-
3
- import { Canvas, Line, Text, Skia } from '@shopify/react-native-skia';
4
- import { getFont } from "../common.js";
5
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
6
- function VerticalLabel({
7
- minValue,
8
- maxValue,
9
- labelCount,
10
- styles
11
- }) {
12
- const {
13
- width,
14
- height,
15
- strokeWidth = 2,
16
- strokeColor = 'white',
17
- textColor = 'white',
18
- paddingTop = 0,
19
- paddingRight = 0,
20
- paddingBottom = 0,
21
- paddingLeft = 0,
22
- fontSize = 12,
23
- backgroundColor
24
- } = styles;
25
-
26
- // Generate evenly spaced values
27
- const stepValue = labelCount > 1 ? (maxValue - minValue) / (labelCount - 1) : 0;
28
- const labels = Array.from({
29
- length: labelCount
30
- }, (_, i) => minValue + i * stepValue);
31
- const font = getFont(fontSize);
32
- const usableHeight = height - paddingTop - paddingBottom - fontSize;
33
- const stepY = labelCount > 1 ? usableHeight / (labelCount - 1) : 0;
34
-
35
- // Precompute text paint
36
- const paint = Skia.Paint();
37
- paint.setColor(Skia.Color(textColor));
38
- return /*#__PURE__*/_jsxs(Canvas, {
39
- style: {
40
- width,
41
- height,
42
- backgroundColor
43
- },
44
- children: [/*#__PURE__*/_jsx(Line, {
45
- p1: {
46
- x: width - paddingRight - strokeWidth / 2,
47
- y: paddingTop
48
- },
49
- p2: {
50
- x: width - paddingRight - strokeWidth / 2,
51
- y: height - paddingBottom
52
- },
53
- color: strokeColor,
54
- strokeWidth: strokeWidth
55
- }), labels.map((label, i) => {
56
- const y = height - paddingBottom - stepY * i;
57
- const text = label.toFixed(0);
58
-
59
- // measure text width for right-align
60
- const textWidth = font.measureText(text).width;
61
- const x = width - paddingRight - strokeWidth - 4 - textWidth;
62
- return /*#__PURE__*/_jsx(Text, {
63
- x: x,
64
- y: y,
65
- text: text,
66
- font: font,
67
- color: textColor
68
- }, i);
69
- })]
70
- });
71
- }
72
- export default VerticalLabel;
73
- //# sourceMappingURL=VerticalLabel.js.map
@@ -1 +0,0 @@
1
- {"version":3,"names":["Canvas","Line","Text","Skia","getFont","jsx","_jsx","jsxs","_jsxs","VerticalLabel","minValue","maxValue","labelCount","styles","width","height","strokeWidth","strokeColor","textColor","paddingTop","paddingRight","paddingBottom","paddingLeft","fontSize","backgroundColor","stepValue","labels","Array","from","length","_","i","font","usableHeight","stepY","paint","Paint","setColor","Color","style","children","p1","x","y","p2","color","map","label","text","toFixed","textWidth","measureText"],"sourceRoot":"../../../../src","sources":["skia/Common/VerticalLabel.tsx"],"mappings":";;AAAA,SAASA,MAAM,EAAEC,IAAI,EAAEC,IAAI,EAAEC,IAAI,QAAQ,4BAA4B;AACrE,SAASC,OAAO,QAA0B,cAAW;AAAC,SAAAC,GAAA,IAAAC,IAAA,EAAAC,IAAA,IAAAC,KAAA;AAiBtD,SAASC,aAAaA,CAAC;EACrBC,QAAQ;EACRC,QAAQ;EACRC,UAAU;EACVC;AACkB,CAAC,EAAE;EACrB,MAAM;IACJC,KAAK;IACLC,MAAM;IACNC,WAAW,GAAG,CAAC;IACfC,WAAW,GAAG,OAAO;IACrBC,SAAS,GAAG,OAAO;IACnBC,UAAU,GAAG,CAAC;IACdC,YAAY,GAAG,CAAC;IAChBC,aAAa,GAAG,CAAC;IACjBC,WAAW,GAAG,CAAC;IACfC,QAAQ,GAAG,EAAE;IACbC;EACF,CAAC,GAAGX,MAAM;;EAEV;EACA,MAAMY,SAAS,GACbb,UAAU,GAAG,CAAC,GAAG,CAACD,QAAQ,GAAGD,QAAQ,KAAKE,UAAU,GAAG,CAAC,CAAC,GAAG,CAAC;EAC/D,MAAMc,MAAM,GAAGC,KAAK,CAACC,IAAI,CACvB;IAAEC,MAAM,EAAEjB;EAAW,CAAC,EACtB,CAACkB,CAAC,EAAEC,CAAC,KAAKrB,QAAQ,GAAGqB,CAAC,GAAGN,SAC3B,CAAC;EAED,MAAMO,IAAI,GAAG5B,OAAO,CAACmB,QAAQ,CAAC;EAE9B,MAAMU,YAAY,GAAGlB,MAAM,GAAGI,UAAU,GAAGE,aAAa,GAAGE,QAAQ;EACnE,MAAMW,KAAK,GAAGtB,UAAU,GAAG,CAAC,GAAGqB,YAAY,IAAIrB,UAAU,GAAG,CAAC,CAAC,GAAG,CAAC;;EAElE;EACA,MAAMuB,KAAK,GAAGhC,IAAI,CAACiC,KAAK,CAAC,CAAC;EAC1BD,KAAK,CAACE,QAAQ,CAAClC,IAAI,CAACmC,KAAK,CAACpB,SAAS,CAAC,CAAC;EAErC,oBACEV,KAAA,CAACR,MAAM;IAACuC,KAAK,EAAE;MAAEzB,KAAK;MAAEC,MAAM;MAAES;IAAgB,CAAE;IAAAgB,QAAA,gBAChDlC,IAAA,CAACL,IAAI;MACHwC,EAAE,EAAE;QAAEC,CAAC,EAAE5B,KAAK,GAAGM,YAAY,GAAGJ,WAAW,GAAG,CAAC;QAAE2B,CAAC,EAAExB;MAAW,CAAE;MACjEyB,EAAE,EAAE;QACFF,CAAC,EAAE5B,KAAK,GAAGM,YAAY,GAAGJ,WAAW,GAAG,CAAC;QACzC2B,CAAC,EAAE5B,MAAM,GAAGM;MACd,CAAE;MACFwB,KAAK,EAAE5B,WAAY;MACnBD,WAAW,EAAEA;IAAY,CAC1B,CAAC,EAEDU,MAAM,CAACoB,GAAG,CAAC,CAACC,KAAK,EAAEhB,CAAC,KAAK;MACxB,MAAMY,CAAC,GAAG5B,MAAM,GAAGM,aAAa,GAAGa,KAAK,GAAGH,CAAC;MAC5C,MAAMiB,IAAI,GAAGD,KAAK,CAACE,OAAO,CAAC,CAAC,CAAC;;MAE7B;MACA,MAAMC,SAAS,GAAGlB,IAAI,CAACmB,WAAW,CAACH,IAAI,CAAC,CAAClC,KAAK;MAC9C,MAAM4B,CAAC,GAAG5B,KAAK,GAAGM,YAAY,GAAGJ,WAAW,GAAG,CAAC,GAAGkC,SAAS;MAE5D,oBACE5C,IAAA,CAACJ,IAAI;QAEHwC,CAAC,EAAEA,CAAE;QACLC,CAAC,EAAEA,CAAE;QACLK,IAAI,EAAEA,IAAK;QACXhB,IAAI,EAAEA,IAAK;QACXa,KAAK,EAAE3B;MAAU,GALZa,CAMN,CAAC;IAEN,CAAC,CAAC;EAAA,CACI,CAAC;AAEb;AAEA,eAAetB,aAAa","ignoreList":[]}