@edadma/logo 0.2.3 → 0.2.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.
- package/dist/main.js +13597 -13439
- package/dist/main.js.map +4 -4
- package/package.json +5 -25
- package/src/main/scala/io/github/edadma/logo/LogoJS.scala +106 -24
- package/dist/react/LogoCanvas.js +0 -74
- package/dist/react/index.js +0 -2
- package/react/LogoCanvas.tsx +0 -174
- package/react/index.ts +0 -2
package/package.json
CHANGED
|
@@ -1,29 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@edadma/logo",
|
|
3
|
-
"version": "0.2.
|
|
4
|
-
"description": "Logo programming language interpreter
|
|
3
|
+
"version": "0.2.5",
|
|
4
|
+
"description": "Logo programming language interpreter",
|
|
5
5
|
"main": "dist/main.js",
|
|
6
6
|
"module": "dist/main.js",
|
|
7
7
|
"types": "src/index.d.ts",
|
|
8
8
|
"files": [
|
|
9
9
|
"dist",
|
|
10
|
-
"src"
|
|
11
|
-
"react"
|
|
10
|
+
"src"
|
|
12
11
|
],
|
|
13
12
|
"exports": {
|
|
14
13
|
".": {
|
|
15
14
|
"import": "./dist/main.js",
|
|
16
15
|
"types": "./src/index.d.ts"
|
|
17
|
-
},
|
|
18
|
-
"./react": {
|
|
19
|
-
"import": "./react/index.ts",
|
|
20
|
-
"types": "./react/index.ts"
|
|
21
16
|
}
|
|
22
17
|
},
|
|
23
18
|
"scripts": {
|
|
24
|
-
"build": "
|
|
25
|
-
"build:scala": "cd .. && sbt logoJS/fullLinkJS && cp js/target/scala-3.7.4/logo-opt/main.js js/target/scala-3.7.4/logo-opt/main.js.map js/dist/",
|
|
26
|
-
"build:react": "tsc --project tsconfig.react.json",
|
|
19
|
+
"build": "cd .. && sbt logoJS/fullLinkJS && cp js/target/scala-3.7.4/logo-opt/main.js js/target/scala-3.7.4/logo-opt/main.js.map js/dist/",
|
|
27
20
|
"prepublishOnly": "npm run build"
|
|
28
21
|
},
|
|
29
22
|
"keywords": [
|
|
@@ -32,7 +25,6 @@
|
|
|
32
25
|
"turtle",
|
|
33
26
|
"graphics",
|
|
34
27
|
"education",
|
|
35
|
-
"react",
|
|
36
28
|
"canvas"
|
|
37
29
|
],
|
|
38
30
|
"author": "Edward A. Maxedon, Sr.",
|
|
@@ -44,17 +36,5 @@
|
|
|
44
36
|
"bugs": {
|
|
45
37
|
"url": "https://github.com/edadma/logo/issues"
|
|
46
38
|
},
|
|
47
|
-
"homepage": "https://github.com/edadma/logo#readme"
|
|
48
|
-
"peerDependencies": {
|
|
49
|
-
"react": ">=17.0.0"
|
|
50
|
-
},
|
|
51
|
-
"peerDependenciesMeta": {
|
|
52
|
-
"react": {
|
|
53
|
-
"optional": true
|
|
54
|
-
}
|
|
55
|
-
},
|
|
56
|
-
"devDependencies": {
|
|
57
|
-
"@types/react": "^18.2.0",
|
|
58
|
-
"typescript": "^5.0.0"
|
|
59
|
-
}
|
|
39
|
+
"homepage": "https://github.com/edadma/logo#readme"
|
|
60
40
|
}
|
|
@@ -57,6 +57,7 @@ class LogoJS(canvas: html.Canvas) extends js.Object:
|
|
|
57
57
|
private var autoRender: Boolean = true
|
|
58
58
|
private var initialized: Boolean = false
|
|
59
59
|
private var backgroundColor: String = "white"
|
|
60
|
+
private var foregroundColor: (Int, Int, Int) = (0, 0, 0) // RGB for theme-aware drawing
|
|
60
61
|
private var eventHandler: Option[js.Function0[Unit]] = None
|
|
61
62
|
|
|
62
63
|
private val logo = new Logo:
|
|
@@ -100,9 +101,10 @@ class LogoJS(canvas: html.Canvas) extends js.Object:
|
|
|
100
101
|
backgroundColor = color
|
|
101
102
|
render()
|
|
102
103
|
|
|
103
|
-
/** Set the default pen color (used after clear) */
|
|
104
|
+
/** Set the default pen color (used after clear and for theme-aware drawing) */
|
|
104
105
|
def setForegroundColor(color: String): Unit =
|
|
105
106
|
val rgb = parseColor(color)
|
|
107
|
+
foregroundColor = rgb
|
|
106
108
|
logo.setDefaultColor(rgb)
|
|
107
109
|
render()
|
|
108
110
|
|
|
@@ -172,21 +174,33 @@ class LogoJS(canvas: html.Canvas) extends js.Object:
|
|
|
172
174
|
val lines = js.Array[LineData]()
|
|
173
175
|
val labels = js.Array[LabelData]()
|
|
174
176
|
val arcs = js.Array[ArcData]()
|
|
177
|
+
var currentColor: (Int, Int, Int) = foregroundColor
|
|
178
|
+
var currentWidth: Double = 1.0
|
|
175
179
|
|
|
176
180
|
logo.drawing.foreach {
|
|
177
|
-
case
|
|
181
|
+
case DrawSetColor(colorOpt) =>
|
|
182
|
+
currentColor = colorOpt.getOrElse(foregroundColor)
|
|
183
|
+
|
|
184
|
+
case DrawSetWidth(width) =>
|
|
185
|
+
currentWidth = width
|
|
186
|
+
|
|
187
|
+
case DrawLine(x1, y1, x2, y2) =>
|
|
188
|
+
val (r, g, b) = currentColor
|
|
178
189
|
lines.push(js.Dynamic.literal(
|
|
179
190
|
x1 = x1, y1 = y1, x2 = x2, y2 = y2,
|
|
180
|
-
color = s"rgb($r,$g,$b)", width =
|
|
191
|
+
color = s"rgb($r,$g,$b)", width = currentWidth
|
|
181
192
|
).asInstanceOf[LineData])
|
|
193
|
+
|
|
182
194
|
case DrawLabel(x, y, heading, text) =>
|
|
183
195
|
labels.push(js.Dynamic.literal(
|
|
184
196
|
x = x, y = y, heading = heading, text = text
|
|
185
197
|
).asInstanceOf[LabelData])
|
|
186
|
-
|
|
198
|
+
|
|
199
|
+
case DrawArc(x, y, heading, angle, radius) =>
|
|
200
|
+
val (r, g, b) = currentColor
|
|
187
201
|
arcs.push(js.Dynamic.literal(
|
|
188
202
|
x = x, y = y, heading = heading, angle = angle, radius = radius,
|
|
189
|
-
color = s"rgb($r,$g,$b)", width =
|
|
203
|
+
color = s"rgb($r,$g,$b)", width = currentWidth
|
|
190
204
|
).asInstanceOf[ArcData])
|
|
191
205
|
}
|
|
192
206
|
|
|
@@ -203,6 +217,8 @@ class LogoJS(canvas: html.Canvas) extends js.Object:
|
|
|
203
217
|
private def renderWithPaths(): Unit =
|
|
204
218
|
case class Style(color: (Int, Int, Int), width: Double)
|
|
205
219
|
|
|
220
|
+
var currentColor: (Int, Int, Int) = foregroundColor
|
|
221
|
+
var currentWidth: Double = 1.0
|
|
206
222
|
var currentStyle: Option[Style] = None
|
|
207
223
|
var pathStarted = false
|
|
208
224
|
var lastX: Double = 0
|
|
@@ -220,8 +236,14 @@ class LogoJS(canvas: html.Canvas) extends js.Object:
|
|
|
220
236
|
currentStyle = None
|
|
221
237
|
|
|
222
238
|
logo.drawing.foreach {
|
|
223
|
-
case
|
|
224
|
-
|
|
239
|
+
case DrawSetColor(colorOpt) =>
|
|
240
|
+
currentColor = colorOpt.getOrElse(foregroundColor)
|
|
241
|
+
|
|
242
|
+
case DrawSetWidth(width) =>
|
|
243
|
+
currentWidth = width
|
|
244
|
+
|
|
245
|
+
case DrawLine(x1, y1, x2, y2) =>
|
|
246
|
+
val style = Style(currentColor, currentWidth)
|
|
225
247
|
|
|
226
248
|
if !currentStyle.contains(style) then
|
|
227
249
|
flushPath()
|
|
@@ -243,9 +265,9 @@ class LogoJS(canvas: html.Canvas) extends js.Object:
|
|
|
243
265
|
lastX = x2
|
|
244
266
|
lastY = y2
|
|
245
267
|
|
|
246
|
-
case DrawArc(x, y, heading, angleDeg, radius
|
|
268
|
+
case DrawArc(x, y, heading, angleDeg, radius) =>
|
|
247
269
|
flushPath()
|
|
248
|
-
renderArc(x, y, heading, angleDeg, radius,
|
|
270
|
+
renderArc(x, y, heading, angleDeg, radius, currentColor, currentWidth)
|
|
249
271
|
|
|
250
272
|
case DrawLabel(x, y, heading, text) =>
|
|
251
273
|
flushPath()
|
|
@@ -255,17 +277,27 @@ class LogoJS(canvas: html.Canvas) extends js.Object:
|
|
|
255
277
|
flushPath()
|
|
256
278
|
|
|
257
279
|
private def renderWithLines(): Unit =
|
|
280
|
+
var currentColor: (Int, Int, Int) = foregroundColor
|
|
281
|
+
var currentWidth: Double = 1.0
|
|
282
|
+
|
|
258
283
|
logo.drawing.foreach {
|
|
259
|
-
case
|
|
284
|
+
case DrawSetColor(colorOpt) =>
|
|
285
|
+
currentColor = colorOpt.getOrElse(foregroundColor)
|
|
286
|
+
|
|
287
|
+
case DrawSetWidth(width) =>
|
|
288
|
+
currentWidth = width
|
|
289
|
+
|
|
290
|
+
case DrawLine(x1, y1, x2, y2) =>
|
|
291
|
+
val (r, g, b) = currentColor
|
|
260
292
|
ctx.strokeStyle = s"rgb($r,$g,$b)"
|
|
261
|
-
ctx.lineWidth =
|
|
293
|
+
ctx.lineWidth = currentWidth
|
|
262
294
|
ctx.beginPath()
|
|
263
295
|
ctx.moveTo(x1, y1)
|
|
264
296
|
ctx.lineTo(x2, y2)
|
|
265
297
|
ctx.stroke()
|
|
266
298
|
|
|
267
|
-
case DrawArc(x, y, heading, angleDeg, radius
|
|
268
|
-
renderArc(x, y, heading, angleDeg, radius,
|
|
299
|
+
case DrawArc(x, y, heading, angleDeg, radius) =>
|
|
300
|
+
renderArc(x, y, heading, angleDeg, radius, currentColor, currentWidth)
|
|
269
301
|
|
|
270
302
|
case DrawLabel(x, y, heading, text) =>
|
|
271
303
|
renderLabel(x, y, heading, text)
|
|
@@ -312,22 +344,72 @@ class LogoJS(canvas: html.Canvas) extends js.Object:
|
|
|
312
344
|
ctx.stroke()
|
|
313
345
|
|
|
314
346
|
private def drawTurtle(x: Double, y: Double, heading: Double): Unit =
|
|
315
|
-
val w = 15.0
|
|
316
|
-
val h = 20.0
|
|
317
|
-
|
|
318
347
|
ctx.save()
|
|
319
348
|
ctx.translate(x, y)
|
|
320
|
-
ctx.rotate(heading
|
|
349
|
+
ctx.rotate(heading + Pi / 2)
|
|
321
350
|
|
|
351
|
+
// Tail (behind shell)
|
|
322
352
|
ctx.beginPath()
|
|
323
|
-
ctx.moveTo(0,
|
|
324
|
-
ctx.lineTo(
|
|
325
|
-
ctx.
|
|
326
|
-
ctx.lineTo(w / 2, h / 2)
|
|
327
|
-
ctx.closePath()
|
|
328
|
-
|
|
329
|
-
ctx.strokeStyle = "green"
|
|
353
|
+
ctx.moveTo(0, 10)
|
|
354
|
+
ctx.lineTo(0, 14)
|
|
355
|
+
ctx.strokeStyle = "#4a7a44"
|
|
330
356
|
ctx.lineWidth = 2
|
|
357
|
+
ctx.lineCap = "round"
|
|
358
|
+
ctx.stroke()
|
|
359
|
+
|
|
360
|
+
// Legs (behind shell)
|
|
361
|
+
ctx.fillStyle = "#4a7a44"
|
|
362
|
+
ctx.strokeStyle = "#1a3a18"
|
|
363
|
+
ctx.lineWidth = 1
|
|
364
|
+
// Front legs
|
|
365
|
+
ctx.beginPath()
|
|
366
|
+
ctx.ellipse(-7, -6, 3, 5, 0.4, 0, 2 * Pi)
|
|
367
|
+
ctx.fill()
|
|
368
|
+
ctx.stroke()
|
|
369
|
+
ctx.beginPath()
|
|
370
|
+
ctx.ellipse(7, -6, 3, 5, -0.4, 0, 2 * Pi)
|
|
371
|
+
ctx.fill()
|
|
372
|
+
ctx.stroke()
|
|
373
|
+
// Back legs
|
|
374
|
+
ctx.beginPath()
|
|
375
|
+
ctx.ellipse(-6, 6, 3, 4, 0.3, 0, 2 * Pi)
|
|
376
|
+
ctx.fill()
|
|
377
|
+
ctx.stroke()
|
|
378
|
+
ctx.beginPath()
|
|
379
|
+
ctx.ellipse(6, 6, 3, 4, -0.3, 0, 2 * Pi)
|
|
380
|
+
ctx.fill()
|
|
381
|
+
ctx.stroke()
|
|
382
|
+
|
|
383
|
+
// Head (behind shell)
|
|
384
|
+
ctx.beginPath()
|
|
385
|
+
ctx.ellipse(0, -14, 4, 5, 0, 0, 2 * Pi)
|
|
386
|
+
ctx.fillStyle = "#4a7a44"
|
|
387
|
+
ctx.fill()
|
|
388
|
+
ctx.strokeStyle = "#1a3a18"
|
|
389
|
+
ctx.lineWidth = 1.5
|
|
390
|
+
ctx.stroke()
|
|
391
|
+
|
|
392
|
+
// Eyes
|
|
393
|
+
ctx.fillStyle = "black"
|
|
394
|
+
ctx.beginPath()
|
|
395
|
+
ctx.arc(-1.5, -15, 1, 0, 2 * Pi)
|
|
396
|
+
ctx.arc(1.5, -15, 1, 0, 2 * Pi)
|
|
397
|
+
ctx.fill()
|
|
398
|
+
|
|
399
|
+
// Shell (on top)
|
|
400
|
+
ctx.beginPath()
|
|
401
|
+
ctx.ellipse(0, 0, 8, 10, 0, 0, 2 * Pi)
|
|
402
|
+
ctx.fillStyle = "#2d5a27"
|
|
403
|
+
ctx.fill()
|
|
404
|
+
ctx.strokeStyle = "#1a3a18"
|
|
405
|
+
ctx.lineWidth = 1.5
|
|
406
|
+
ctx.stroke()
|
|
407
|
+
|
|
408
|
+
// Shell pattern
|
|
409
|
+
ctx.strokeStyle = "#3d7a37"
|
|
410
|
+
ctx.lineWidth = 1
|
|
411
|
+
ctx.beginPath()
|
|
412
|
+
ctx.ellipse(0, 0, 5, 6, 0, 0, 2 * Pi)
|
|
331
413
|
ctx.stroke()
|
|
332
414
|
|
|
333
415
|
ctx.restore()
|
package/dist/react/LogoCanvas.js
DELETED
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { useRef, useEffect, useImperativeHandle, forwardRef } from 'react';
|
|
3
|
-
export const LogoCanvas = forwardRef(({ width = 600, height = 400, program, pathRendering = true, onError, onComplete, className, style, }, ref) => {
|
|
4
|
-
const canvasRef = useRef(null);
|
|
5
|
-
const logoRef = useRef(null);
|
|
6
|
-
// Initialize Logo instance
|
|
7
|
-
useEffect(() => {
|
|
8
|
-
if (canvasRef.current && typeof Logo !== 'undefined') {
|
|
9
|
-
logoRef.current = new Logo(canvasRef.current);
|
|
10
|
-
logoRef.current.setPathRendering(pathRendering);
|
|
11
|
-
}
|
|
12
|
-
}, []);
|
|
13
|
-
// Update path rendering setting
|
|
14
|
-
useEffect(() => {
|
|
15
|
-
if (logoRef.current) {
|
|
16
|
-
logoRef.current.setPathRendering(pathRendering);
|
|
17
|
-
}
|
|
18
|
-
}, [pathRendering]);
|
|
19
|
-
// Run program when it changes
|
|
20
|
-
useEffect(() => {
|
|
21
|
-
if (logoRef.current && program !== undefined) {
|
|
22
|
-
try {
|
|
23
|
-
logoRef.current.clear();
|
|
24
|
-
logoRef.current.run(program);
|
|
25
|
-
onComplete?.();
|
|
26
|
-
}
|
|
27
|
-
catch (e) {
|
|
28
|
-
onError?.(e instanceof Error ? e : new Error(String(e)));
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
}, [program, onError, onComplete]);
|
|
32
|
-
// Expose methods via ref
|
|
33
|
-
useImperativeHandle(ref, () => ({
|
|
34
|
-
execute: (command) => {
|
|
35
|
-
if (logoRef.current) {
|
|
36
|
-
try {
|
|
37
|
-
logoRef.current.execute(command);
|
|
38
|
-
}
|
|
39
|
-
catch (e) {
|
|
40
|
-
onError?.(e instanceof Error ? e : new Error(String(e)));
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
},
|
|
44
|
-
run: (prog) => {
|
|
45
|
-
if (logoRef.current) {
|
|
46
|
-
try {
|
|
47
|
-
logoRef.current.run(prog);
|
|
48
|
-
onComplete?.();
|
|
49
|
-
}
|
|
50
|
-
catch (e) {
|
|
51
|
-
onError?.(e instanceof Error ? e : new Error(String(e)));
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
},
|
|
55
|
-
clear: () => {
|
|
56
|
-
logoRef.current?.clear();
|
|
57
|
-
},
|
|
58
|
-
getDrawing: () => {
|
|
59
|
-
return logoRef.current?.getDrawing() ?? { lines: [], labels: [] };
|
|
60
|
-
},
|
|
61
|
-
getTurtle: () => {
|
|
62
|
-
return (logoRef.current?.getTurtle() ?? {
|
|
63
|
-
x: 0,
|
|
64
|
-
y: 0,
|
|
65
|
-
heading: Math.PI / 2,
|
|
66
|
-
visible: true,
|
|
67
|
-
});
|
|
68
|
-
},
|
|
69
|
-
getLogo: () => logoRef.current,
|
|
70
|
-
}));
|
|
71
|
-
return (_jsx("canvas", { ref: canvasRef, width: width, height: height, className: className, style: { backgroundColor: 'white', ...style } }));
|
|
72
|
-
});
|
|
73
|
-
LogoCanvas.displayName = 'LogoCanvas';
|
|
74
|
-
export default LogoCanvas;
|
package/dist/react/index.js
DELETED
package/react/LogoCanvas.tsx
DELETED
|
@@ -1,174 +0,0 @@
|
|
|
1
|
-
import React, { useRef, useEffect, useImperativeHandle, forwardRef } from 'react';
|
|
2
|
-
|
|
3
|
-
// Type definitions for the Logo class from Scala.js
|
|
4
|
-
interface LogoDrawing {
|
|
5
|
-
lines: Array<{
|
|
6
|
-
x1: number;
|
|
7
|
-
y1: number;
|
|
8
|
-
x2: number;
|
|
9
|
-
y2: number;
|
|
10
|
-
color: string;
|
|
11
|
-
width: number;
|
|
12
|
-
}>;
|
|
13
|
-
labels: Array<{
|
|
14
|
-
x: number;
|
|
15
|
-
y: number;
|
|
16
|
-
heading: number;
|
|
17
|
-
text: string;
|
|
18
|
-
}>;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
interface TurtleState {
|
|
22
|
-
x: number;
|
|
23
|
-
y: number;
|
|
24
|
-
heading: number;
|
|
25
|
-
visible: boolean;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
interface LogoInstance {
|
|
29
|
-
run(program: string): void;
|
|
30
|
-
execute(command: string): void;
|
|
31
|
-
clear(): void;
|
|
32
|
-
render(): void;
|
|
33
|
-
setPathRendering(enabled: boolean): void;
|
|
34
|
-
setAutoRender(enabled: boolean): void;
|
|
35
|
-
getDrawing(): LogoDrawing;
|
|
36
|
-
getTurtle(): TurtleState;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
declare const Logo: new (canvas: HTMLCanvasElement) => LogoInstance;
|
|
40
|
-
|
|
41
|
-
export interface LogoCanvasProps {
|
|
42
|
-
/** Width of the canvas in pixels */
|
|
43
|
-
width?: number;
|
|
44
|
-
/** Height of the canvas in pixels */
|
|
45
|
-
height?: number;
|
|
46
|
-
/** Logo program to run */
|
|
47
|
-
program?: string;
|
|
48
|
-
/** Whether to use path-based rendering (smoother curves) */
|
|
49
|
-
pathRendering?: boolean;
|
|
50
|
-
/** Callback when an error occurs */
|
|
51
|
-
onError?: (error: Error) => void;
|
|
52
|
-
/** Callback when program execution completes */
|
|
53
|
-
onComplete?: () => void;
|
|
54
|
-
/** Additional CSS class for the canvas */
|
|
55
|
-
className?: string;
|
|
56
|
-
/** Additional inline styles for the canvas */
|
|
57
|
-
style?: React.CSSProperties;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
export interface LogoCanvasRef {
|
|
61
|
-
/** Execute a Logo command */
|
|
62
|
-
execute: (command: string) => void;
|
|
63
|
-
/** Run a full Logo program */
|
|
64
|
-
run: (program: string) => void;
|
|
65
|
-
/** Clear the canvas and reset turtle */
|
|
66
|
-
clear: () => void;
|
|
67
|
-
/** Get the current drawing data */
|
|
68
|
-
getDrawing: () => LogoDrawing;
|
|
69
|
-
/** Get the current turtle state */
|
|
70
|
-
getTurtle: () => TurtleState;
|
|
71
|
-
/** Get the underlying Logo instance */
|
|
72
|
-
getLogo: () => LogoInstance | null;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
export const LogoCanvas = forwardRef<LogoCanvasRef, LogoCanvasProps>(
|
|
76
|
-
(
|
|
77
|
-
{
|
|
78
|
-
width = 600,
|
|
79
|
-
height = 400,
|
|
80
|
-
program,
|
|
81
|
-
pathRendering = true,
|
|
82
|
-
onError,
|
|
83
|
-
onComplete,
|
|
84
|
-
className,
|
|
85
|
-
style,
|
|
86
|
-
},
|
|
87
|
-
ref
|
|
88
|
-
) => {
|
|
89
|
-
const canvasRef = useRef<HTMLCanvasElement>(null);
|
|
90
|
-
const logoRef = useRef<LogoInstance | null>(null);
|
|
91
|
-
|
|
92
|
-
// Initialize Logo instance
|
|
93
|
-
useEffect(() => {
|
|
94
|
-
if (canvasRef.current && typeof Logo !== 'undefined') {
|
|
95
|
-
logoRef.current = new Logo(canvasRef.current);
|
|
96
|
-
logoRef.current.setPathRendering(pathRendering);
|
|
97
|
-
}
|
|
98
|
-
}, []);
|
|
99
|
-
|
|
100
|
-
// Update path rendering setting
|
|
101
|
-
useEffect(() => {
|
|
102
|
-
if (logoRef.current) {
|
|
103
|
-
logoRef.current.setPathRendering(pathRendering);
|
|
104
|
-
}
|
|
105
|
-
}, [pathRendering]);
|
|
106
|
-
|
|
107
|
-
// Run program when it changes
|
|
108
|
-
useEffect(() => {
|
|
109
|
-
if (logoRef.current && program !== undefined) {
|
|
110
|
-
try {
|
|
111
|
-
logoRef.current.clear();
|
|
112
|
-
logoRef.current.run(program);
|
|
113
|
-
onComplete?.();
|
|
114
|
-
} catch (e) {
|
|
115
|
-
onError?.(e instanceof Error ? e : new Error(String(e)));
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
}, [program, onError, onComplete]);
|
|
119
|
-
|
|
120
|
-
// Expose methods via ref
|
|
121
|
-
useImperativeHandle(ref, () => ({
|
|
122
|
-
execute: (command: string) => {
|
|
123
|
-
if (logoRef.current) {
|
|
124
|
-
try {
|
|
125
|
-
logoRef.current.execute(command);
|
|
126
|
-
} catch (e) {
|
|
127
|
-
onError?.(e instanceof Error ? e : new Error(String(e)));
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
},
|
|
131
|
-
run: (prog: string) => {
|
|
132
|
-
if (logoRef.current) {
|
|
133
|
-
try {
|
|
134
|
-
logoRef.current.run(prog);
|
|
135
|
-
onComplete?.();
|
|
136
|
-
} catch (e) {
|
|
137
|
-
onError?.(e instanceof Error ? e : new Error(String(e)));
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
},
|
|
141
|
-
clear: () => {
|
|
142
|
-
logoRef.current?.clear();
|
|
143
|
-
},
|
|
144
|
-
getDrawing: () => {
|
|
145
|
-
return logoRef.current?.getDrawing() ?? { lines: [], labels: [] };
|
|
146
|
-
},
|
|
147
|
-
getTurtle: () => {
|
|
148
|
-
return (
|
|
149
|
-
logoRef.current?.getTurtle() ?? {
|
|
150
|
-
x: 0,
|
|
151
|
-
y: 0,
|
|
152
|
-
heading: Math.PI / 2,
|
|
153
|
-
visible: true,
|
|
154
|
-
}
|
|
155
|
-
);
|
|
156
|
-
},
|
|
157
|
-
getLogo: () => logoRef.current,
|
|
158
|
-
}));
|
|
159
|
-
|
|
160
|
-
return (
|
|
161
|
-
<canvas
|
|
162
|
-
ref={canvasRef}
|
|
163
|
-
width={width}
|
|
164
|
-
height={height}
|
|
165
|
-
className={className}
|
|
166
|
-
style={{ backgroundColor: 'white', ...style }}
|
|
167
|
-
/>
|
|
168
|
-
);
|
|
169
|
-
}
|
|
170
|
-
);
|
|
171
|
-
|
|
172
|
-
LogoCanvas.displayName = 'LogoCanvas';
|
|
173
|
-
|
|
174
|
-
export default LogoCanvas;
|
package/react/index.ts
DELETED