kei-lisp-plugin-graphics 1.0.1 → 2.0.0
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/README.md +12 -1
- package/dist/index.cjs +453 -409
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +77 -61
- package/dist/index.d.ts +77 -61
- package/dist/index.js +453 -409
- package/dist/index.js.map +1 -1
- package/package.json +10 -8
package/dist/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import { Cons, InterpretedSymbol } from "kei-lisp";
|
|
|
4
4
|
* @class
|
|
5
5
|
* @classdesc Canvas2D drawing plugin for the kei-lisp interpreter. Implements
|
|
6
6
|
* the `KeiLispPlugin` contract (`name` / `has` / `apply`) and
|
|
7
|
-
* exposes
|
|
7
|
+
* exposes 45 `g…` Lisp functions that proxy to a 2D rendering
|
|
8
8
|
* context.
|
|
9
9
|
* @author Keisuke Ikeda
|
|
10
10
|
* @this {GraphicsPlugin}
|
|
@@ -16,6 +16,59 @@ var GraphicsPlugin = class GraphicsPlugin extends Object {
|
|
|
16
16
|
*/
|
|
17
17
|
static buildInFunctions = GraphicsPlugin.setup();
|
|
18
18
|
/**
|
|
19
|
+
* Builds the dispatch table.
|
|
20
|
+
* @return the dispatch table
|
|
21
|
+
*/
|
|
22
|
+
static setup() {
|
|
23
|
+
const aTable = /* @__PURE__ */ new Map();
|
|
24
|
+
aTable.set(InterpretedSymbol.of("galpha"), "gAlpha");
|
|
25
|
+
aTable.set(InterpretedSymbol.of("garc"), "gArc");
|
|
26
|
+
aTable.set(InterpretedSymbol.of("garc-to"), "gArcTo");
|
|
27
|
+
aTable.set(InterpretedSymbol.of("gbezcurve-to"), "gBezCurveTo");
|
|
28
|
+
aTable.set(InterpretedSymbol.of("gclear"), "gClear");
|
|
29
|
+
aTable.set(InterpretedSymbol.of("gclose"), "gClose");
|
|
30
|
+
aTable.set(InterpretedSymbol.of("gcolor"), "gColor");
|
|
31
|
+
aTable.set(InterpretedSymbol.of("gfill"), "gFill");
|
|
32
|
+
aTable.set(InterpretedSymbol.of("gfill-color"), "gFillColor");
|
|
33
|
+
aTable.set(InterpretedSymbol.of("gfill-rect"), "gFillRect");
|
|
34
|
+
aTable.set(InterpretedSymbol.of("gfill-text"), "gFillText");
|
|
35
|
+
aTable.set(InterpretedSymbol.of("gfill-tri"), "gFillTri");
|
|
36
|
+
aTable.set(InterpretedSymbol.of("gfinish-path"), "gFinishPath");
|
|
37
|
+
aTable.set(InterpretedSymbol.of("gimage"), "gImage");
|
|
38
|
+
aTable.set(InterpretedSymbol.of("gmove-to"), "gMoveTo");
|
|
39
|
+
aTable.set(InterpretedSymbol.of("gline-to"), "gLineTo");
|
|
40
|
+
aTable.set(InterpretedSymbol.of("gline-cap"), "gLineCap");
|
|
41
|
+
aTable.set(InterpretedSymbol.of("gline-join"), "gLineJoin");
|
|
42
|
+
aTable.set(InterpretedSymbol.of("gline-width"), "gLineWidth");
|
|
43
|
+
aTable.set(InterpretedSymbol.of("gopen"), "gOpen");
|
|
44
|
+
aTable.set(InterpretedSymbol.of("gpattern"), "gPattern");
|
|
45
|
+
aTable.set(InterpretedSymbol.of("gquadcurve-to"), "gQuadCurveTo");
|
|
46
|
+
aTable.set(InterpretedSymbol.of("gsave-jpeg"), "gSaveJpeg");
|
|
47
|
+
aTable.set(InterpretedSymbol.of("gsave-png"), "gSavePng");
|
|
48
|
+
aTable.set(InterpretedSymbol.of("gscale"), "gScale");
|
|
49
|
+
aTable.set(InterpretedSymbol.of("gshadow-blur"), "gShadowBlur");
|
|
50
|
+
aTable.set(InterpretedSymbol.of("gshadow-color"), "gShadowColor");
|
|
51
|
+
aTable.set(InterpretedSymbol.of("gshadow-offsetx"), "gShadowOffsetX");
|
|
52
|
+
aTable.set(InterpretedSymbol.of("gshadow-offsety"), "gShadowOffsetY");
|
|
53
|
+
aTable.set(InterpretedSymbol.of("gsleep"), "gSleep");
|
|
54
|
+
aTable.set(InterpretedSymbol.of("gstart-path"), "gStartPath");
|
|
55
|
+
aTable.set(InterpretedSymbol.of("gstroke"), "gStroke");
|
|
56
|
+
aTable.set(InterpretedSymbol.of("gstroke-color"), "gStrokeColor");
|
|
57
|
+
aTable.set(InterpretedSymbol.of("gstroke-rect"), "gStrokeRect");
|
|
58
|
+
aTable.set(InterpretedSymbol.of("gstroke-text"), "gStrokeText");
|
|
59
|
+
aTable.set(InterpretedSymbol.of("gstroke-tri"), "gStrokeTri");
|
|
60
|
+
aTable.set(InterpretedSymbol.of("gtext-align"), "gTextAlign");
|
|
61
|
+
aTable.set(InterpretedSymbol.of("gtext-dire"), "gTextDirection");
|
|
62
|
+
aTable.set(InterpretedSymbol.of("gtext-font"), "gTextFont");
|
|
63
|
+
aTable.set(InterpretedSymbol.of("gtext-line"), "gTextBaseline");
|
|
64
|
+
aTable.set(InterpretedSymbol.of("gtranslate"), "gTranslate");
|
|
65
|
+
aTable.set(InterpretedSymbol.of("grect"), "gRect");
|
|
66
|
+
aTable.set(InterpretedSymbol.of("grotate"), "gRotate");
|
|
67
|
+
aTable.set(InterpretedSymbol.of("gsave"), "gSave");
|
|
68
|
+
aTable.set(InterpretedSymbol.of("grestore"), "gRestore");
|
|
69
|
+
return aTable;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
19
72
|
* Plugin identifier, used for diagnostics.
|
|
20
73
|
*/
|
|
21
74
|
name = "graphics";
|
|
@@ -34,6 +87,79 @@ var GraphicsPlugin = class GraphicsPlugin extends Object {
|
|
|
34
87
|
this.isOpen = false;
|
|
35
88
|
}
|
|
36
89
|
/**
|
|
90
|
+
* Writes a diagnostic line directly to `process.stderr`, matching the
|
|
91
|
+
* convention used by kei-lisp itself (`Applier.format` writes to
|
|
92
|
+
* `process.stdout`). In a Node runtime this hits the real stderr; in a
|
|
93
|
+
* browser kei-lisp host (e.g. kei-lisp-web) the host typically swaps
|
|
94
|
+
* `process.stderr.write` for a sink that routes to the REPL output panel,
|
|
95
|
+
* so the same call reaches the user via the host's normal output channel.
|
|
96
|
+
* @param line - the line to write
|
|
97
|
+
*/
|
|
98
|
+
#print(line) {
|
|
99
|
+
process.stderr.write(line + "\n");
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Encodes the canvas via `toDataURL` and triggers a browser download through
|
|
103
|
+
* a temporary `<a download>` element. Requires a DOM (`document`) and an
|
|
104
|
+
* `HTMLCanvasElement`; `OffscreenCanvas` has no `toDataURL`, and Node.js has
|
|
105
|
+
* no `document` — those callers must pass a file path instead.
|
|
106
|
+
* @param mimeType - the image MIME type to encode
|
|
107
|
+
* @param label - the format name used in diagnostics ("jpeg" / "png")
|
|
108
|
+
* @return `t` on success, `Cons.nil` otherwise
|
|
109
|
+
*/
|
|
110
|
+
#downloadCanvas(mimeType, label) {
|
|
111
|
+
if (typeof document === "undefined" || !("toDataURL" in this.canvas)) {
|
|
112
|
+
this.#print(`Can not save ${label}. Browser download needs a DOM and an HTMLCanvasElement; pass a file path to save on Node.js.`);
|
|
113
|
+
return Cons.nil;
|
|
114
|
+
}
|
|
115
|
+
try {
|
|
116
|
+
const link = document.createElement("a");
|
|
117
|
+
link.href = this.canvas.toDataURL(mimeType);
|
|
118
|
+
link.download = "canvas";
|
|
119
|
+
document.body.append(link);
|
|
120
|
+
link.click();
|
|
121
|
+
link.remove();
|
|
122
|
+
return InterpretedSymbol.of("t");
|
|
123
|
+
} catch {
|
|
124
|
+
this.#print(`Can not save ${label}. If you are using an image in the canvas, you can't save ${label}.`);
|
|
125
|
+
return Cons.nil;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Writes the encoded canvas image to a file path on Node.js, using
|
|
130
|
+
* `process.getBuiltinModule('node:fs')` so browser bundles never see a
|
|
131
|
+
* `node:fs` import. `HTMLCanvasElement` (and node-canvas) encode
|
|
132
|
+
* synchronously via `toDataURL`; `OffscreenCanvas` only offers the async
|
|
133
|
+
* `convertToBlob`, so its file is written after this returns — the same
|
|
134
|
+
* fire-and-forget contract as `gImage`.
|
|
135
|
+
* @param path - the destination file path
|
|
136
|
+
* @param mimeType - the image MIME type to encode
|
|
137
|
+
* @param label - the format name used in diagnostics ("jpeg" / "png")
|
|
138
|
+
* @return `t` on success, `Cons.nil` otherwise
|
|
139
|
+
*/
|
|
140
|
+
#writeCanvasToFile(path, mimeType, label) {
|
|
141
|
+
const fs = typeof process.getBuiltinModule === "function" ? process.getBuiltinModule("node:fs") : void 0;
|
|
142
|
+
if (fs === void 0) {
|
|
143
|
+
this.#print(`Can not save ${label}. Saving to a file path requires Node.js.`);
|
|
144
|
+
return Cons.nil;
|
|
145
|
+
}
|
|
146
|
+
try {
|
|
147
|
+
if ("toDataURL" in this.canvas) {
|
|
148
|
+
const dataUrl = this.canvas.toDataURL(mimeType);
|
|
149
|
+
const base64 = dataUrl.slice(dataUrl.indexOf(",") + 1);
|
|
150
|
+
fs.writeFileSync(path, Buffer.from(base64, "base64"));
|
|
151
|
+
return InterpretedSymbol.of("t");
|
|
152
|
+
}
|
|
153
|
+
this.canvas.convertToBlob({ type: mimeType }).then(async (blob) => {
|
|
154
|
+
fs.writeFileSync(path, new Uint8Array(await blob.arrayBuffer()));
|
|
155
|
+
});
|
|
156
|
+
return InterpretedSymbol.of("t");
|
|
157
|
+
} catch {
|
|
158
|
+
this.#print(`Can not save ${label}.`);
|
|
159
|
+
return Cons.nil;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
37
163
|
* Returns true if this plugin handles the given symbol.
|
|
38
164
|
* @param aSymbol - the call symbol
|
|
39
165
|
* @return true if `apply` should be called
|
|
@@ -44,22 +170,22 @@ var GraphicsPlugin = class GraphicsPlugin extends Object {
|
|
|
44
170
|
/**
|
|
45
171
|
* Dispatches the given symbol to the matching `g…` method.
|
|
46
172
|
* @param aSymbol - the call symbol
|
|
47
|
-
* @param
|
|
48
|
-
* @param
|
|
173
|
+
* @param arguments_ - the evaluated argument list
|
|
174
|
+
* @param _context - the interpreter context (unused by this plugin)
|
|
49
175
|
* @return the method's result, or `Cons.nil` if dispatch fails
|
|
50
176
|
*/
|
|
51
|
-
apply(aSymbol,
|
|
52
|
-
return this.selectProcedure(aSymbol,
|
|
177
|
+
apply(aSymbol, arguments_, _context) {
|
|
178
|
+
return this.selectProcedure(aSymbol, arguments_);
|
|
53
179
|
}
|
|
54
180
|
/**
|
|
55
181
|
* Resolves the procedure name and invokes the matching method.
|
|
56
182
|
* @param procedure - the Lisp symbol
|
|
57
|
-
* @param
|
|
183
|
+
* @param arguments_ - the evaluated argument list
|
|
58
184
|
* @return the method's result, or `Cons.nil` if not registered
|
|
59
185
|
*/
|
|
60
|
-
selectProcedure(procedure,
|
|
61
|
-
if (GraphicsPlugin.buildInFunctions.has(procedure)) return this.buildInFunction(procedure,
|
|
62
|
-
this
|
|
186
|
+
selectProcedure(procedure, arguments_) {
|
|
187
|
+
if (GraphicsPlugin.buildInFunctions.has(procedure)) return this.buildInFunction(procedure, arguments_);
|
|
188
|
+
this.#print(`I could find no procedure description for ${String(procedure)}`);
|
|
63
189
|
return Cons.nil;
|
|
64
190
|
}
|
|
65
191
|
/**
|
|
@@ -69,14 +195,14 @@ var GraphicsPlugin = class GraphicsPlugin extends Object {
|
|
|
69
195
|
* Ramda `R.invoker(1, methodName)(args, this)` call would surface the same
|
|
70
196
|
* error by attempting to call `undefined`.
|
|
71
197
|
* @param procedure - the Lisp symbol
|
|
72
|
-
* @param
|
|
198
|
+
* @param arguments_ - the evaluated argument list
|
|
73
199
|
* @return the method's result
|
|
74
200
|
*/
|
|
75
|
-
buildInFunction(procedure,
|
|
201
|
+
buildInFunction(procedure, arguments_) {
|
|
76
202
|
const methodName = GraphicsPlugin.buildInFunctions.get(procedure);
|
|
77
203
|
const method = this[methodName];
|
|
78
204
|
if (typeof method !== "function") throw new TypeError(`${this.constructor.name} does not have a method named "${methodName}"`);
|
|
79
|
-
return method.call(this,
|
|
205
|
+
return method.call(this, arguments_);
|
|
80
206
|
}
|
|
81
207
|
/**
|
|
82
208
|
* Checks whether the canvas exposes a usable 2D context, and narrows
|
|
@@ -85,47 +211,34 @@ var GraphicsPlugin = class GraphicsPlugin extends Object {
|
|
|
85
211
|
*/
|
|
86
212
|
checkSupport() {
|
|
87
213
|
if (this.ctx === null) {
|
|
88
|
-
this
|
|
214
|
+
this.#print("Unable to initialize canvas. The browser or machine may not support it.");
|
|
89
215
|
return false;
|
|
90
216
|
}
|
|
91
217
|
return true;
|
|
92
218
|
}
|
|
93
|
-
|
|
94
|
-
* Writes a diagnostic line directly to `process.stderr`, matching the
|
|
95
|
-
* convention used by kei-lisp itself (`Applier.format` writes to
|
|
96
|
-
* `process.stdout`). In a Node runtime this hits the real stderr; in a
|
|
97
|
-
* browser kei-lisp host (e.g. kei-lisp-web) the host typically swaps
|
|
98
|
-
* `process.stderr.write` for a sink that routes to the REPL output panel,
|
|
99
|
-
* so the same call reaches the user via the host's normal output channel.
|
|
100
|
-
* @param line - the line to write
|
|
101
|
-
*/
|
|
102
|
-
_print(line) {
|
|
103
|
-
process.stderr.write(line + "\n");
|
|
104
|
-
}
|
|
105
|
-
gAlpha(args) {
|
|
219
|
+
gAlpha(arguments_) {
|
|
106
220
|
if (!this.checkSupport()) return Cons.nil;
|
|
107
221
|
if (this.isOpen) try {
|
|
108
|
-
if (
|
|
109
|
-
const aNumber =
|
|
222
|
+
if (arguments_.length() === 1 && Cons.isNumber(arguments_.car)) {
|
|
223
|
+
const aNumber = arguments_.car <= 0 ? 0 : arguments_.car >= 1 ? 1 : arguments_.car;
|
|
110
224
|
this.ctx.globalAlpha = aNumber;
|
|
111
|
-
this.ctx.save();
|
|
112
225
|
return InterpretedSymbol.of("t");
|
|
113
226
|
}
|
|
114
|
-
this
|
|
227
|
+
this.#print("Can not set alpha.");
|
|
115
228
|
return Cons.nil;
|
|
116
229
|
} catch {
|
|
117
|
-
this
|
|
230
|
+
this.#print("Can not set alpha.");
|
|
118
231
|
return Cons.nil;
|
|
119
232
|
}
|
|
120
|
-
this
|
|
233
|
+
this.#print("The canvas is closed and cannot be executed.");
|
|
121
234
|
return Cons.nil;
|
|
122
235
|
}
|
|
123
|
-
gArc(
|
|
236
|
+
gArc(arguments_) {
|
|
124
237
|
if (!this.checkSupport()) return Cons.nil;
|
|
125
238
|
if (this.isOpen) try {
|
|
126
|
-
if (
|
|
127
|
-
const a0 =
|
|
128
|
-
const cdr1 =
|
|
239
|
+
if (arguments_.length() === 6) {
|
|
240
|
+
const a0 = arguments_.car;
|
|
241
|
+
const cdr1 = arguments_.cdr;
|
|
129
242
|
const a1 = cdr1.car;
|
|
130
243
|
const cdr2 = cdr1.cdr;
|
|
131
244
|
const a2 = cdr2.car;
|
|
@@ -135,27 +248,26 @@ var GraphicsPlugin = class GraphicsPlugin extends Object {
|
|
|
135
248
|
const a4 = cdr4.car;
|
|
136
249
|
const a5 = cdr4.cdr.car;
|
|
137
250
|
if (Cons.isNumber(a0) && Cons.isNumber(a1) && Cons.isNumber(a2) && Cons.isNumber(a3) && Cons.isNumber(a4) && Cons.isNumber(a5)) {
|
|
138
|
-
const
|
|
139
|
-
this.ctx.arc(a0, a1, a2, Math.PI / 180 * a3, Math.PI / 180 * a4,
|
|
140
|
-
this.ctx.save();
|
|
251
|
+
const isAFlag = a5 >= 0;
|
|
252
|
+
this.ctx.arc(a0, a1, a2, Math.PI / 180 * a3, Math.PI / 180 * a4, isAFlag);
|
|
141
253
|
return InterpretedSymbol.of("t");
|
|
142
254
|
}
|
|
143
255
|
}
|
|
144
|
-
this
|
|
256
|
+
this.#print("Can not draw arc.");
|
|
145
257
|
return Cons.nil;
|
|
146
258
|
} catch {
|
|
147
|
-
this
|
|
259
|
+
this.#print("Can not draw arc.");
|
|
148
260
|
return Cons.nil;
|
|
149
261
|
}
|
|
150
|
-
this
|
|
262
|
+
this.#print("The canvas is closed and cannot be executed.");
|
|
151
263
|
return Cons.nil;
|
|
152
264
|
}
|
|
153
|
-
gArcTo(
|
|
265
|
+
gArcTo(arguments_) {
|
|
154
266
|
if (!this.checkSupport()) return Cons.nil;
|
|
155
267
|
if (this.isOpen) try {
|
|
156
|
-
if (
|
|
157
|
-
const a0 =
|
|
158
|
-
const cdr1 =
|
|
268
|
+
if (arguments_.length() === 5) {
|
|
269
|
+
const a0 = arguments_.car;
|
|
270
|
+
const cdr1 = arguments_.cdr;
|
|
159
271
|
const a1 = cdr1.car;
|
|
160
272
|
const cdr2 = cdr1.cdr;
|
|
161
273
|
const a2 = cdr2.car;
|
|
@@ -164,25 +276,24 @@ var GraphicsPlugin = class GraphicsPlugin extends Object {
|
|
|
164
276
|
const a4 = cdr3.cdr.car;
|
|
165
277
|
if (Cons.isNumber(a0) && Cons.isNumber(a1) && Cons.isNumber(a2) && Cons.isNumber(a3) && Cons.isNumber(a4)) {
|
|
166
278
|
this.ctx.arcTo(a0, a1, a2, a3, a4);
|
|
167
|
-
this.ctx.save();
|
|
168
279
|
return InterpretedSymbol.of("t");
|
|
169
280
|
}
|
|
170
281
|
}
|
|
171
|
-
this
|
|
282
|
+
this.#print("Can not draw arc to.");
|
|
172
283
|
return Cons.nil;
|
|
173
284
|
} catch {
|
|
174
|
-
this
|
|
285
|
+
this.#print("Can not draw arc to.");
|
|
175
286
|
return Cons.nil;
|
|
176
287
|
}
|
|
177
|
-
this
|
|
288
|
+
this.#print("The canvas is closed and cannot be executed.");
|
|
178
289
|
return Cons.nil;
|
|
179
290
|
}
|
|
180
|
-
gBezCurveTo(
|
|
291
|
+
gBezCurveTo(arguments_) {
|
|
181
292
|
if (!this.checkSupport()) return Cons.nil;
|
|
182
293
|
if (this.isOpen) try {
|
|
183
|
-
if (
|
|
184
|
-
const a0 =
|
|
185
|
-
const cdr1 =
|
|
294
|
+
if (arguments_.length() === 6) {
|
|
295
|
+
const a0 = arguments_.car;
|
|
296
|
+
const cdr1 = arguments_.cdr;
|
|
186
297
|
const a1 = cdr1.car;
|
|
187
298
|
const cdr2 = cdr1.cdr;
|
|
188
299
|
const a2 = cdr2.car;
|
|
@@ -193,17 +304,16 @@ var GraphicsPlugin = class GraphicsPlugin extends Object {
|
|
|
193
304
|
const a5 = cdr4.cdr.car;
|
|
194
305
|
if (Cons.isNumber(a0) && Cons.isNumber(a1) && Cons.isNumber(a2) && Cons.isNumber(a3) && Cons.isNumber(a4) && Cons.isNumber(a5)) {
|
|
195
306
|
this.ctx.bezierCurveTo(a0, a1, a2, a3, a4, a5);
|
|
196
|
-
this.ctx.save();
|
|
197
307
|
return InterpretedSymbol.of("t");
|
|
198
308
|
}
|
|
199
309
|
}
|
|
200
|
-
this
|
|
310
|
+
this.#print("Can not draw bezier curve.");
|
|
201
311
|
return Cons.nil;
|
|
202
312
|
} catch {
|
|
203
|
-
this
|
|
313
|
+
this.#print("Can not draw bezier curve.");
|
|
204
314
|
return Cons.nil;
|
|
205
315
|
}
|
|
206
|
-
this
|
|
316
|
+
this.#print("The canvas is closed and cannot be executed.");
|
|
207
317
|
return Cons.nil;
|
|
208
318
|
}
|
|
209
319
|
gClear() {
|
|
@@ -212,13 +322,12 @@ var GraphicsPlugin = class GraphicsPlugin extends Object {
|
|
|
212
322
|
this.ctx.fillStyle = "#ffffff";
|
|
213
323
|
this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
|
|
214
324
|
this.ctx.fillStyle = "#000000";
|
|
215
|
-
this.ctx.save();
|
|
216
325
|
return InterpretedSymbol.of("t");
|
|
217
326
|
} catch {
|
|
218
|
-
this
|
|
327
|
+
this.#print("Can not clear.");
|
|
219
328
|
return Cons.nil;
|
|
220
329
|
}
|
|
221
|
-
this
|
|
330
|
+
this.#print("The canvas is closed and cannot be executed.");
|
|
222
331
|
return Cons.nil;
|
|
223
332
|
}
|
|
224
333
|
gClose() {
|
|
@@ -228,116 +337,111 @@ var GraphicsPlugin = class GraphicsPlugin extends Object {
|
|
|
228
337
|
this.isOpen = false;
|
|
229
338
|
return InterpretedSymbol.of("t");
|
|
230
339
|
} catch {
|
|
231
|
-
this
|
|
340
|
+
this.#print("Can not close.");
|
|
232
341
|
return Cons.nil;
|
|
233
342
|
}
|
|
234
|
-
this
|
|
343
|
+
this.#print("The canvas has already been closed.");
|
|
235
344
|
return Cons.nil;
|
|
236
345
|
}
|
|
237
|
-
gColor(
|
|
346
|
+
gColor(arguments_) {
|
|
238
347
|
if (!this.checkSupport()) return Cons.nil;
|
|
239
348
|
if (this.isOpen) try {
|
|
240
|
-
if (
|
|
241
|
-
const aColor = this.selectColor(
|
|
349
|
+
if (arguments_.length() >= 1) {
|
|
350
|
+
const aColor = this.selectColor(arguments_);
|
|
242
351
|
this.ctx.fillStyle = aColor;
|
|
243
352
|
this.ctx.strokeStyle = aColor;
|
|
244
|
-
this.ctx.save();
|
|
245
353
|
return InterpretedSymbol.of("t");
|
|
246
354
|
}
|
|
247
|
-
this
|
|
355
|
+
this.#print("Can not set color.");
|
|
248
356
|
return Cons.nil;
|
|
249
357
|
} catch {
|
|
250
|
-
this
|
|
358
|
+
this.#print("Can not set color.");
|
|
251
359
|
return Cons.nil;
|
|
252
360
|
}
|
|
253
|
-
this
|
|
361
|
+
this.#print("The canvas is closed and cannot be executed.");
|
|
254
362
|
return Cons.nil;
|
|
255
363
|
}
|
|
256
364
|
gFill() {
|
|
257
365
|
if (!this.checkSupport()) return Cons.nil;
|
|
258
366
|
if (this.isOpen) try {
|
|
259
367
|
this.ctx.fill();
|
|
260
|
-
this.ctx.save();
|
|
261
368
|
return InterpretedSymbol.of("t");
|
|
262
369
|
} catch {
|
|
263
|
-
this
|
|
370
|
+
this.#print("Can not fill.");
|
|
264
371
|
return Cons.nil;
|
|
265
372
|
}
|
|
266
|
-
this
|
|
373
|
+
this.#print("The canvas is closed and cannot be executed.");
|
|
267
374
|
return Cons.nil;
|
|
268
375
|
}
|
|
269
|
-
gFillColor(
|
|
376
|
+
gFillColor(arguments_) {
|
|
270
377
|
if (!this.checkSupport()) return Cons.nil;
|
|
271
378
|
if (this.isOpen) try {
|
|
272
|
-
if (
|
|
273
|
-
const aColor = this.selectColor(
|
|
379
|
+
if (arguments_.length() >= 1) {
|
|
380
|
+
const aColor = this.selectColor(arguments_);
|
|
274
381
|
this.ctx.fillStyle = aColor;
|
|
275
|
-
this.ctx.save();
|
|
276
382
|
return InterpretedSymbol.of("t");
|
|
277
383
|
}
|
|
278
|
-
this
|
|
384
|
+
this.#print("Can not set fill color.");
|
|
279
385
|
return Cons.nil;
|
|
280
386
|
} catch {
|
|
281
|
-
this
|
|
387
|
+
this.#print("Can not set fill color.");
|
|
282
388
|
return Cons.nil;
|
|
283
389
|
}
|
|
284
|
-
this
|
|
390
|
+
this.#print("The canvas is closed and cannot be executed.");
|
|
285
391
|
return Cons.nil;
|
|
286
392
|
}
|
|
287
|
-
gFillRect(
|
|
393
|
+
gFillRect(arguments_) {
|
|
288
394
|
if (!this.checkSupport()) return Cons.nil;
|
|
289
395
|
if (this.isOpen) try {
|
|
290
|
-
if (
|
|
291
|
-
const a0 =
|
|
292
|
-
const cdr1 =
|
|
396
|
+
if (arguments_.length() === 4) {
|
|
397
|
+
const a0 = arguments_.car;
|
|
398
|
+
const cdr1 = arguments_.cdr;
|
|
293
399
|
const a1 = cdr1.car;
|
|
294
400
|
const cdr2 = cdr1.cdr;
|
|
295
401
|
const a2 = cdr2.car;
|
|
296
402
|
const a3 = cdr2.cdr.car;
|
|
297
403
|
if (Cons.isNumber(a0) && Cons.isNumber(a1) && Cons.isNumber(a2) && Cons.isNumber(a3)) {
|
|
298
404
|
this.ctx.fillRect(a0, a1, a2, a3);
|
|
299
|
-
this.ctx.save();
|
|
300
405
|
return InterpretedSymbol.of("t");
|
|
301
406
|
}
|
|
302
407
|
}
|
|
303
|
-
this
|
|
408
|
+
this.#print("Can not draw fill rectangle.");
|
|
304
409
|
return Cons.nil;
|
|
305
410
|
} catch {
|
|
306
|
-
this
|
|
411
|
+
this.#print("Can not draw fill rectangle.");
|
|
307
412
|
return Cons.nil;
|
|
308
413
|
}
|
|
309
|
-
this
|
|
414
|
+
this.#print("The canvas is closed and cannot be executed.");
|
|
310
415
|
return Cons.nil;
|
|
311
416
|
}
|
|
312
|
-
gFillText(
|
|
417
|
+
gFillText(arguments_) {
|
|
313
418
|
if (!this.checkSupport()) return Cons.nil;
|
|
314
419
|
if (this.isOpen) try {
|
|
315
|
-
if (
|
|
316
|
-
const a0 =
|
|
317
|
-
const cdr1 =
|
|
420
|
+
if (arguments_.length() === 3) {
|
|
421
|
+
const a0 = arguments_.car;
|
|
422
|
+
const cdr1 = arguments_.cdr;
|
|
318
423
|
const a1 = cdr1.car;
|
|
319
424
|
const a2 = cdr1.cdr.car;
|
|
320
425
|
if (Cons.isString(a0) && Cons.isNumber(a1) && Cons.isNumber(a2)) {
|
|
321
426
|
this.ctx.fillText(a0, a1, a2);
|
|
322
|
-
this.ctx.save();
|
|
323
427
|
return InterpretedSymbol.of("t");
|
|
324
428
|
}
|
|
325
429
|
}
|
|
326
|
-
this
|
|
430
|
+
this.#print("Can not draw fill text.");
|
|
327
431
|
return Cons.nil;
|
|
328
432
|
} catch {
|
|
329
|
-
this
|
|
433
|
+
this.#print("Can not draw fill text.");
|
|
330
434
|
return Cons.nil;
|
|
331
435
|
}
|
|
332
|
-
this
|
|
436
|
+
this.#print("The canvas is closed and cannot be executed.");
|
|
333
437
|
return Cons.nil;
|
|
334
438
|
}
|
|
335
|
-
gFillTri(
|
|
439
|
+
gFillTri(arguments_) {
|
|
336
440
|
if (!this.checkSupport()) return Cons.nil;
|
|
337
441
|
if (this.isOpen) try {
|
|
338
|
-
if (
|
|
339
|
-
const a0 =
|
|
340
|
-
const cdr1 =
|
|
442
|
+
if (arguments_.length() === 6) {
|
|
443
|
+
const a0 = arguments_.car;
|
|
444
|
+
const cdr1 = arguments_.cdr;
|
|
341
445
|
const a1 = cdr1.car;
|
|
342
446
|
const cdr2 = cdr1.cdr;
|
|
343
447
|
const a2 = cdr2.car;
|
|
@@ -352,54 +456,51 @@ var GraphicsPlugin = class GraphicsPlugin extends Object {
|
|
|
352
456
|
this.ctx.lineTo(a2, a3);
|
|
353
457
|
this.ctx.lineTo(a4, a5);
|
|
354
458
|
this.ctx.fill();
|
|
355
|
-
this.ctx.save();
|
|
356
459
|
return InterpretedSymbol.of("t");
|
|
357
460
|
}
|
|
358
461
|
}
|
|
359
|
-
this
|
|
462
|
+
this.#print("Can not draw fill triangle.");
|
|
360
463
|
return Cons.nil;
|
|
361
464
|
} catch {
|
|
362
|
-
this
|
|
465
|
+
this.#print("Can not draw fill triangle.");
|
|
363
466
|
return Cons.nil;
|
|
364
467
|
}
|
|
365
|
-
this
|
|
468
|
+
this.#print("The canvas is closed and cannot be executed.");
|
|
366
469
|
return Cons.nil;
|
|
367
470
|
}
|
|
368
471
|
gFinishPath() {
|
|
369
472
|
if (!this.checkSupport()) return Cons.nil;
|
|
370
473
|
if (this.isOpen) try {
|
|
371
474
|
this.ctx.closePath();
|
|
372
|
-
this.ctx.save();
|
|
373
475
|
return InterpretedSymbol.of("t");
|
|
374
476
|
} catch {
|
|
375
|
-
this
|
|
477
|
+
this.#print("Can not finish path.");
|
|
376
478
|
return Cons.nil;
|
|
377
479
|
}
|
|
378
|
-
this
|
|
480
|
+
this.#print("The canvas is closed and cannot be executed.");
|
|
379
481
|
return Cons.nil;
|
|
380
482
|
}
|
|
381
|
-
gImage(
|
|
483
|
+
gImage(arguments_) {
|
|
382
484
|
if (!this.checkSupport()) return Cons.nil;
|
|
383
485
|
if (this.isOpen) try {
|
|
384
|
-
const
|
|
385
|
-
if (
|
|
386
|
-
const a0 =
|
|
387
|
-
const cdr1 =
|
|
486
|
+
const length_ = arguments_.length();
|
|
487
|
+
if (length_ === 3) {
|
|
488
|
+
const a0 = arguments_.car;
|
|
489
|
+
const cdr1 = arguments_.cdr;
|
|
388
490
|
const a1 = cdr1.car;
|
|
389
491
|
const a2 = cdr1.cdr.car;
|
|
390
492
|
if (Cons.isString(a0) && Cons.isNumber(a1) && Cons.isNumber(a2)) {
|
|
391
|
-
const
|
|
493
|
+
const context = this.ctx;
|
|
392
494
|
const anImage = new Image();
|
|
393
495
|
anImage.src = a0;
|
|
394
496
|
anImage.onload = () => {
|
|
395
|
-
|
|
497
|
+
context.drawImage(anImage, a1, a2);
|
|
396
498
|
};
|
|
397
|
-
ctx.save();
|
|
398
499
|
return InterpretedSymbol.of("t");
|
|
399
500
|
}
|
|
400
|
-
} else if (
|
|
401
|
-
const a0 =
|
|
402
|
-
const cdr1 =
|
|
501
|
+
} else if (length_ === 5) {
|
|
502
|
+
const a0 = arguments_.car;
|
|
503
|
+
const cdr1 = arguments_.cdr;
|
|
403
504
|
const a1 = cdr1.car;
|
|
404
505
|
const cdr2 = cdr1.cdr;
|
|
405
506
|
const a2 = cdr2.car;
|
|
@@ -407,119 +508,111 @@ var GraphicsPlugin = class GraphicsPlugin extends Object {
|
|
|
407
508
|
const a3 = cdr3.car;
|
|
408
509
|
const a4 = cdr3.cdr.car;
|
|
409
510
|
if (Cons.isString(a0) && Cons.isNumber(a1) && Cons.isNumber(a2) && Cons.isNumber(a3) && Cons.isNumber(a4)) {
|
|
410
|
-
const
|
|
511
|
+
const context = this.ctx;
|
|
411
512
|
const anImage = new Image();
|
|
412
513
|
anImage.src = a0;
|
|
413
514
|
anImage.onload = () => {
|
|
414
|
-
|
|
515
|
+
context.drawImage(anImage, a1, a2, a3, a4);
|
|
415
516
|
};
|
|
416
|
-
ctx.save();
|
|
417
517
|
return InterpretedSymbol.of("t");
|
|
418
518
|
}
|
|
419
519
|
}
|
|
420
|
-
this
|
|
520
|
+
this.#print("Can not draw Image.");
|
|
421
521
|
return Cons.nil;
|
|
422
522
|
} catch {
|
|
423
|
-
this
|
|
523
|
+
this.#print("Can not draw Image.");
|
|
424
524
|
return Cons.nil;
|
|
425
525
|
}
|
|
426
|
-
this
|
|
526
|
+
this.#print("The canvas is closed and cannot be executed.");
|
|
427
527
|
return Cons.nil;
|
|
428
528
|
}
|
|
429
|
-
gLineTo(
|
|
529
|
+
gLineTo(arguments_) {
|
|
430
530
|
if (!this.checkSupport()) return Cons.nil;
|
|
431
531
|
if (this.isOpen) try {
|
|
432
|
-
if (
|
|
433
|
-
const a0 =
|
|
434
|
-
const a1 =
|
|
532
|
+
if (arguments_.length() === 2) {
|
|
533
|
+
const a0 = arguments_.car;
|
|
534
|
+
const a1 = arguments_.cdr.car;
|
|
435
535
|
if (Cons.isNumber(a0) && Cons.isNumber(a1)) {
|
|
436
536
|
this.ctx.lineTo(a0, a1);
|
|
437
|
-
this.ctx.save();
|
|
438
537
|
return InterpretedSymbol.of("t");
|
|
439
538
|
}
|
|
440
539
|
}
|
|
441
|
-
this
|
|
540
|
+
this.#print("Can not draw line to");
|
|
442
541
|
return Cons.nil;
|
|
443
542
|
} catch {
|
|
444
|
-
this
|
|
543
|
+
this.#print("Can not draw line to");
|
|
445
544
|
return Cons.nil;
|
|
446
545
|
}
|
|
447
|
-
this
|
|
546
|
+
this.#print("The canvas is closed and cannot be executed.");
|
|
448
547
|
return Cons.nil;
|
|
449
548
|
}
|
|
450
|
-
gLineCap(
|
|
549
|
+
gLineCap(arguments_) {
|
|
451
550
|
if (!this.checkSupport()) return Cons.nil;
|
|
452
551
|
if (this.isOpen) try {
|
|
453
|
-
if (
|
|
454
|
-
|
|
455
|
-
this.ctx.lineCap = aString;
|
|
456
|
-
this.ctx.save();
|
|
552
|
+
if (arguments_.length() === 1 && Cons.isString(arguments_.car)) {
|
|
553
|
+
this.ctx.lineCap = arguments_.car;
|
|
457
554
|
return InterpretedSymbol.of("t");
|
|
458
555
|
}
|
|
459
|
-
this
|
|
556
|
+
this.#print("Can not set line cap.");
|
|
460
557
|
return Cons.nil;
|
|
461
558
|
} catch {
|
|
462
|
-
this
|
|
559
|
+
this.#print("Can not set line cap.");
|
|
463
560
|
return Cons.nil;
|
|
464
561
|
}
|
|
465
|
-
this
|
|
562
|
+
this.#print("The canvas is closed and cannot be executed.");
|
|
466
563
|
return Cons.nil;
|
|
467
564
|
}
|
|
468
|
-
gLineJoin(
|
|
565
|
+
gLineJoin(arguments_) {
|
|
469
566
|
if (!this.checkSupport()) return Cons.nil;
|
|
470
567
|
if (this.isOpen) try {
|
|
471
|
-
if (
|
|
472
|
-
|
|
473
|
-
this.ctx.lineJoin = aString;
|
|
474
|
-
this.ctx.save();
|
|
568
|
+
if (arguments_.length() === 1 && Cons.isString(arguments_.car)) {
|
|
569
|
+
this.ctx.lineJoin = arguments_.car;
|
|
475
570
|
return InterpretedSymbol.of("t");
|
|
476
571
|
}
|
|
477
|
-
this
|
|
572
|
+
this.#print("Can not set line join.");
|
|
478
573
|
return Cons.nil;
|
|
479
574
|
} catch {
|
|
480
|
-
this
|
|
575
|
+
this.#print("Can not set line join.");
|
|
481
576
|
return Cons.nil;
|
|
482
577
|
}
|
|
483
|
-
this
|
|
578
|
+
this.#print("The canvas is closed and cannot be executed.");
|
|
484
579
|
return Cons.nil;
|
|
485
580
|
}
|
|
486
|
-
gLineWidth(
|
|
581
|
+
gLineWidth(arguments_) {
|
|
487
582
|
if (!this.checkSupport()) return Cons.nil;
|
|
488
583
|
if (this.isOpen) try {
|
|
489
|
-
if (
|
|
490
|
-
const aNumber =
|
|
584
|
+
if (arguments_.length() === 1 && Cons.isNumber(arguments_.car)) {
|
|
585
|
+
const aNumber = arguments_.car <= 0 ? 1 : arguments_.car;
|
|
491
586
|
this.ctx.lineWidth = aNumber;
|
|
492
|
-
this.ctx.save();
|
|
493
587
|
return InterpretedSymbol.of("t");
|
|
494
588
|
}
|
|
495
|
-
this
|
|
589
|
+
this.#print("Can not set line width.");
|
|
496
590
|
return Cons.nil;
|
|
497
591
|
} catch {
|
|
498
|
-
this
|
|
592
|
+
this.#print("Can not set line width.");
|
|
499
593
|
return Cons.nil;
|
|
500
594
|
}
|
|
501
|
-
this
|
|
595
|
+
this.#print("The canvas is closed and cannot be executed.");
|
|
502
596
|
return Cons.nil;
|
|
503
597
|
}
|
|
504
|
-
gMoveTo(
|
|
598
|
+
gMoveTo(arguments_) {
|
|
505
599
|
if (!this.checkSupport()) return Cons.nil;
|
|
506
600
|
if (this.isOpen) try {
|
|
507
|
-
if (
|
|
508
|
-
const a0 =
|
|
509
|
-
const a1 =
|
|
601
|
+
if (arguments_.length() === 2) {
|
|
602
|
+
const a0 = arguments_.car;
|
|
603
|
+
const a1 = arguments_.cdr.car;
|
|
510
604
|
if (Cons.isNumber(a0) && Cons.isNumber(a1)) {
|
|
511
605
|
this.ctx.moveTo(a0, a1);
|
|
512
|
-
this.ctx.save();
|
|
513
606
|
return InterpretedSymbol.of("t");
|
|
514
607
|
}
|
|
515
608
|
}
|
|
516
|
-
this
|
|
609
|
+
this.#print("Can not move");
|
|
517
610
|
return Cons.nil;
|
|
518
611
|
} catch {
|
|
519
|
-
this
|
|
612
|
+
this.#print("Can not move");
|
|
520
613
|
return Cons.nil;
|
|
521
614
|
}
|
|
522
|
-
this
|
|
615
|
+
this.#print("The canvas is closed and cannot be executed.");
|
|
523
616
|
return Cons.nil;
|
|
524
617
|
}
|
|
525
618
|
gOpen() {
|
|
@@ -529,304 +622,278 @@ var GraphicsPlugin = class GraphicsPlugin extends Object {
|
|
|
529
622
|
this.ctx.fillStyle = "#ffffff";
|
|
530
623
|
this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
|
|
531
624
|
this.ctx.fillStyle = "#000000";
|
|
532
|
-
this.
|
|
533
|
-
this._print("canvas size, width : 600 height : 300");
|
|
625
|
+
this.#print(`canvas size, width : ${this.canvas.width} height : ${this.canvas.height}`);
|
|
534
626
|
return InterpretedSymbol.of("t");
|
|
535
627
|
} catch {
|
|
536
|
-
this
|
|
628
|
+
this.#print("Can not open.");
|
|
537
629
|
return Cons.nil;
|
|
538
630
|
}
|
|
539
|
-
this
|
|
631
|
+
this.#print("The canvas has already been opened.");
|
|
540
632
|
return Cons.nil;
|
|
541
633
|
}
|
|
542
|
-
gPattern(
|
|
634
|
+
gPattern(arguments_) {
|
|
543
635
|
if (!this.checkSupport()) return Cons.nil;
|
|
544
636
|
if (this.isOpen) try {
|
|
545
|
-
if (
|
|
546
|
-
const a0 =
|
|
547
|
-
const a1 =
|
|
637
|
+
if (arguments_.length() === 2) {
|
|
638
|
+
const a0 = arguments_.car;
|
|
639
|
+
const a1 = arguments_.cdr.car;
|
|
548
640
|
if (Cons.isString(a0) && Cons.isNumber(a1)) {
|
|
549
641
|
const aString = a1 === 0 ? "repeat" : a1 > 0 ? "repeat-x" : "repeat-y";
|
|
550
|
-
const
|
|
642
|
+
const context = this.ctx;
|
|
551
643
|
const anImage = new Image();
|
|
552
644
|
anImage.src = a0;
|
|
553
645
|
anImage.onload = () => {
|
|
554
|
-
|
|
646
|
+
context.fillStyle = context.createPattern(anImage, aString);
|
|
555
647
|
};
|
|
556
|
-
ctx.save();
|
|
557
648
|
return InterpretedSymbol.of("t");
|
|
558
649
|
}
|
|
559
650
|
}
|
|
560
|
-
this
|
|
651
|
+
this.#print("Can not set pattern.");
|
|
561
652
|
return Cons.nil;
|
|
562
653
|
} catch {
|
|
563
|
-
this
|
|
654
|
+
this.#print("Can not set pattern.");
|
|
564
655
|
return Cons.nil;
|
|
565
656
|
}
|
|
566
|
-
this
|
|
657
|
+
this.#print("The canvas is closed and cannot be executed.");
|
|
567
658
|
return Cons.nil;
|
|
568
659
|
}
|
|
569
|
-
gQuadCurveTo(
|
|
660
|
+
gQuadCurveTo(arguments_) {
|
|
570
661
|
if (!this.checkSupport()) return Cons.nil;
|
|
571
662
|
if (this.isOpen) try {
|
|
572
|
-
if (
|
|
573
|
-
const a0 =
|
|
574
|
-
const cdr1 =
|
|
663
|
+
if (arguments_.length() === 4) {
|
|
664
|
+
const a0 = arguments_.car;
|
|
665
|
+
const cdr1 = arguments_.cdr;
|
|
575
666
|
const a1 = cdr1.car;
|
|
576
667
|
const cdr2 = cdr1.cdr;
|
|
577
668
|
const a2 = cdr2.car;
|
|
578
669
|
const a3 = cdr2.cdr.car;
|
|
579
670
|
if (Cons.isNumber(a0) && Cons.isNumber(a1) && Cons.isNumber(a2) && Cons.isNumber(a3)) {
|
|
580
671
|
this.ctx.quadraticCurveTo(a0, a1, a2, a3);
|
|
581
|
-
this.ctx.save();
|
|
582
672
|
return InterpretedSymbol.of("t");
|
|
583
673
|
}
|
|
584
674
|
}
|
|
585
|
-
this
|
|
675
|
+
this.#print("Can not draw quadratic curve.");
|
|
586
676
|
return Cons.nil;
|
|
587
677
|
} catch {
|
|
588
|
-
this
|
|
678
|
+
this.#print("Can not draw quadratic curve.");
|
|
589
679
|
return Cons.nil;
|
|
590
680
|
}
|
|
591
|
-
this
|
|
681
|
+
this.#print("The canvas is closed and cannot be executed.");
|
|
592
682
|
return Cons.nil;
|
|
593
683
|
}
|
|
594
|
-
gSaveJpeg() {
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
anImage.src = this.canvas.toDataURL("image/jpeg");
|
|
600
|
-
const link = document.createElement("a");
|
|
601
|
-
link.href = anImage.src;
|
|
602
|
-
link.download = "canvas";
|
|
603
|
-
document.body.append(link);
|
|
604
|
-
link.click();
|
|
605
|
-
link.remove();
|
|
606
|
-
return InterpretedSymbol.of("t");
|
|
607
|
-
} catch {
|
|
608
|
-
this._print("Can not save jpeg. If you are using an image in the canvas, you can't save jpeg.");
|
|
609
|
-
return Cons.nil;
|
|
610
|
-
}
|
|
611
|
-
this._print("The canvas is closed and cannot be executed.");
|
|
612
|
-
return Cons.nil;
|
|
684
|
+
gSaveJpeg(arguments_) {
|
|
685
|
+
return this.saveCanvas(arguments_, "image/jpeg", "jpeg");
|
|
686
|
+
}
|
|
687
|
+
gSavePng(arguments_) {
|
|
688
|
+
return this.saveCanvas(arguments_, "image/png", "png");
|
|
613
689
|
}
|
|
614
|
-
|
|
690
|
+
/**
|
|
691
|
+
* Shared implementation of `gsave-jpeg` / `gsave-png`. With no argument it
|
|
692
|
+
* triggers a browser download; with a single string argument it writes the
|
|
693
|
+
* encoded image to that file path on Node.js.
|
|
694
|
+
* @param arguments_ - the evaluated argument list (empty, or one path string)
|
|
695
|
+
* @param mimeType - the image MIME type to encode
|
|
696
|
+
* @param label - the format name used in diagnostics ("jpeg" / "png")
|
|
697
|
+
* @return `t` on success, `Cons.nil` otherwise
|
|
698
|
+
*/
|
|
699
|
+
saveCanvas(arguments_, mimeType, label) {
|
|
615
700
|
if (!this.checkSupport()) return Cons.nil;
|
|
616
|
-
if (this.isOpen)
|
|
617
|
-
const
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
link.href = anImage.src;
|
|
622
|
-
link.download = "canvas";
|
|
623
|
-
document.body.append(link);
|
|
624
|
-
link.click();
|
|
625
|
-
link.remove();
|
|
626
|
-
return InterpretedSymbol.of("t");
|
|
627
|
-
} catch {
|
|
628
|
-
this._print("Can not save png. If you are using an image in the canvas, you can't save png.");
|
|
701
|
+
if (this.isOpen) {
|
|
702
|
+
const length_ = arguments_.length();
|
|
703
|
+
if (length_ === 0) return this.#downloadCanvas(mimeType, label);
|
|
704
|
+
if (length_ === 1 && Cons.isString(arguments_.car)) return this.#writeCanvasToFile(arguments_.car, mimeType, label);
|
|
705
|
+
this.#print(`Can not save ${label}.`);
|
|
629
706
|
return Cons.nil;
|
|
630
707
|
}
|
|
631
|
-
this
|
|
708
|
+
this.#print("The canvas is closed and cannot be executed.");
|
|
632
709
|
return Cons.nil;
|
|
633
710
|
}
|
|
634
|
-
gScale(
|
|
711
|
+
gScale(arguments_) {
|
|
635
712
|
if (!this.checkSupport()) return Cons.nil;
|
|
636
713
|
if (this.isOpen) try {
|
|
637
|
-
if (
|
|
638
|
-
const a0 =
|
|
639
|
-
const a1 =
|
|
714
|
+
if (arguments_.length() === 2) {
|
|
715
|
+
const a0 = arguments_.car;
|
|
716
|
+
const a1 = arguments_.cdr.car;
|
|
640
717
|
if (Cons.isNumber(a0) && Cons.isNumber(a1)) {
|
|
641
718
|
this.ctx.scale(a0, a1);
|
|
642
|
-
this.ctx.save();
|
|
643
719
|
return InterpretedSymbol.of("t");
|
|
644
720
|
}
|
|
645
721
|
}
|
|
646
|
-
this
|
|
722
|
+
this.#print("Can not scale.");
|
|
647
723
|
return Cons.nil;
|
|
648
724
|
} catch {
|
|
649
|
-
this
|
|
725
|
+
this.#print("Can not scale.");
|
|
650
726
|
return Cons.nil;
|
|
651
727
|
}
|
|
652
|
-
this
|
|
728
|
+
this.#print("The canvas is closed and cannot be executed.");
|
|
653
729
|
return Cons.nil;
|
|
654
730
|
}
|
|
655
|
-
gShadowBlur(
|
|
731
|
+
gShadowBlur(arguments_) {
|
|
656
732
|
if (!this.checkSupport()) return Cons.nil;
|
|
657
733
|
if (this.isOpen) {
|
|
658
|
-
if (
|
|
659
|
-
this.ctx.
|
|
660
|
-
this.ctx.save();
|
|
734
|
+
if (arguments_.length() === 1 && Cons.isNumber(arguments_.car)) {
|
|
735
|
+
this.ctx.shadowBlur = arguments_.car;
|
|
661
736
|
return InterpretedSymbol.of("t");
|
|
662
737
|
}
|
|
663
|
-
this
|
|
738
|
+
this.#print("Can not set shadow blur.");
|
|
664
739
|
return Cons.nil;
|
|
665
740
|
}
|
|
666
|
-
this
|
|
741
|
+
this.#print("The canvas is closed and cannot be executed.");
|
|
667
742
|
return Cons.nil;
|
|
668
743
|
}
|
|
669
|
-
gShadowColor(
|
|
744
|
+
gShadowColor(arguments_) {
|
|
670
745
|
if (!this.checkSupport()) return Cons.nil;
|
|
671
746
|
if (this.isOpen) try {
|
|
672
|
-
if (
|
|
673
|
-
const aColor = this.selectColor(
|
|
747
|
+
if (arguments_.length() === 1) {
|
|
748
|
+
const aColor = this.selectColor(arguments_);
|
|
674
749
|
this.ctx.shadowColor = aColor;
|
|
675
|
-
this.ctx.save();
|
|
676
750
|
return InterpretedSymbol.of("t");
|
|
677
751
|
}
|
|
678
|
-
this
|
|
752
|
+
this.#print("Can not set shadow color.");
|
|
679
753
|
return Cons.nil;
|
|
680
754
|
} catch {
|
|
681
|
-
this
|
|
755
|
+
this.#print("Can not set shadow color.");
|
|
682
756
|
return Cons.nil;
|
|
683
757
|
}
|
|
684
|
-
this
|
|
758
|
+
this.#print("The canvas is closed and cannot be executed.");
|
|
685
759
|
return Cons.nil;
|
|
686
760
|
}
|
|
687
|
-
gShadowOffsetX(
|
|
761
|
+
gShadowOffsetX(arguments_) {
|
|
688
762
|
if (!this.checkSupport()) return Cons.nil;
|
|
689
763
|
if (this.isOpen) {
|
|
690
|
-
if (
|
|
691
|
-
this.ctx.shadowOffsetX =
|
|
692
|
-
this.ctx.save();
|
|
764
|
+
if (arguments_.length() === 1 && Cons.isNumber(arguments_.car)) {
|
|
765
|
+
this.ctx.shadowOffsetX = arguments_.car;
|
|
693
766
|
return InterpretedSymbol.of("t");
|
|
694
767
|
}
|
|
695
|
-
this
|
|
768
|
+
this.#print("Can not set shadow offsetX.");
|
|
696
769
|
return Cons.nil;
|
|
697
770
|
}
|
|
698
|
-
this
|
|
771
|
+
this.#print("The canvas is closed and cannot be executed.");
|
|
699
772
|
return Cons.nil;
|
|
700
773
|
}
|
|
701
|
-
gShadowOffsetY(
|
|
774
|
+
gShadowOffsetY(arguments_) {
|
|
702
775
|
if (!this.checkSupport()) return Cons.nil;
|
|
703
776
|
if (this.isOpen) {
|
|
704
|
-
if (
|
|
705
|
-
this.ctx.shadowOffsetY =
|
|
706
|
-
this.ctx.save();
|
|
777
|
+
if (arguments_.length() === 1 && Cons.isNumber(arguments_.car)) {
|
|
778
|
+
this.ctx.shadowOffsetY = arguments_.car;
|
|
707
779
|
return InterpretedSymbol.of("t");
|
|
708
780
|
}
|
|
709
|
-
this
|
|
781
|
+
this.#print("Can not set shadow offsetY.");
|
|
710
782
|
return Cons.nil;
|
|
711
783
|
}
|
|
712
|
-
this
|
|
784
|
+
this.#print("The canvas is closed and cannot be executed.");
|
|
713
785
|
return Cons.nil;
|
|
714
786
|
}
|
|
715
|
-
gSleep(
|
|
787
|
+
gSleep(arguments_) {
|
|
716
788
|
if (!this.checkSupport()) return Cons.nil;
|
|
717
789
|
if (this.isOpen) {
|
|
718
790
|
const sleep = (ms) => {
|
|
719
791
|
const time = Date.now() + ms;
|
|
720
792
|
while (Date.now() < time);
|
|
721
793
|
};
|
|
722
|
-
if (
|
|
723
|
-
sleep(
|
|
794
|
+
if (arguments_.length() === 1 && Cons.isNumber(arguments_.car)) {
|
|
795
|
+
sleep(arguments_.car);
|
|
724
796
|
return InterpretedSymbol.of("t");
|
|
725
797
|
}
|
|
726
|
-
this
|
|
798
|
+
this.#print("Can not sleep");
|
|
727
799
|
return Cons.nil;
|
|
728
800
|
}
|
|
729
|
-
this
|
|
801
|
+
this.#print("The canvas is closed and cannot be executed.");
|
|
730
802
|
return Cons.nil;
|
|
731
803
|
}
|
|
732
804
|
gStartPath() {
|
|
733
805
|
if (!this.checkSupport()) return Cons.nil;
|
|
734
806
|
if (this.isOpen) try {
|
|
735
807
|
this.ctx.beginPath();
|
|
736
|
-
this.ctx.save();
|
|
737
808
|
return InterpretedSymbol.of("t");
|
|
738
809
|
} catch {
|
|
739
|
-
this
|
|
810
|
+
this.#print("Can not start path.");
|
|
740
811
|
return Cons.nil;
|
|
741
812
|
}
|
|
742
|
-
this
|
|
813
|
+
this.#print("The canvas is closed and cannot be executed.");
|
|
743
814
|
return Cons.nil;
|
|
744
815
|
}
|
|
745
816
|
gStroke() {
|
|
746
817
|
if (!this.checkSupport()) return Cons.nil;
|
|
747
818
|
if (this.isOpen) try {
|
|
748
819
|
this.ctx.stroke();
|
|
749
|
-
this.ctx.save();
|
|
750
820
|
return InterpretedSymbol.of("t");
|
|
751
821
|
} catch {
|
|
752
|
-
this
|
|
822
|
+
this.#print("Can not stroke.");
|
|
753
823
|
return Cons.nil;
|
|
754
824
|
}
|
|
755
|
-
this
|
|
825
|
+
this.#print("The canvas is closed and cannot be executed.");
|
|
756
826
|
return Cons.nil;
|
|
757
827
|
}
|
|
758
|
-
gStrokeColor(
|
|
828
|
+
gStrokeColor(arguments_) {
|
|
759
829
|
if (!this.checkSupport()) return Cons.nil;
|
|
760
830
|
if (this.isOpen) try {
|
|
761
|
-
if (
|
|
762
|
-
const aColor = this.selectColor(
|
|
831
|
+
if (arguments_.length() >= 1) {
|
|
832
|
+
const aColor = this.selectColor(arguments_);
|
|
763
833
|
this.ctx.strokeStyle = aColor;
|
|
764
|
-
this.ctx.save();
|
|
765
834
|
return InterpretedSymbol.of("t");
|
|
766
835
|
}
|
|
767
|
-
this
|
|
836
|
+
this.#print("Can not set stroke color");
|
|
768
837
|
return Cons.nil;
|
|
769
838
|
} catch {
|
|
770
|
-
this
|
|
839
|
+
this.#print("Can not set stroke color");
|
|
771
840
|
return Cons.nil;
|
|
772
841
|
}
|
|
773
|
-
this
|
|
842
|
+
this.#print("The canvas is closed and cannot be executed.");
|
|
774
843
|
return Cons.nil;
|
|
775
844
|
}
|
|
776
|
-
gStrokeRect(
|
|
845
|
+
gStrokeRect(arguments_) {
|
|
777
846
|
if (!this.checkSupport()) return Cons.nil;
|
|
778
847
|
if (this.isOpen) try {
|
|
779
|
-
if (
|
|
780
|
-
const a0 =
|
|
781
|
-
const cdr1 =
|
|
848
|
+
if (arguments_.length() === 4) {
|
|
849
|
+
const a0 = arguments_.car;
|
|
850
|
+
const cdr1 = arguments_.cdr;
|
|
782
851
|
const a1 = cdr1.car;
|
|
783
852
|
const cdr2 = cdr1.cdr;
|
|
784
853
|
const a2 = cdr2.car;
|
|
785
854
|
const a3 = cdr2.cdr.car;
|
|
786
855
|
if (Cons.isNumber(a0) && Cons.isNumber(a1) && Cons.isNumber(a2) && Cons.isNumber(a3)) {
|
|
787
856
|
this.ctx.strokeRect(a0, a1, a2, a3);
|
|
788
|
-
this.ctx.save();
|
|
789
857
|
return InterpretedSymbol.of("t");
|
|
790
858
|
}
|
|
791
859
|
}
|
|
792
|
-
this
|
|
860
|
+
this.#print("Can not draw stroke rectangle.");
|
|
793
861
|
return Cons.nil;
|
|
794
862
|
} catch {
|
|
795
|
-
this
|
|
863
|
+
this.#print("Can not draw stroke rectangle.");
|
|
796
864
|
return Cons.nil;
|
|
797
865
|
}
|
|
798
|
-
this
|
|
866
|
+
this.#print("The canvas is closed and cannot be executed.");
|
|
799
867
|
return Cons.nil;
|
|
800
868
|
}
|
|
801
|
-
gStrokeText(
|
|
869
|
+
gStrokeText(arguments_) {
|
|
802
870
|
if (!this.checkSupport()) return Cons.nil;
|
|
803
871
|
if (this.isOpen) try {
|
|
804
|
-
if (
|
|
805
|
-
const a0 =
|
|
806
|
-
const cdr1 =
|
|
872
|
+
if (arguments_.length() === 3) {
|
|
873
|
+
const a0 = arguments_.car;
|
|
874
|
+
const cdr1 = arguments_.cdr;
|
|
807
875
|
const a1 = cdr1.car;
|
|
808
876
|
const a2 = cdr1.cdr.car;
|
|
809
877
|
if (Cons.isString(a0) && Cons.isNumber(a1) && Cons.isNumber(a2)) {
|
|
810
878
|
this.ctx.strokeText(a0, a1, a2);
|
|
811
|
-
this.ctx.save();
|
|
812
879
|
return InterpretedSymbol.of("t");
|
|
813
880
|
}
|
|
814
881
|
}
|
|
815
|
-
this
|
|
882
|
+
this.#print("Can not draw stroke text.");
|
|
816
883
|
return Cons.nil;
|
|
817
884
|
} catch {
|
|
818
|
-
this
|
|
885
|
+
this.#print("Can not draw stroke text.");
|
|
819
886
|
return Cons.nil;
|
|
820
887
|
}
|
|
821
|
-
this
|
|
888
|
+
this.#print("The canvas is closed and cannot be executed.");
|
|
822
889
|
return Cons.nil;
|
|
823
890
|
}
|
|
824
|
-
gStrokeTri(
|
|
891
|
+
gStrokeTri(arguments_) {
|
|
825
892
|
if (!this.checkSupport()) return Cons.nil;
|
|
826
893
|
if (this.isOpen) try {
|
|
827
|
-
if (
|
|
828
|
-
const a0 =
|
|
829
|
-
const cdr1 =
|
|
894
|
+
if (arguments_.length() === 6) {
|
|
895
|
+
const a0 = arguments_.car;
|
|
896
|
+
const cdr1 = arguments_.cdr;
|
|
830
897
|
const a1 = cdr1.car;
|
|
831
898
|
const cdr2 = cdr1.cdr;
|
|
832
899
|
const a2 = cdr2.car;
|
|
@@ -842,231 +909,208 @@ var GraphicsPlugin = class GraphicsPlugin extends Object {
|
|
|
842
909
|
this.ctx.lineTo(a4, a5);
|
|
843
910
|
this.ctx.closePath();
|
|
844
911
|
this.ctx.stroke();
|
|
845
|
-
this.ctx.save();
|
|
846
912
|
return InterpretedSymbol.of("t");
|
|
847
913
|
}
|
|
848
914
|
}
|
|
849
|
-
this
|
|
915
|
+
this.#print("Can not draw stroke triangle.");
|
|
850
916
|
return Cons.nil;
|
|
851
917
|
} catch {
|
|
852
|
-
this
|
|
918
|
+
this.#print("Can not draw stroke triangle.");
|
|
853
919
|
return Cons.nil;
|
|
854
920
|
}
|
|
855
|
-
this
|
|
921
|
+
this.#print("The canvas is closed and cannot be executed.");
|
|
856
922
|
return Cons.nil;
|
|
857
923
|
}
|
|
858
|
-
gTextAlign(
|
|
924
|
+
gTextAlign(arguments_) {
|
|
859
925
|
if (!this.checkSupport()) return Cons.nil;
|
|
860
926
|
if (this.isOpen) try {
|
|
861
|
-
if (
|
|
862
|
-
this.ctx.textAlign =
|
|
863
|
-
this.ctx.save();
|
|
927
|
+
if (arguments_.length() === 1 && Cons.isString(arguments_.car)) {
|
|
928
|
+
this.ctx.textAlign = arguments_.car;
|
|
864
929
|
return InterpretedSymbol.of("t");
|
|
865
930
|
}
|
|
866
|
-
this
|
|
931
|
+
this.#print("Can not set text align.");
|
|
867
932
|
return Cons.nil;
|
|
868
933
|
} catch {
|
|
869
|
-
this
|
|
934
|
+
this.#print("Can not set text align.");
|
|
870
935
|
return Cons.nil;
|
|
871
936
|
}
|
|
872
|
-
this
|
|
937
|
+
this.#print("The canvas is closed and cannot be executed.");
|
|
873
938
|
return Cons.nil;
|
|
874
939
|
}
|
|
875
|
-
gTextBaseline(
|
|
940
|
+
gTextBaseline(arguments_) {
|
|
876
941
|
if (!this.checkSupport()) return Cons.nil;
|
|
877
942
|
if (this.isOpen) try {
|
|
878
|
-
if (
|
|
879
|
-
this.ctx.textBaseline =
|
|
880
|
-
this.ctx.save();
|
|
943
|
+
if (arguments_.length() === 1 && Cons.isString(arguments_.car)) {
|
|
944
|
+
this.ctx.textBaseline = arguments_.car;
|
|
881
945
|
return InterpretedSymbol.of("t");
|
|
882
946
|
}
|
|
883
|
-
this
|
|
947
|
+
this.#print("Can not set text baseline.");
|
|
884
948
|
return Cons.nil;
|
|
885
949
|
} catch {
|
|
886
|
-
this
|
|
950
|
+
this.#print("Can not set text baseline.");
|
|
887
951
|
return Cons.nil;
|
|
888
952
|
}
|
|
889
|
-
this
|
|
953
|
+
this.#print("The canvas is closed and cannot be executed.");
|
|
890
954
|
return Cons.nil;
|
|
891
955
|
}
|
|
892
|
-
gTextDirection(
|
|
956
|
+
gTextDirection(arguments_) {
|
|
893
957
|
if (!this.checkSupport()) return Cons.nil;
|
|
894
958
|
if (this.isOpen) try {
|
|
895
|
-
if (
|
|
896
|
-
|
|
897
|
-
this.ctx.direction = aString;
|
|
898
|
-
this.ctx.save();
|
|
959
|
+
if (arguments_.length() === 1 && Cons.isString(arguments_.car)) {
|
|
960
|
+
this.ctx.direction = arguments_.car;
|
|
899
961
|
return InterpretedSymbol.of("t");
|
|
900
962
|
}
|
|
901
|
-
this
|
|
963
|
+
this.#print("Can not set text direction.");
|
|
902
964
|
return Cons.nil;
|
|
903
965
|
} catch {
|
|
904
|
-
this
|
|
966
|
+
this.#print("Can not set text direction.");
|
|
905
967
|
return Cons.nil;
|
|
906
968
|
}
|
|
907
|
-
this
|
|
969
|
+
this.#print("The canvas is closed and cannot be executed.");
|
|
908
970
|
return Cons.nil;
|
|
909
971
|
}
|
|
910
|
-
gTextFont(
|
|
972
|
+
gTextFont(arguments_) {
|
|
911
973
|
if (!this.checkSupport()) return Cons.nil;
|
|
912
974
|
if (this.isOpen) try {
|
|
913
|
-
if (
|
|
914
|
-
this.ctx.font =
|
|
915
|
-
this.ctx.save();
|
|
975
|
+
if (arguments_.length() === 1 && Cons.isString(arguments_.car)) {
|
|
976
|
+
this.ctx.font = arguments_.car;
|
|
916
977
|
return InterpretedSymbol.of("t");
|
|
917
978
|
}
|
|
918
|
-
this
|
|
979
|
+
this.#print("Can not set text font.");
|
|
919
980
|
return Cons.nil;
|
|
920
981
|
} catch {
|
|
921
|
-
this
|
|
982
|
+
this.#print("Can not set text font.");
|
|
922
983
|
return Cons.nil;
|
|
923
984
|
}
|
|
924
|
-
this
|
|
985
|
+
this.#print("The canvas is closed and cannot be executed.");
|
|
925
986
|
return Cons.nil;
|
|
926
987
|
}
|
|
927
|
-
gTranslate(
|
|
988
|
+
gTranslate(arguments_) {
|
|
928
989
|
if (!this.checkSupport()) return Cons.nil;
|
|
929
990
|
if (this.isOpen) try {
|
|
930
|
-
if (
|
|
931
|
-
const a0 =
|
|
932
|
-
const a1 =
|
|
991
|
+
if (arguments_.length() === 2) {
|
|
992
|
+
const a0 = arguments_.car;
|
|
993
|
+
const a1 = arguments_.cdr.car;
|
|
933
994
|
if (Cons.isNumber(a0) && Cons.isNumber(a1)) {
|
|
934
995
|
this.ctx.translate(a0, a1);
|
|
935
|
-
this.ctx.save();
|
|
936
996
|
return InterpretedSymbol.of("t");
|
|
937
997
|
}
|
|
938
998
|
}
|
|
939
|
-
this
|
|
999
|
+
this.#print("Can not translate.");
|
|
940
1000
|
return Cons.nil;
|
|
941
1001
|
} catch {
|
|
942
|
-
this
|
|
1002
|
+
this.#print("Can not translate.");
|
|
943
1003
|
return Cons.nil;
|
|
944
1004
|
}
|
|
945
|
-
this
|
|
1005
|
+
this.#print("The canvas is closed and cannot be executed.");
|
|
946
1006
|
return Cons.nil;
|
|
947
1007
|
}
|
|
948
|
-
gRect(
|
|
1008
|
+
gRect(arguments_) {
|
|
949
1009
|
if (!this.checkSupport()) return Cons.nil;
|
|
950
1010
|
if (this.isOpen) try {
|
|
951
|
-
if (
|
|
952
|
-
const a0 =
|
|
953
|
-
const cdr1 =
|
|
1011
|
+
if (arguments_.length() === 4) {
|
|
1012
|
+
const a0 = arguments_.car;
|
|
1013
|
+
const cdr1 = arguments_.cdr;
|
|
954
1014
|
const a1 = cdr1.car;
|
|
955
1015
|
const cdr2 = cdr1.cdr;
|
|
956
1016
|
const a2 = cdr2.car;
|
|
957
1017
|
const a3 = cdr2.cdr.car;
|
|
958
1018
|
if (Cons.isNumber(a0) && Cons.isNumber(a1) && Cons.isNumber(a2) && Cons.isNumber(a3)) {
|
|
959
1019
|
this.ctx.rect(a0, a1, a2, a3);
|
|
960
|
-
this.ctx.save();
|
|
961
1020
|
return InterpretedSymbol.of("t");
|
|
962
1021
|
}
|
|
963
1022
|
}
|
|
964
|
-
this
|
|
1023
|
+
this.#print("Can not draw rectangle.");
|
|
965
1024
|
return Cons.nil;
|
|
966
1025
|
} catch {
|
|
967
|
-
this
|
|
1026
|
+
this.#print("Can not draw rectangle.");
|
|
968
1027
|
return Cons.nil;
|
|
969
1028
|
}
|
|
970
|
-
this
|
|
1029
|
+
this.#print("The canvas is closed and cannot be executed.");
|
|
971
1030
|
return Cons.nil;
|
|
972
1031
|
}
|
|
973
|
-
gRotate(
|
|
1032
|
+
gRotate(arguments_) {
|
|
974
1033
|
if (!this.checkSupport()) return Cons.nil;
|
|
975
1034
|
if (this.isOpen) try {
|
|
976
|
-
if (
|
|
977
|
-
this.ctx.rotate(Math.PI / 180 *
|
|
978
|
-
this.ctx.save();
|
|
1035
|
+
if (arguments_.length() === 1 && Cons.isNumber(arguments_.car)) {
|
|
1036
|
+
this.ctx.rotate(Math.PI / 180 * arguments_.car);
|
|
979
1037
|
return InterpretedSymbol.of("t");
|
|
980
1038
|
}
|
|
981
|
-
this
|
|
1039
|
+
this.#print("Can not rotate.");
|
|
982
1040
|
return Cons.nil;
|
|
983
1041
|
} catch {
|
|
984
|
-
this
|
|
1042
|
+
this.#print("Can not rotate.");
|
|
985
1043
|
return Cons.nil;
|
|
986
1044
|
}
|
|
987
|
-
this
|
|
1045
|
+
this.#print("The canvas is closed and cannot be executed.");
|
|
1046
|
+
return Cons.nil;
|
|
1047
|
+
}
|
|
1048
|
+
/**
|
|
1049
|
+
* Pushes the current drawing state (styles, transform, clip) onto the
|
|
1050
|
+
* context's state stack. Pairs with `gRestore` to let Lisp callers manage
|
|
1051
|
+
* state explicitly. Replaces the legacy per-method `ctx.save()` calls, which
|
|
1052
|
+
* pushed state on every draw with no matching `restore()` and grew the stack
|
|
1053
|
+
* unbounded.
|
|
1054
|
+
* @return `t` on success, `Cons.nil` otherwise
|
|
1055
|
+
*/
|
|
1056
|
+
gSave() {
|
|
1057
|
+
if (!this.checkSupport()) return Cons.nil;
|
|
1058
|
+
if (this.isOpen) try {
|
|
1059
|
+
this.ctx.save();
|
|
1060
|
+
return InterpretedSymbol.of("t");
|
|
1061
|
+
} catch {
|
|
1062
|
+
this.#print("Can not save.");
|
|
1063
|
+
return Cons.nil;
|
|
1064
|
+
}
|
|
1065
|
+
this.#print("The canvas is closed and cannot be executed.");
|
|
1066
|
+
return Cons.nil;
|
|
1067
|
+
}
|
|
1068
|
+
/**
|
|
1069
|
+
* Pops the most recently saved drawing state off the context's state stack.
|
|
1070
|
+
* Pairs with `gSave`. Popping an empty stack is a no-op per the Canvas spec.
|
|
1071
|
+
* @return `t` on success, `Cons.nil` otherwise
|
|
1072
|
+
*/
|
|
1073
|
+
gRestore() {
|
|
1074
|
+
if (!this.checkSupport()) return Cons.nil;
|
|
1075
|
+
if (this.isOpen) try {
|
|
1076
|
+
this.ctx.restore();
|
|
1077
|
+
return InterpretedSymbol.of("t");
|
|
1078
|
+
} catch {
|
|
1079
|
+
this.#print("Can not restore.");
|
|
1080
|
+
return Cons.nil;
|
|
1081
|
+
}
|
|
1082
|
+
this.#print("The canvas is closed and cannot be executed.");
|
|
988
1083
|
return Cons.nil;
|
|
989
1084
|
}
|
|
990
1085
|
/**
|
|
991
1086
|
* Parses a color spec from the head of the argument Cons. Accepts
|
|
992
1087
|
* (1 string), (3 numbers — rgb), or (4 numbers — rgba); falls back to
|
|
993
1088
|
* `'black'` on anything else (legacy behavior).
|
|
994
|
-
* @param
|
|
1089
|
+
* @param arguments_ - the argument Cons to parse
|
|
995
1090
|
* @return CSS color string
|
|
996
1091
|
*/
|
|
997
|
-
selectColor(
|
|
1092
|
+
selectColor(arguments_) {
|
|
998
1093
|
let aColor = "black";
|
|
999
|
-
const
|
|
1000
|
-
const a0 =
|
|
1001
|
-
if (
|
|
1002
|
-
else if (
|
|
1003
|
-
const cdr1 =
|
|
1094
|
+
const length_ = arguments_.length();
|
|
1095
|
+
const a0 = arguments_.car;
|
|
1096
|
+
if (length_ === 1 && Cons.isString(a0)) aColor = a0;
|
|
1097
|
+
else if (length_ === 3) {
|
|
1098
|
+
const cdr1 = arguments_.cdr;
|
|
1004
1099
|
const a1 = cdr1.car;
|
|
1005
1100
|
const a2 = cdr1.cdr.car;
|
|
1006
1101
|
if (Cons.isNumber(a0) && Cons.isNumber(a1) && Cons.isNumber(a2)) aColor = `rgb(${a0}, ${a1}, ${a2})`;
|
|
1007
|
-
else this
|
|
1008
|
-
} else if (
|
|
1009
|
-
const cdr1 =
|
|
1102
|
+
else this.#print("Can not set color. set color \"black\".");
|
|
1103
|
+
} else if (length_ === 4) {
|
|
1104
|
+
const cdr1 = arguments_.cdr;
|
|
1010
1105
|
const a1 = cdr1.car;
|
|
1011
1106
|
const cdr2 = cdr1.cdr;
|
|
1012
1107
|
const a2 = cdr2.car;
|
|
1013
1108
|
const a3 = cdr2.cdr.car;
|
|
1014
1109
|
if (Cons.isNumber(a0) && Cons.isNumber(a1) && Cons.isNumber(a2) && Cons.isNumber(a3)) aColor = `rgba(${a0}, ${a1}, ${a2}, ${a3})`;
|
|
1015
|
-
else this
|
|
1016
|
-
} else this
|
|
1110
|
+
else this.#print("Can not set color. set color \"black\".");
|
|
1111
|
+
} else this.#print("Can not set color. set color \"black\".");
|
|
1017
1112
|
return aColor;
|
|
1018
1113
|
}
|
|
1019
|
-
/**
|
|
1020
|
-
* Builds the dispatch table.
|
|
1021
|
-
* @return the dispatch table
|
|
1022
|
-
*/
|
|
1023
|
-
static setup() {
|
|
1024
|
-
const aTable = /* @__PURE__ */ new Map();
|
|
1025
|
-
aTable.set(InterpretedSymbol.of("galpha"), "gAlpha");
|
|
1026
|
-
aTable.set(InterpretedSymbol.of("garc"), "gArc");
|
|
1027
|
-
aTable.set(InterpretedSymbol.of("garc-to"), "gArcTo");
|
|
1028
|
-
aTable.set(InterpretedSymbol.of("gbezcurve-to"), "gBezCurveTo");
|
|
1029
|
-
aTable.set(InterpretedSymbol.of("gclear"), "gClear");
|
|
1030
|
-
aTable.set(InterpretedSymbol.of("gclose"), "gClose");
|
|
1031
|
-
aTable.set(InterpretedSymbol.of("gcolor"), "gColor");
|
|
1032
|
-
aTable.set(InterpretedSymbol.of("gfill"), "gFill");
|
|
1033
|
-
aTable.set(InterpretedSymbol.of("gfill-color"), "gFillColor");
|
|
1034
|
-
aTable.set(InterpretedSymbol.of("gfill-rect"), "gFillRect");
|
|
1035
|
-
aTable.set(InterpretedSymbol.of("gfill-text"), "gFillText");
|
|
1036
|
-
aTable.set(InterpretedSymbol.of("gfill-tri"), "gFillTri");
|
|
1037
|
-
aTable.set(InterpretedSymbol.of("gfinish-path"), "gFinishPath");
|
|
1038
|
-
aTable.set(InterpretedSymbol.of("gimage"), "gImage");
|
|
1039
|
-
aTable.set(InterpretedSymbol.of("gmove-to"), "gMoveTo");
|
|
1040
|
-
aTable.set(InterpretedSymbol.of("gline-to"), "gLineTo");
|
|
1041
|
-
aTable.set(InterpretedSymbol.of("gline-cap"), "gLineCap");
|
|
1042
|
-
aTable.set(InterpretedSymbol.of("gline-join"), "gLineJoin");
|
|
1043
|
-
aTable.set(InterpretedSymbol.of("gline-width"), "gLineWidth");
|
|
1044
|
-
aTable.set(InterpretedSymbol.of("gopen"), "gOpen");
|
|
1045
|
-
aTable.set(InterpretedSymbol.of("gpattern"), "gPattern");
|
|
1046
|
-
aTable.set(InterpretedSymbol.of("gquadcurve-to"), "gQuadCurveTo");
|
|
1047
|
-
aTable.set(InterpretedSymbol.of("gsave-jpeg"), "gSaveJpeg");
|
|
1048
|
-
aTable.set(InterpretedSymbol.of("gsave-png"), "gSavePng");
|
|
1049
|
-
aTable.set(InterpretedSymbol.of("gscale"), "gScale");
|
|
1050
|
-
aTable.set(InterpretedSymbol.of("gshadow-blur"), "gShadowBlur");
|
|
1051
|
-
aTable.set(InterpretedSymbol.of("gshadow-color"), "gShadowColor");
|
|
1052
|
-
aTable.set(InterpretedSymbol.of("gshadow-offsetx"), "gShadowOffsetX");
|
|
1053
|
-
aTable.set(InterpretedSymbol.of("gshadow-offsety"), "gShadowOffsetY");
|
|
1054
|
-
aTable.set(InterpretedSymbol.of("gsleep"), "gSleep");
|
|
1055
|
-
aTable.set(InterpretedSymbol.of("gstart-path"), "gStartPath");
|
|
1056
|
-
aTable.set(InterpretedSymbol.of("gstroke"), "gStroke");
|
|
1057
|
-
aTable.set(InterpretedSymbol.of("gstroke-color"), "gStrokeColor");
|
|
1058
|
-
aTable.set(InterpretedSymbol.of("gstroke-rect"), "gStrokeRect");
|
|
1059
|
-
aTable.set(InterpretedSymbol.of("gstroke-text"), "gStrokeText");
|
|
1060
|
-
aTable.set(InterpretedSymbol.of("gstroke-tri"), "gStrokeTri");
|
|
1061
|
-
aTable.set(InterpretedSymbol.of("gtext-align"), "gTextAlign");
|
|
1062
|
-
aTable.set(InterpretedSymbol.of("gtext-dire"), "gTextDirection");
|
|
1063
|
-
aTable.set(InterpretedSymbol.of("gtext-font"), "gTextFont");
|
|
1064
|
-
aTable.set(InterpretedSymbol.of("gtext-line"), "gTextBaseline");
|
|
1065
|
-
aTable.set(InterpretedSymbol.of("gtranslate"), "gTranslate");
|
|
1066
|
-
aTable.set(InterpretedSymbol.of("grect"), "gRect");
|
|
1067
|
-
aTable.set(InterpretedSymbol.of("grotate"), "gRotate");
|
|
1068
|
-
return aTable;
|
|
1069
|
-
}
|
|
1070
1114
|
};
|
|
1071
1115
|
//#endregion
|
|
1072
1116
|
//#region src/index.ts
|