@jiujue/react-canvas-fiber 2.1.2 → 2.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/dist/index.d.cts CHANGED
@@ -137,6 +137,72 @@ type RectProps = {
137
137
  onPointerEnter?: CanvasPointerEventHandler;
138
138
  onPointerLeave?: CanvasPointerEventHandler;
139
139
  };
140
+ type CircleProps = {
141
+ children?: ReactNode;
142
+ style?: YogaStyle;
143
+ fill?: string;
144
+ stroke?: string;
145
+ lineWidth?: number;
146
+ pointerEvents?: PointerEventsMode;
147
+ onPointerDownCapture?: CanvasPointerEventHandler;
148
+ onPointerDown?: CanvasPointerEventHandler;
149
+ onPointerMoveCapture?: CanvasPointerEventHandler;
150
+ onPointerMove?: CanvasPointerEventHandler;
151
+ onPointerUpCapture?: CanvasPointerEventHandler;
152
+ onPointerUp?: CanvasPointerEventHandler;
153
+ onPointerCancelCapture?: CanvasPointerEventHandler;
154
+ onPointerCancel?: CanvasPointerEventHandler;
155
+ onClickCapture?: CanvasPointerEventHandler;
156
+ onClick?: CanvasPointerEventHandler;
157
+ onPointerEnter?: CanvasPointerEventHandler;
158
+ onPointerLeave?: CanvasPointerEventHandler;
159
+ };
160
+ type PathProps = {
161
+ children?: ReactNode;
162
+ style?: YogaStyle;
163
+ d: string;
164
+ fill?: string;
165
+ fillRule?: CanvasFillRule;
166
+ stroke?: string;
167
+ lineWidth?: number;
168
+ pointerEvents?: PointerEventsMode;
169
+ onPointerDownCapture?: CanvasPointerEventHandler;
170
+ onPointerDown?: CanvasPointerEventHandler;
171
+ onPointerMoveCapture?: CanvasPointerEventHandler;
172
+ onPointerMove?: CanvasPointerEventHandler;
173
+ onPointerUpCapture?: CanvasPointerEventHandler;
174
+ onPointerUp?: CanvasPointerEventHandler;
175
+ onPointerCancelCapture?: CanvasPointerEventHandler;
176
+ onPointerCancel?: CanvasPointerEventHandler;
177
+ onClickCapture?: CanvasPointerEventHandler;
178
+ onClick?: CanvasPointerEventHandler;
179
+ onPointerEnter?: CanvasPointerEventHandler;
180
+ onPointerLeave?: CanvasPointerEventHandler;
181
+ };
182
+ type LineProps = {
183
+ children?: ReactNode;
184
+ style?: YogaStyle;
185
+ x1?: number;
186
+ y1?: number;
187
+ x2?: number;
188
+ y2?: number;
189
+ stroke?: string;
190
+ lineWidth?: number;
191
+ lineCap?: CanvasLineCap;
192
+ pointerEvents?: PointerEventsMode;
193
+ onPointerDownCapture?: CanvasPointerEventHandler;
194
+ onPointerDown?: CanvasPointerEventHandler;
195
+ onPointerMoveCapture?: CanvasPointerEventHandler;
196
+ onPointerMove?: CanvasPointerEventHandler;
197
+ onPointerUpCapture?: CanvasPointerEventHandler;
198
+ onPointerUp?: CanvasPointerEventHandler;
199
+ onPointerCancelCapture?: CanvasPointerEventHandler;
200
+ onPointerCancel?: CanvasPointerEventHandler;
201
+ onClickCapture?: CanvasPointerEventHandler;
202
+ onClick?: CanvasPointerEventHandler;
203
+ onPointerEnter?: CanvasPointerEventHandler;
204
+ onPointerLeave?: CanvasPointerEventHandler;
205
+ };
140
206
  type TextProps = {
141
207
  children?: never;
142
208
  text: string;
@@ -192,12 +258,18 @@ declare function Canvas(props: CanvasProps): react_jsx_runtime.JSX.Element;
192
258
  * 它们返回 intrinsic element(字符串 type),由自定义 reconciler 接管创建/更新节点:
193
259
  * - <View/> -> CanvasNode(type='View')
194
260
  * - <Rect/> -> CanvasNode(type='Rect')
261
+ * - <Circle/> -> CanvasNode(type='Circle')
262
+ * - <Path/> -> CanvasNode(type='Path')
263
+ * - <Line/> -> CanvasNode(type='Line')
195
264
  * - <Text/> -> CanvasNode(type='Text')
196
265
  * - <Image/> -> CanvasNode(type='Image')
197
266
  */
198
267
  declare function View(props: ViewProps): react.ReactElement<ViewProps, string | react.JSXElementConstructor<any>>;
199
268
  declare function Rect(props: RectProps): react.ReactElement<RectProps, string | react.JSXElementConstructor<any>>;
269
+ declare function Circle(props: CircleProps): react.ReactElement<CircleProps, string | react.JSXElementConstructor<any>>;
270
+ declare function Path(props: PathProps): react.ReactElement<PathProps, string | react.JSXElementConstructor<any>>;
271
+ declare function Line(props: LineProps): react.ReactElement<LineProps, string | react.JSXElementConstructor<any>>;
200
272
  declare function Text(props: TextProps): react.ReactElement<TextProps, string | react.JSXElementConstructor<any>>;
201
273
  declare function Image(props: ImageProps): react.ReactElement<ImageProps, string | react.JSXElementConstructor<any>>;
202
274
 
203
- export { Canvas, Image, Rect, Text, View };
275
+ export { Canvas, Circle, Image, Line, Path, Rect, Text, View };
package/dist/index.d.ts CHANGED
@@ -137,6 +137,72 @@ type RectProps = {
137
137
  onPointerEnter?: CanvasPointerEventHandler;
138
138
  onPointerLeave?: CanvasPointerEventHandler;
139
139
  };
140
+ type CircleProps = {
141
+ children?: ReactNode;
142
+ style?: YogaStyle;
143
+ fill?: string;
144
+ stroke?: string;
145
+ lineWidth?: number;
146
+ pointerEvents?: PointerEventsMode;
147
+ onPointerDownCapture?: CanvasPointerEventHandler;
148
+ onPointerDown?: CanvasPointerEventHandler;
149
+ onPointerMoveCapture?: CanvasPointerEventHandler;
150
+ onPointerMove?: CanvasPointerEventHandler;
151
+ onPointerUpCapture?: CanvasPointerEventHandler;
152
+ onPointerUp?: CanvasPointerEventHandler;
153
+ onPointerCancelCapture?: CanvasPointerEventHandler;
154
+ onPointerCancel?: CanvasPointerEventHandler;
155
+ onClickCapture?: CanvasPointerEventHandler;
156
+ onClick?: CanvasPointerEventHandler;
157
+ onPointerEnter?: CanvasPointerEventHandler;
158
+ onPointerLeave?: CanvasPointerEventHandler;
159
+ };
160
+ type PathProps = {
161
+ children?: ReactNode;
162
+ style?: YogaStyle;
163
+ d: string;
164
+ fill?: string;
165
+ fillRule?: CanvasFillRule;
166
+ stroke?: string;
167
+ lineWidth?: number;
168
+ pointerEvents?: PointerEventsMode;
169
+ onPointerDownCapture?: CanvasPointerEventHandler;
170
+ onPointerDown?: CanvasPointerEventHandler;
171
+ onPointerMoveCapture?: CanvasPointerEventHandler;
172
+ onPointerMove?: CanvasPointerEventHandler;
173
+ onPointerUpCapture?: CanvasPointerEventHandler;
174
+ onPointerUp?: CanvasPointerEventHandler;
175
+ onPointerCancelCapture?: CanvasPointerEventHandler;
176
+ onPointerCancel?: CanvasPointerEventHandler;
177
+ onClickCapture?: CanvasPointerEventHandler;
178
+ onClick?: CanvasPointerEventHandler;
179
+ onPointerEnter?: CanvasPointerEventHandler;
180
+ onPointerLeave?: CanvasPointerEventHandler;
181
+ };
182
+ type LineProps = {
183
+ children?: ReactNode;
184
+ style?: YogaStyle;
185
+ x1?: number;
186
+ y1?: number;
187
+ x2?: number;
188
+ y2?: number;
189
+ stroke?: string;
190
+ lineWidth?: number;
191
+ lineCap?: CanvasLineCap;
192
+ pointerEvents?: PointerEventsMode;
193
+ onPointerDownCapture?: CanvasPointerEventHandler;
194
+ onPointerDown?: CanvasPointerEventHandler;
195
+ onPointerMoveCapture?: CanvasPointerEventHandler;
196
+ onPointerMove?: CanvasPointerEventHandler;
197
+ onPointerUpCapture?: CanvasPointerEventHandler;
198
+ onPointerUp?: CanvasPointerEventHandler;
199
+ onPointerCancelCapture?: CanvasPointerEventHandler;
200
+ onPointerCancel?: CanvasPointerEventHandler;
201
+ onClickCapture?: CanvasPointerEventHandler;
202
+ onClick?: CanvasPointerEventHandler;
203
+ onPointerEnter?: CanvasPointerEventHandler;
204
+ onPointerLeave?: CanvasPointerEventHandler;
205
+ };
140
206
  type TextProps = {
141
207
  children?: never;
142
208
  text: string;
@@ -192,12 +258,18 @@ declare function Canvas(props: CanvasProps): react_jsx_runtime.JSX.Element;
192
258
  * 它们返回 intrinsic element(字符串 type),由自定义 reconciler 接管创建/更新节点:
193
259
  * - <View/> -> CanvasNode(type='View')
194
260
  * - <Rect/> -> CanvasNode(type='Rect')
261
+ * - <Circle/> -> CanvasNode(type='Circle')
262
+ * - <Path/> -> CanvasNode(type='Path')
263
+ * - <Line/> -> CanvasNode(type='Line')
195
264
  * - <Text/> -> CanvasNode(type='Text')
196
265
  * - <Image/> -> CanvasNode(type='Image')
197
266
  */
198
267
  declare function View(props: ViewProps): react.ReactElement<ViewProps, string | react.JSXElementConstructor<any>>;
199
268
  declare function Rect(props: RectProps): react.ReactElement<RectProps, string | react.JSXElementConstructor<any>>;
269
+ declare function Circle(props: CircleProps): react.ReactElement<CircleProps, string | react.JSXElementConstructor<any>>;
270
+ declare function Path(props: PathProps): react.ReactElement<PathProps, string | react.JSXElementConstructor<any>>;
271
+ declare function Line(props: LineProps): react.ReactElement<LineProps, string | react.JSXElementConstructor<any>>;
200
272
  declare function Text(props: TextProps): react.ReactElement<TextProps, string | react.JSXElementConstructor<any>>;
201
273
  declare function Image(props: ImageProps): react.ReactElement<ImageProps, string | react.JSXElementConstructor<any>>;
202
274
 
203
- export { Canvas, Image, Rect, Text, View };
275
+ export { Canvas, Circle, Image, Line, Path, Rect, Text, View };
package/dist/index.js CHANGED
@@ -44,10 +44,92 @@ function createNode(type, props) {
44
44
  node.imageInstance = null;
45
45
  } else if (type === "View") {
46
46
  node.backgroundImageInstance = null;
47
+ } else if (type === "Path") {
48
+ node.path2d = null;
49
+ node.pathSource = null;
47
50
  }
48
51
  return node;
49
52
  }
50
53
 
54
+ // src/utils/style.ts
55
+ function normalizeInsets(style) {
56
+ const paddingHorizontal = style?.paddingHorizontal ?? style?.padding ?? 0;
57
+ const paddingVertical = style?.paddingVertical ?? style?.padding ?? 0;
58
+ const marginHorizontal = style?.marginHorizontal ?? style?.margin ?? 0;
59
+ const marginVertical = style?.marginVertical ?? style?.margin ?? 0;
60
+ return {
61
+ paddingTop: style?.paddingTop ?? paddingVertical,
62
+ paddingRight: style?.paddingRight ?? paddingHorizontal,
63
+ paddingBottom: style?.paddingBottom ?? paddingVertical,
64
+ paddingLeft: style?.paddingLeft ?? paddingHorizontal,
65
+ marginTop: style?.marginTop ?? marginVertical,
66
+ marginRight: style?.marginRight ?? marginHorizontal,
67
+ marginBottom: style?.marginBottom ?? marginVertical,
68
+ marginLeft: style?.marginLeft ?? marginHorizontal
69
+ };
70
+ }
71
+
72
+ // src/utils/path2d.ts
73
+ function resolvePath2D(node) {
74
+ const d = node.props?.d;
75
+ if (typeof d !== "string" || !d.trim()) {
76
+ node.path2d = null;
77
+ node.pathSource = null;
78
+ return null;
79
+ }
80
+ if (node.pathSource === d && node.path2d) return node.path2d;
81
+ try {
82
+ const path = new Path2D(d);
83
+ node.path2d = path;
84
+ node.pathSource = d;
85
+ return path;
86
+ } catch {
87
+ node.path2d = null;
88
+ node.pathSource = d;
89
+ return null;
90
+ }
91
+ }
92
+
93
+ // src/render/drawPrimitives.ts
94
+ function drawPathNode(ctx, node, x, y) {
95
+ const path = resolvePath2D(node);
96
+ if (!path) return;
97
+ const fill = node.props.fill ?? "#ffffff";
98
+ const fillRule = node.props.fillRule;
99
+ const stroke = node.props.stroke;
100
+ const lineWidth = node.props.lineWidth ?? 1;
101
+ ctx.save();
102
+ ctx.translate(x, y);
103
+ if (fill) {
104
+ ctx.fillStyle = fill;
105
+ ctx.fill(path, fillRule);
106
+ }
107
+ if (stroke) {
108
+ ctx.strokeStyle = stroke;
109
+ ctx.lineWidth = lineWidth;
110
+ ctx.stroke(path);
111
+ }
112
+ ctx.restore();
113
+ }
114
+ function drawLineNode(ctx, node, x, y, w, h) {
115
+ const stroke = node.props.stroke ?? "#ffffff";
116
+ const lineWidth = node.props.lineWidth ?? 1;
117
+ const lineCap = node.props.lineCap;
118
+ const x1 = node.props.x1 ?? 0;
119
+ const y1 = node.props.y1 ?? 0;
120
+ const x2 = node.props.x2 ?? w;
121
+ const y2 = node.props.y2 ?? h;
122
+ ctx.save();
123
+ ctx.beginPath();
124
+ ctx.moveTo(x + x1, y + y1);
125
+ ctx.lineTo(x + x2, y + y2);
126
+ ctx.strokeStyle = stroke;
127
+ ctx.lineWidth = lineWidth;
128
+ if (lineCap) ctx.lineCap = lineCap;
129
+ ctx.stroke();
130
+ ctx.restore();
131
+ }
132
+
51
133
  // src/render/drawTree.ts
52
134
  function resolveInheritedTextStyle(node, defaults) {
53
135
  const own = node.props?.style ?? {};
@@ -364,6 +446,36 @@ function drawNode(state, node, offsetX, offsetY) {
364
446
  }
365
447
  ctx.restore();
366
448
  }
449
+ if (node.type === "Circle") {
450
+ const fill = node.props.fill ?? "#ffffff";
451
+ const stroke = node.props.stroke;
452
+ const lineWidth = node.props.lineWidth ?? 1;
453
+ if (w > 0 && h > 0) {
454
+ const cx = x + w / 2;
455
+ const cy = y + h / 2;
456
+ const rx = w / 2;
457
+ const ry = h / 2;
458
+ ctx.save();
459
+ ctx.beginPath();
460
+ ctx.ellipse(cx, cy, rx, ry, 0, 0, Math.PI * 2);
461
+ if (fill) {
462
+ ctx.fillStyle = fill;
463
+ ctx.fill();
464
+ }
465
+ if (stroke) {
466
+ ctx.strokeStyle = stroke;
467
+ ctx.lineWidth = lineWidth;
468
+ ctx.stroke();
469
+ }
470
+ ctx.restore();
471
+ }
472
+ }
473
+ if (node.type === "Path") {
474
+ drawPathNode(ctx, node, x, y);
475
+ }
476
+ if (node.type === "Line") {
477
+ drawLineNode(ctx, node, x, y, w, h);
478
+ }
367
479
  if (node.type === "Text") {
368
480
  const text = node.props.text;
369
481
  const color = node.props.color ?? "#ffffff";
@@ -442,26 +554,6 @@ function drawTree(root, ctx, dpr, clearColor, defaults) {
442
554
  }
443
555
  ctx.restore();
444
556
  }
445
-
446
- // src/utils/style.ts
447
- function normalizeInsets(style) {
448
- const paddingHorizontal = style?.paddingHorizontal ?? style?.padding ?? 0;
449
- const paddingVertical = style?.paddingVertical ?? style?.padding ?? 0;
450
- const marginHorizontal = style?.marginHorizontal ?? style?.margin ?? 0;
451
- const marginVertical = style?.marginVertical ?? style?.margin ?? 0;
452
- return {
453
- paddingTop: style?.paddingTop ?? paddingVertical,
454
- paddingRight: style?.paddingRight ?? paddingHorizontal,
455
- paddingBottom: style?.paddingBottom ?? paddingVertical,
456
- paddingLeft: style?.paddingLeft ?? paddingHorizontal,
457
- marginTop: style?.marginTop ?? marginVertical,
458
- marginRight: style?.marginRight ?? marginHorizontal,
459
- marginBottom: style?.marginBottom ?? marginVertical,
460
- marginLeft: style?.marginLeft ?? marginHorizontal
461
- };
462
- }
463
-
464
- // src/layout/layoutTree.ts
465
557
  var layoutEnginePromise = null;
466
558
  function getLayoutEngine() {
467
559
  if (!layoutEnginePromise) {
@@ -928,6 +1020,38 @@ function createReconcilerRoot(container) {
928
1020
  };
929
1021
  }
930
1022
 
1023
+ // src/runtime/hitTestPrimitives.ts
1024
+ function hitTestEllipse(x, y, left, top, width, height) {
1025
+ const rx = width / 2;
1026
+ const ry = height / 2;
1027
+ if (rx <= 0 || ry <= 0) return false;
1028
+ const cx = left + rx;
1029
+ const cy = top + ry;
1030
+ const dx = (x - cx) / rx;
1031
+ const dy = (y - cy) / ry;
1032
+ return dx * dx + dy * dy <= 1;
1033
+ }
1034
+ function hitTestLineSegment(x, y, ax, ay, bx, by, threshold) {
1035
+ const abx = bx - ax;
1036
+ const aby = by - ay;
1037
+ const apx = x - ax;
1038
+ const apy = y - ay;
1039
+ const abLenSq = abx * abx + aby * aby;
1040
+ if (abLenSq <= 1e-9) {
1041
+ const dx2 = x - ax;
1042
+ const dy2 = y - ay;
1043
+ return dx2 * dx2 + dy2 * dy2 <= threshold * threshold;
1044
+ }
1045
+ let t = (apx * abx + apy * aby) / abLenSq;
1046
+ if (t < 0) t = 0;
1047
+ else if (t > 1) t = 1;
1048
+ const px = ax + t * abx;
1049
+ const py = ay + t * aby;
1050
+ const dx = x - px;
1051
+ const dy = y - py;
1052
+ return dx * dx + dy * dy <= threshold * threshold;
1053
+ }
1054
+
931
1055
  // src/runtime/root.ts
932
1056
  function createCanvasRoot(canvas, options) {
933
1057
  const ctx = canvas.getContext("2d");
@@ -1213,6 +1337,37 @@ function createCanvasRoot(canvas, options) {
1213
1337
  const hit = hitTestNode(child, x, y, childOffsetX, childOffsetY);
1214
1338
  if (hit) return hit;
1215
1339
  }
1340
+ if (node.type === "Circle") {
1341
+ const ok = hitTestEllipse(x, y, left, top, node.layout.width, node.layout.height);
1342
+ if (!ok) return null;
1343
+ }
1344
+ if (node.type === "Line") {
1345
+ const w = node.layout.width;
1346
+ const h = node.layout.height;
1347
+ const x1 = node.props.x1 ?? 0;
1348
+ const y1 = node.props.y1 ?? 0;
1349
+ const x2 = node.props.x2 ?? w;
1350
+ const y2 = node.props.y2 ?? h;
1351
+ const lineWidth = node.props.lineWidth ?? 1;
1352
+ const threshold = Math.max(1, lineWidth / 2);
1353
+ const ok = hitTestLineSegment(x, y, left + x1, top + y1, left + x2, top + y2, threshold);
1354
+ if (!ok) return null;
1355
+ }
1356
+ if (node.type === "Path") {
1357
+ const path = resolvePath2D(node);
1358
+ if (!path) return null;
1359
+ const fillRule = node.props.fillRule;
1360
+ const stroke = node.props.stroke;
1361
+ const lineWidth = node.props.lineWidth ?? 1;
1362
+ ctx.save();
1363
+ ctx.setTransform(1, 0, 0, 1, 0, 0);
1364
+ ctx.translate(left, top);
1365
+ ctx.lineWidth = lineWidth;
1366
+ const inFill = ctx.isPointInPath(path, x, y, fillRule);
1367
+ const inStroke = stroke ? ctx.isPointInStroke(path, x, y) : false;
1368
+ ctx.restore();
1369
+ if (!inFill && !inStroke) return null;
1370
+ }
1216
1371
  return node;
1217
1372
  };
1218
1373
  const hitTestScrollbarThumbNode = (node, x, y, offsetX, offsetY) => {
@@ -1891,6 +2046,15 @@ function View(props) {
1891
2046
  function Rect(props) {
1892
2047
  return createElement("Rect", props);
1893
2048
  }
2049
+ function Circle(props) {
2050
+ return createElement("Circle", props);
2051
+ }
2052
+ function Path(props) {
2053
+ return createElement("Path", props);
2054
+ }
2055
+ function Line(props) {
2056
+ return createElement("Line", props);
2057
+ }
1894
2058
  function Text(props) {
1895
2059
  return createElement("Text", props);
1896
2060
  }
@@ -1898,6 +2062,6 @@ function Image2(props) {
1898
2062
  return createElement("Image", props);
1899
2063
  }
1900
2064
 
1901
- export { Canvas, Image2 as Image, Rect, Text, View };
2065
+ export { Canvas, Circle, Image2 as Image, Line, Path, Rect, Text, View };
1902
2066
  //# sourceMappingURL=index.js.map
1903
2067
  //# sourceMappingURL=index.js.map