q5 2.14.4 → 2.15.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/src/q5-2d-text.js DELETED
@@ -1,279 +0,0 @@
1
- Q5.renderers.q2d.text = ($, q) => {
2
- $._textAlign = 'left';
3
- $._textBaseline = 'alphabetic';
4
- $._textSize = 12;
5
-
6
- let font = 'sans-serif',
7
- leadingSet = false,
8
- leading = 15,
9
- leadDiff = 3,
10
- emphasis = 'normal',
11
- fontMod = false,
12
- styleHash = 0,
13
- styleHashes = [],
14
- useCache = false,
15
- genTextImage = false,
16
- cacheSize = 0,
17
- cacheMax = 12000;
18
-
19
- let cache = ($._textCache = {});
20
-
21
- $.loadFont = (url, cb) => {
22
- q._preloadCount++;
23
- let name = url.split('/').pop().split('.')[0].replace(' ', '');
24
- let f = new FontFace(name, `url(${url})`);
25
- document.fonts.add(f);
26
- f.load().then(() => {
27
- q._preloadCount--;
28
- if (cb) cb(name);
29
- });
30
- $.textFont(name);
31
- return name;
32
- };
33
-
34
- $.textFont = (x) => {
35
- if (!x || x == font) return font;
36
- font = x;
37
- fontMod = true;
38
- styleHash = -1;
39
- };
40
-
41
- $.textSize = (x) => {
42
- if (x == undefined || x == $._textSize) return $._textSize;
43
- if ($._da) x *= $._da;
44
- $._textSize = x;
45
- fontMod = true;
46
- styleHash = -1;
47
- if (!leadingSet) {
48
- leading = x * 1.25;
49
- leadDiff = leading - x;
50
- }
51
- };
52
-
53
- $.textStyle = (x) => {
54
- if (!x || x == emphasis) return emphasis;
55
- emphasis = x;
56
- fontMod = true;
57
- styleHash = -1;
58
- };
59
-
60
- $.textLeading = (x) => {
61
- if (x == undefined) return leading || $._textSize * 1.25;
62
- leadingSet = true;
63
- if (x == leading) return leading;
64
- if ($._da) x *= $._da;
65
- leading = x;
66
- leadDiff = x - $._textSize;
67
- styleHash = -1;
68
- };
69
-
70
- $.textAlign = (horiz, vert) => {
71
- $.ctx.textAlign = $._textAlign = horiz;
72
- if (vert) {
73
- $.ctx.textBaseline = $._textBaseline = vert == $.CENTER ? 'middle' : vert;
74
- }
75
- };
76
-
77
- const updateFont = () => {
78
- $.ctx.font = `${emphasis} ${$._textSize}px ${font}`;
79
- fontMod = false;
80
- };
81
-
82
- $.textWidth = (str) => {
83
- if (fontMod) updateFont();
84
- return $.ctx.measureText(str).width;
85
- };
86
- $.textAscent = (str) => {
87
- if (fontMod) updateFont();
88
- return $.ctx.measureText(str).actualBoundingBoxAscent;
89
- };
90
- $.textDescent = (str) => {
91
- if (fontMod) updateFont();
92
- return $.ctx.measureText(str).actualBoundingBoxDescent;
93
- };
94
-
95
- $.textFill = $.fill;
96
- $.textStroke = $.stroke;
97
-
98
- let updateStyleHash = () => {
99
- let styleString = font + $._textSize + emphasis + leading;
100
-
101
- let hash = 5381;
102
- for (let i = 0; i < styleString.length; i++) {
103
- hash = (hash * 33) ^ styleString.charCodeAt(i);
104
- }
105
- styleHash = hash >>> 0;
106
- };
107
-
108
- $.textCache = (enable, maxSize) => {
109
- if (maxSize) cacheMax = maxSize;
110
- if (enable !== undefined) useCache = enable;
111
- return useCache;
112
- };
113
-
114
- $.createTextImage = (str, w, h) => {
115
- genTextImage = true;
116
- img = $.text(str, 0, 0, w, h);
117
- genTextImage = false;
118
- return img;
119
- };
120
-
121
- let lines = [];
122
-
123
- $.text = (str, x, y, w, h) => {
124
- if (str === undefined || (!$._doFill && !$._doStroke)) return;
125
- str = str.toString();
126
- if ($._da) {
127
- x *= $._da;
128
- y *= $._da;
129
- }
130
- let ctx = $.ctx;
131
- let img, tX, tY;
132
-
133
- if (fontMod) {
134
- ctx.font = `${emphasis} ${$._textSize}px ${font}`;
135
- fontMod = false;
136
- }
137
-
138
- if (useCache || genTextImage) {
139
- if (styleHash == -1) updateStyleHash();
140
-
141
- img = cache[str];
142
- if (img) img = img[styleHash];
143
-
144
- if (img) {
145
- if (img._fill == $._fill && img._stroke == $._stroke && img._strokeWeight == $._strokeWeight) {
146
- if (genTextImage) return img;
147
- return $.textImage(img, x, y);
148
- } else img.clear();
149
- }
150
- }
151
-
152
- if (str.indexOf('\n') == -1) lines[0] = str;
153
- else lines = str.split('\n');
154
-
155
- if (str.length > w) {
156
- let wrapped = [];
157
- for (let line of lines) {
158
- let i = 0;
159
-
160
- while (i < line.length) {
161
- let max = i + w;
162
- if (max >= line.length) {
163
- wrapped.push(line.slice(i));
164
- break;
165
- }
166
- let end = line.lastIndexOf(' ', max);
167
- if (end === -1 || end < i) end = max;
168
- wrapped.push(line.slice(i, end));
169
- i = end + 1;
170
- }
171
- }
172
- lines = wrapped;
173
- }
174
-
175
- if (!useCache && !genTextImage) {
176
- tX = x;
177
- tY = y;
178
- } else {
179
- tX = 0;
180
- tY = leading * lines.length;
181
-
182
- if (!img) {
183
- let measure = ctx.measureText(' ');
184
- let ascent = measure.fontBoundingBoxAscent;
185
- let descent = measure.fontBoundingBoxDescent;
186
-
187
- img = $.createImage.call($, Math.ceil(ctx.measureText(str).width), Math.ceil(tY + descent), {
188
- pixelDensity: $._pixelDensity
189
- });
190
-
191
- img._ascent = ascent;
192
- img._descent = descent;
193
- img._top = descent + leadDiff;
194
- img._middle = img._top + ascent * 0.5;
195
- img._bottom = img._top + ascent;
196
- img._leading = leading;
197
- }
198
-
199
- img._fill = $._fill;
200
- img._stroke = $._stroke;
201
- img._strokeWeight = $._strokeWeight;
202
- img.modified = true;
203
-
204
- ctx = img.ctx;
205
-
206
- ctx.font = $.ctx.font;
207
- ctx.fillStyle = $._fill;
208
- ctx.strokeStyle = $._stroke;
209
- ctx.lineWidth = $.ctx.lineWidth;
210
- }
211
-
212
- let ogFill;
213
- if (!$._fillSet) {
214
- ogFill = ctx.fillStyle;
215
- ctx.fillStyle = 'black';
216
- }
217
-
218
- let lineAmount = 0;
219
- for (let line of lines) {
220
- if ($._doStroke && $._strokeSet) ctx.strokeText(line, tX, tY);
221
- if ($._doFill) ctx.fillText(line, tX, tY);
222
- tY += leading;
223
- lineAmount++;
224
- if (lineAmount >= h) break;
225
- }
226
- lines = [];
227
-
228
- if (!$._fillSet) ctx.fillStyle = ogFill;
229
-
230
- if (useCache || genTextImage) {
231
- styleHashes.push(styleHash);
232
- (cache[str] ??= {})[styleHash] = img;
233
-
234
- cacheSize++;
235
- if (cacheSize > cacheMax) {
236
- let half = Math.ceil(cacheSize / 2);
237
- let hashes = styleHashes.splice(0, half);
238
- for (let s in cache) {
239
- s = cache[s];
240
- for (let h of hashes) delete s[h];
241
- }
242
- cacheSize -= half;
243
- }
244
-
245
- if (genTextImage) return img;
246
- $.textImage(img, x, y);
247
- }
248
- };
249
-
250
- $.textImage = (img, x, y) => {
251
- if (typeof img == 'string') img = $.createTextImage(img);
252
-
253
- let og = $._imageMode;
254
- $._imageMode = 'corner';
255
-
256
- let ta = $._textAlign;
257
- if (ta == 'center') x -= img.canvas.hw;
258
- else if (ta == 'right') x -= img.width;
259
-
260
- let bl = $._textBaseline;
261
- if (bl == 'alphabetic') y -= img._leading;
262
- else if (bl == 'middle') y -= img._middle;
263
- else if (bl == 'bottom') y -= img._bottom;
264
- else if (bl == 'top') y -= img._top;
265
-
266
- $.image(img, x, y);
267
- $._imageMode = og;
268
- };
269
-
270
- $.nf = (n, l, r) => {
271
- let neg = n < 0;
272
- n = Math.abs(n);
273
- let parts = n.toFixed(r).split('.');
274
- parts[0] = parts[0].padStart(l, '0');
275
- let s = parts.join('.');
276
- if (neg) s = '-' + s;
277
- return s;
278
- };
279
- };
package/src/q5-ai.js DELETED
@@ -1,65 +0,0 @@
1
- Q5.modules.ai = ($) => {
2
- $.askAI = (question = '') => {
3
- Q5.disableFriendlyErrors = false;
4
- throw Error('Ask AI ✨ ' + question);
5
- };
6
-
7
- $._askAI = async (e) => {
8
- let askAI = e.message?.includes('Ask AI ✨');
9
- let stackLines = e.stack?.split('\n');
10
- if (!e.stack || stackLines.length <= 1) return;
11
-
12
- let idx = 1;
13
- let sep = '(';
14
- if (navigator.userAgent.indexOf('Chrome') == -1) {
15
- idx = 0;
16
- sep = '@';
17
- }
18
- while (stackLines[idx].indexOf('q5') >= 0) idx++;
19
-
20
- let errFile = stackLines[idx].split(sep).at(-1);
21
- if (errFile.startsWith('blob:')) errFile = errFile.slice(5);
22
- let parts = errFile.split(':');
23
- let lineNum = parseInt(parts.at(-2));
24
- if (askAI) lineNum++;
25
- parts[3] = parts[3].split(')')[0];
26
- let fileUrl = parts.slice(0, 2).join(':');
27
- let fileBase = fileUrl.split('/').at(-1);
28
-
29
- try {
30
- let res = await (await fetch(fileUrl)).text();
31
- let lines = res.split('\n');
32
- let errLine = lines[lineNum - 1].trim();
33
-
34
- let context = '';
35
- let i = 1;
36
- while (context.length < 1600) {
37
- if (lineNum - i >= 0) {
38
- context = lines[lineNum - i].trim() + '\n' + context;
39
- }
40
- if (lineNum + i < lines.length) {
41
- context += lines[lineNum + i].trim() + '\n';
42
- } else break;
43
- i++;
44
- }
45
-
46
- let question =
47
- askAI && e.message.length > 10 ? e.message.slice(10) : 'Whats+wrong+with+this+line%3F+short+answer';
48
-
49
- let url =
50
- 'https://chatgpt.com/?q=q5.js+' +
51
- question +
52
- (askAI ? '' : '%0A%0A' + encodeURIComponent(e.name + ': ' + e.message)) +
53
- '%0A%0ALine%3A+' +
54
- encodeURIComponent(errLine) +
55
- '%0A%0AExcerpt+for+context%3A%0A%0A' +
56
- encodeURIComponent(context);
57
-
58
- console.warn('Error in ' + fileBase + ' on line ' + lineNum + ':\n\n' + errLine);
59
-
60
- console.warn('Ask AI ✨ ' + url);
61
-
62
- if (askAI) return window.open(url, '_blank');
63
- } catch (err) {}
64
- };
65
- };
package/src/q5-canvas.js DELETED
@@ -1,367 +0,0 @@
1
- Q5.modules.canvas = ($, q) => {
2
- $._OffscreenCanvas =
3
- window.OffscreenCanvas ||
4
- function () {
5
- return document.createElement('canvas');
6
- };
7
-
8
- if (Q5._server) {
9
- if (Q5._createServerCanvas) {
10
- q.canvas = Q5._createServerCanvas(100, 100);
11
- }
12
- } else if ($._scope == 'image' || $._scope == 'graphics') {
13
- q.canvas = new $._OffscreenCanvas(100, 100);
14
- }
15
-
16
- if (!$.canvas) {
17
- if (typeof document == 'object') {
18
- q.canvas = document.createElement('canvas');
19
- $.canvas.id = 'q5Canvas' + Q5._instanceCount;
20
- $.canvas.classList.add('q5Canvas');
21
- } else $.noCanvas();
22
- }
23
-
24
- let c = $.canvas;
25
- $.width = 200;
26
- $.height = 200;
27
- $._pixelDensity = 1;
28
-
29
- $.displayDensity = () => window.devicePixelRatio || 1;
30
-
31
- if (c) {
32
- c.width = 200;
33
- c.height = 200;
34
- if ($._scope != 'image') {
35
- c.renderer = $._renderer;
36
- c[$._renderer] = true;
37
-
38
- $._pixelDensity = Math.ceil($.displayDensity());
39
- }
40
- }
41
-
42
- $._adjustDisplay = () => {
43
- if (c.style) {
44
- c.style.width = c.w + 'px';
45
- c.style.height = c.h + 'px';
46
- }
47
- };
48
-
49
- $.createCanvas = function (w, h, options) {
50
- if (typeof w == 'object') {
51
- options = w;
52
- w = null;
53
- }
54
- options ??= arguments[3];
55
-
56
- let opt = Object.assign({}, Q5.canvasOptions);
57
- if (typeof options == 'object') Object.assign(opt, options);
58
-
59
- if ($._scope != 'image') {
60
- if ($._scope == 'graphics') $._pixelDensity = this._pixelDensity;
61
- else if (window.IntersectionObserver) {
62
- let wasObserved = false;
63
- new IntersectionObserver((e) => {
64
- c.visible = e[0].isIntersecting;
65
- if (!wasObserved) {
66
- $._wasLooping = $._loop;
67
- wasObserved = true;
68
- }
69
- if (c.visible) {
70
- if ($._wasLooping && !$._loop) $.loop();
71
- } else {
72
- $._wasLooping = $._loop;
73
- $.noLoop();
74
- }
75
- }).observe(c);
76
- }
77
- }
78
-
79
- $._setCanvasSize(w, h);
80
-
81
- Object.assign(c, opt);
82
- let rend = $._createCanvas(c.w, c.h, opt);
83
-
84
- if ($._hooks) {
85
- for (let m of $._hooks.postCanvas) m();
86
- }
87
- if ($._beginRender) $._beginRender();
88
-
89
- return rend;
90
- };
91
-
92
- $.createGraphics = function (w, h, opt) {
93
- let g = new Q5('graphics');
94
- opt ??= {};
95
- opt.alpha ??= true;
96
- opt.colorSpace ??= $.canvas.colorSpace;
97
- g.createCanvas.call($, w, h, opt);
98
- g.defaultWidth = w;
99
- g.defaultHeight = h;
100
- return g;
101
- };
102
-
103
- async function saveFile(data, name, ext) {
104
- name = name || 'untitled';
105
- ext = ext || 'png';
106
- if (ext == 'jpg' || ext == 'png' || ext == 'webp') {
107
- if (data instanceof OffscreenCanvas) {
108
- const blob = await data.convertToBlob({ type: 'image/' + ext });
109
- data = await new Promise((resolve) => {
110
- const reader = new FileReader();
111
- reader.onloadend = () => resolve(reader.result);
112
- reader.readAsDataURL(blob);
113
- });
114
- } else {
115
- data = data.toDataURL('image/' + ext);
116
- }
117
- } else {
118
- let type = 'text/plain';
119
- if (ext == 'json') {
120
- if (typeof data != 'string') data = JSON.stringify(data);
121
- type = 'text/json';
122
- }
123
- data = new Blob([data], { type });
124
- data = URL.createObjectURL(data);
125
- }
126
- let a = document.createElement('a');
127
- a.href = data;
128
- a.download = name + '.' + ext;
129
- a.click();
130
- URL.revokeObjectURL(a.href);
131
- }
132
-
133
- $.save = (a, b, c) => {
134
- if (!a || (typeof a == 'string' && (!b || (!c && b.length < 5)))) {
135
- c = b;
136
- b = a;
137
- a = $.canvas;
138
- }
139
- if (c) return saveFile(a, b, c);
140
- if (b) {
141
- b = b.split('.');
142
- saveFile(a, b[0], b.at(-1));
143
- } else saveFile(a);
144
- };
145
-
146
- $._setCanvasSize = (w, h) => {
147
- w ??= window.innerWidth;
148
- h ??= window.innerHeight;
149
- $.defaultWidth = c.w = w = Math.ceil(w);
150
- $.defaultHeight = c.h = h = Math.ceil(h);
151
- c.hw = w / 2;
152
- c.hh = h / 2;
153
-
154
- // changes the actual size of the canvas
155
- c.width = Math.ceil(w * $._pixelDensity);
156
- c.height = Math.ceil(h * $._pixelDensity);
157
-
158
- if (!$._da) {
159
- q.width = w;
160
- q.height = h;
161
- } else $.flexibleCanvas($._dau);
162
-
163
- if ($.displayMode && !c.displayMode) $.displayMode();
164
- else $._adjustDisplay();
165
- };
166
-
167
- $._setImageSize = (w, h) => {
168
- q.width = c.w = w;
169
- q.height = c.h = h;
170
- c.hw = w / 2;
171
- c.hh = h / 2;
172
-
173
- // changes the actual size of the canvas
174
- c.width = Math.ceil(w * $._pixelDensity);
175
- c.height = Math.ceil(h * $._pixelDensity);
176
- };
177
-
178
- $.defaultImageScale = (scale) => {
179
- if (!scale) return $._defaultImageScale;
180
- return ($._defaultImageScale = scale);
181
- };
182
- $.defaultImageScale(0.5);
183
-
184
- if ($._scope == 'image') return;
185
-
186
- if (c && $._scope != 'graphics') {
187
- c.parent = (el) => {
188
- if (c.parentElement) c.parentElement.removeChild(c);
189
-
190
- if (typeof el == 'string') el = document.getElementById(el);
191
- el.append(c);
192
-
193
- function parentResized() {
194
- if ($.frameCount > 1) {
195
- $._didResize = true;
196
- $._adjustDisplay();
197
- }
198
- }
199
- if (typeof ResizeObserver == 'function') {
200
- if ($._ro) $._ro.disconnect();
201
- $._ro = new ResizeObserver(parentResized);
202
- $._ro.observe(el);
203
- } else if (!$.frameCount) {
204
- window.addEventListener('resize', parentResized);
205
- }
206
- };
207
-
208
- function addCanvas() {
209
- let el = $._parent;
210
- el ??= document.getElementsByTagName('main')[0];
211
- if (!el) {
212
- el = document.createElement('main');
213
- document.body.append(el);
214
- }
215
- c.parent(el);
216
- }
217
- if (document.body) addCanvas();
218
- else document.addEventListener('DOMContentLoaded', addCanvas);
219
- }
220
-
221
- $.resizeCanvas = (w, h) => {
222
- if (!$.ctx) return $.createCanvas(w, h);
223
- if (w == c.w && h == c.h) return;
224
-
225
- $._resizeCanvas(w, h);
226
- };
227
-
228
- if (c && !Q5._createServerCanvas) {
229
- c.resize = $.resizeCanvas;
230
- c.save = $.saveCanvas = $.save;
231
- }
232
-
233
- $.pixelDensity = (v) => {
234
- if (!v || v == $._pixelDensity) return $._pixelDensity;
235
- $._pixelDensity = v;
236
- $._setCanvasSize(c.w, c.h);
237
- return v;
238
- };
239
-
240
- $.flexibleCanvas = (unit = 400) => {
241
- if (unit) {
242
- $._da = c.width / (unit * $._pixelDensity);
243
- q.width = $._dau = unit;
244
- q.height = (c.h / c.w) * unit;
245
- } else $._da = 0;
246
- };
247
-
248
- $._styleNames = [
249
- '_fill',
250
- '_stroke',
251
- '_strokeWeight',
252
- '_doStroke',
253
- '_doFill',
254
- '_strokeSet',
255
- '_fillSet',
256
- '_shadow',
257
- '_doShadow',
258
- '_shadowOffsetX',
259
- '_shadowOffsetY',
260
- '_shadowBlur',
261
- '_tint',
262
- '_imageMode',
263
- '_rectMode',
264
- '_ellipseMode',
265
- '_textSize',
266
- '_textAlign',
267
- '_textBaseline'
268
- ];
269
- $._styles = [];
270
-
271
- $.pushStyles = () => {
272
- let styles = {};
273
- for (let s of $._styleNames) styles[s] = $[s];
274
- $._styles.push(styles);
275
- };
276
- $.popStyles = () => {
277
- let styles = $._styles.pop();
278
- for (let s of $._styleNames) $[s] = styles[s];
279
- };
280
-
281
- if (window && $._scope != 'graphics') {
282
- window.addEventListener('resize', () => {
283
- $._didResize = true;
284
- q.windowWidth = window.innerWidth;
285
- q.windowHeight = window.innerHeight;
286
- q.deviceOrientation = window.screen?.orientation?.type;
287
- });
288
- }
289
- };
290
-
291
- Q5.CENTER = 'center';
292
- Q5.LEFT = 'left';
293
- Q5.RIGHT = 'right';
294
- Q5.TOP = 'top';
295
- Q5.BOTTOM = 'bottom';
296
-
297
- Q5.BASELINE = 'alphabetic';
298
- Q5.MIDDLE = 'middle';
299
-
300
- Q5.NORMAL = 'normal';
301
- Q5.ITALIC = 'italic';
302
- Q5.BOLD = 'bold';
303
- Q5.BOLDITALIC = 'italic bold';
304
-
305
- Q5.ROUND = 'round';
306
- Q5.SQUARE = 'butt';
307
- Q5.PROJECT = 'square';
308
- Q5.MITER = 'miter';
309
- Q5.BEVEL = 'bevel';
310
-
311
- Q5.CHORD_OPEN = 0;
312
- Q5.PIE_OPEN = 1;
313
- Q5.PIE = 2;
314
- Q5.CHORD = 3;
315
-
316
- Q5.RADIUS = 'radius';
317
- Q5.CORNER = 'corner';
318
- Q5.CORNERS = 'corners';
319
-
320
- Q5.OPEN = 0;
321
- Q5.CLOSE = 1;
322
-
323
- Q5.LANDSCAPE = 'landscape';
324
- Q5.PORTRAIT = 'portrait';
325
-
326
- Q5.BLEND = 'source-over';
327
- Q5.REMOVE = 'destination-out';
328
- Q5.ADD = 'lighter';
329
- Q5.DARKEST = 'darken';
330
- Q5.LIGHTEST = 'lighten';
331
- Q5.DIFFERENCE = 'difference';
332
- Q5.SUBTRACT = 'subtract';
333
- Q5.EXCLUSION = 'exclusion';
334
- Q5.MULTIPLY = 'multiply';
335
- Q5.SCREEN = 'screen';
336
- Q5.REPLACE = 'copy';
337
- Q5.OVERLAY = 'overlay';
338
- Q5.HARD_LIGHT = 'hard-light';
339
- Q5.SOFT_LIGHT = 'soft-light';
340
- Q5.DODGE = 'color-dodge';
341
- Q5.BURN = 'color-burn';
342
-
343
- Q5.THRESHOLD = 1;
344
- Q5.GRAY = 2;
345
- Q5.OPAQUE = 3;
346
- Q5.INVERT = 4;
347
- Q5.POSTERIZE = 5;
348
- Q5.DILATE = 6;
349
- Q5.ERODE = 7;
350
- Q5.BLUR = 8;
351
- Q5.SEPIA = 9;
352
- Q5.BRIGHTNESS = 10;
353
- Q5.SATURATION = 11;
354
- Q5.CONTRAST = 12;
355
- Q5.HUE_ROTATE = 13;
356
-
357
- Q5.P2D = '2d';
358
- Q5.WEBGL = 'webgl';
359
-
360
- Q5.canvasOptions = {
361
- alpha: false,
362
- colorSpace: 'display-p3'
363
- };
364
-
365
- if (!window.matchMedia || !matchMedia('(dynamic-range: high) and (color-gamut: p3)').matches) {
366
- Q5.canvasOptions.colorSpace = 'srgb';
367
- } else Q5.supportsHDR = true;