@edadma/logo 0.2.3 → 0.2.4
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 +48 -7
- package/dist/main.js.map +2 -2
- package/package.json +5 -25
- package/src/main/scala/io/github/edadma/logo/LogoJS.scala +61 -11
- 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.4",
|
|
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
|
}
|
|
@@ -312,22 +312,72 @@ class LogoJS(canvas: html.Canvas) extends js.Object:
|
|
|
312
312
|
ctx.stroke()
|
|
313
313
|
|
|
314
314
|
private def drawTurtle(x: Double, y: Double, heading: Double): Unit =
|
|
315
|
-
val w = 15.0
|
|
316
|
-
val h = 20.0
|
|
317
|
-
|
|
318
315
|
ctx.save()
|
|
319
316
|
ctx.translate(x, y)
|
|
320
|
-
ctx.rotate(heading
|
|
317
|
+
ctx.rotate(heading + Pi / 2)
|
|
321
318
|
|
|
319
|
+
// Tail (behind shell)
|
|
322
320
|
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"
|
|
321
|
+
ctx.moveTo(0, 10)
|
|
322
|
+
ctx.lineTo(0, 14)
|
|
323
|
+
ctx.strokeStyle = "#4a7a44"
|
|
330
324
|
ctx.lineWidth = 2
|
|
325
|
+
ctx.lineCap = "round"
|
|
326
|
+
ctx.stroke()
|
|
327
|
+
|
|
328
|
+
// Legs (behind shell)
|
|
329
|
+
ctx.fillStyle = "#4a7a44"
|
|
330
|
+
ctx.strokeStyle = "#1a3a18"
|
|
331
|
+
ctx.lineWidth = 1
|
|
332
|
+
// Front legs
|
|
333
|
+
ctx.beginPath()
|
|
334
|
+
ctx.ellipse(-7, -6, 3, 5, 0.4, 0, 2 * Pi)
|
|
335
|
+
ctx.fill()
|
|
336
|
+
ctx.stroke()
|
|
337
|
+
ctx.beginPath()
|
|
338
|
+
ctx.ellipse(7, -6, 3, 5, -0.4, 0, 2 * Pi)
|
|
339
|
+
ctx.fill()
|
|
340
|
+
ctx.stroke()
|
|
341
|
+
// Back legs
|
|
342
|
+
ctx.beginPath()
|
|
343
|
+
ctx.ellipse(-6, 6, 3, 4, 0.3, 0, 2 * Pi)
|
|
344
|
+
ctx.fill()
|
|
345
|
+
ctx.stroke()
|
|
346
|
+
ctx.beginPath()
|
|
347
|
+
ctx.ellipse(6, 6, 3, 4, -0.3, 0, 2 * Pi)
|
|
348
|
+
ctx.fill()
|
|
349
|
+
ctx.stroke()
|
|
350
|
+
|
|
351
|
+
// Head (behind shell)
|
|
352
|
+
ctx.beginPath()
|
|
353
|
+
ctx.ellipse(0, -14, 4, 5, 0, 0, 2 * Pi)
|
|
354
|
+
ctx.fillStyle = "#4a7a44"
|
|
355
|
+
ctx.fill()
|
|
356
|
+
ctx.strokeStyle = "#1a3a18"
|
|
357
|
+
ctx.lineWidth = 1.5
|
|
358
|
+
ctx.stroke()
|
|
359
|
+
|
|
360
|
+
// Eyes
|
|
361
|
+
ctx.fillStyle = "black"
|
|
362
|
+
ctx.beginPath()
|
|
363
|
+
ctx.arc(-1.5, -15, 1, 0, 2 * Pi)
|
|
364
|
+
ctx.arc(1.5, -15, 1, 0, 2 * Pi)
|
|
365
|
+
ctx.fill()
|
|
366
|
+
|
|
367
|
+
// Shell (on top)
|
|
368
|
+
ctx.beginPath()
|
|
369
|
+
ctx.ellipse(0, 0, 8, 10, 0, 0, 2 * Pi)
|
|
370
|
+
ctx.fillStyle = "#2d5a27"
|
|
371
|
+
ctx.fill()
|
|
372
|
+
ctx.strokeStyle = "#1a3a18"
|
|
373
|
+
ctx.lineWidth = 1.5
|
|
374
|
+
ctx.stroke()
|
|
375
|
+
|
|
376
|
+
// Shell pattern
|
|
377
|
+
ctx.strokeStyle = "#3d7a37"
|
|
378
|
+
ctx.lineWidth = 1
|
|
379
|
+
ctx.beginPath()
|
|
380
|
+
ctx.ellipse(0, 0, 5, 6, 0, 0, 2 * Pi)
|
|
331
381
|
ctx.stroke()
|
|
332
382
|
|
|
333
383
|
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