litecanvas 0.207.2 → 0.209.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/dist/dist.dev.js CHANGED
@@ -115,7 +115,7 @@
115
115
  var assert = (condition, message = "Assertion failed") => {
116
116
  if (!condition) throw new Error("[Litecanvas] " + message);
117
117
  };
118
- var version = "0.207.2";
118
+ var version = "0.209.0";
119
119
  function litecanvas(settings = {}) {
120
120
  const root = window,
121
121
  math = Math,
@@ -146,7 +146,7 @@
146
146
  };
147
147
  DEV: assert(
148
148
  null == settings || "object" === typeof settings,
149
- "litecanvas() 1st parameter must be a object or null",
149
+ "litecanvas() 1st parameter must be a object",
150
150
  );
151
151
  settings = Object.assign(defaults, settings);
152
152
  let _loop = settings.loop,
@@ -192,11 +192,19 @@
192
192
  DEV: assert(isNumber(rads), "rad2deg() 1st parameter must be a number");
193
193
  return (180 / math.PI) * rads;
194
194
  },
195
+ mod(a, b) {
196
+ DEV: assert(isNumber(a), "mod() 1st parameter must be a number");
197
+ DEV: assert(
198
+ isNumber(b) && b >= 0,
199
+ "mod() 2nd parameter must be a non-negative number",
200
+ );
201
+ return ((a % b) + b) % b || 0;
202
+ },
195
203
  round: (n, precision = 0) => {
196
204
  DEV: assert(isNumber(n), "round() 1st parameter must be a number");
197
205
  DEV: assert(
198
206
  isNumber(precision) && precision >= 0,
199
- "round() 2nd parameter must be a positive number or zero",
207
+ "round() 2nd parameter must be a non-negative number",
200
208
  );
201
209
  if (!precision) {
202
210
  return math.round(n);
@@ -282,14 +290,14 @@
282
290
  rseed(value) {
283
291
  DEV: assert(
284
292
  isNumber(value) && value >= 0,
285
- "rseed() 1st parameter must be a positive integer or zero",
293
+ "rseed() 1st parameter must be a non-negative integer",
286
294
  );
287
295
  _rngSeed = ~~value;
288
296
  },
289
297
  cls(color) {
290
298
  DEV: assert(
291
299
  null == color || (isNumber(color) && color >= 0),
292
- "cls() 1st parameter must be a positive number or zero or undefined",
300
+ "cls() 1st parameter must be a non-negative number",
293
301
  );
294
302
  if (null == color) {
295
303
  _ctx.clearRect(0, 0, instance.W, instance.H);
@@ -306,11 +314,11 @@
306
314
  );
307
315
  DEV: assert(
308
316
  isNumber(height) && height >= 0,
309
- "rect() 4th parameter must be a positive number or zero",
317
+ "rect() 4th parameter must be a non-negative number",
310
318
  );
311
319
  DEV: assert(
312
320
  null == color || (isNumber(color) && color >= 0),
313
- "rect() 5th parameter must be a positive number or zero",
321
+ "rect() 5th parameter must be a non-negative number",
314
322
  );
315
323
  DEV: assert(
316
324
  null == radii ||
@@ -333,15 +341,15 @@
333
341
  DEV: assert(isNumber(y), "rectfill() 2nd parameter must be a number");
334
342
  DEV: assert(
335
343
  isNumber(width) && width >= 0,
336
- "rectfill() 3rd parameter must be a positive number or zero",
344
+ "rectfill() 3rd parameter must be a non-negative number",
337
345
  );
338
346
  DEV: assert(
339
347
  isNumber(height) && height >= 0,
340
- "rectfill() 4th parameter must be a positive number or zero",
348
+ "rectfill() 4th parameter must be a non-negative number",
341
349
  );
342
350
  DEV: assert(
343
351
  null == color || (isNumber(color) && color >= 0),
344
- "rectfill() 5th parameter must be a positive number or zero",
352
+ "rectfill() 5th parameter must be a non-negative number",
345
353
  );
346
354
  DEV: assert(
347
355
  null == radii ||
@@ -358,15 +366,15 @@
358
366
  DEV: assert(isNumber(y), "oval() 2nd parameter must be a number");
359
367
  DEV: assert(
360
368
  isNumber(radiusX) && radiusX >= 0,
361
- "oval() 3rd parameter must be a positive number or zero",
369
+ "oval() 3rd parameter must be a non-negative number",
362
370
  );
363
371
  DEV: assert(
364
372
  isNumber(radiusY) && radiusY >= 0,
365
- "oval() 4th parameter must be a positive number or zero",
373
+ "oval() 4th parameter must be a non-negative number",
366
374
  );
367
375
  DEV: assert(
368
376
  null == color || (isNumber(color) && color >= 0),
369
- "oval() 5th parameter must be a positive number or zero",
377
+ "oval() 5th parameter must be a non-negative number",
370
378
  );
371
379
  beginPath(_ctx);
372
380
  _ctx.ellipse(~~x, ~~y, ~~radiusX, ~~radiusY, 0, 0, TWO_PI);
@@ -377,15 +385,15 @@
377
385
  DEV: assert(isNumber(y), "ovalfill() 2nd parameter must be a number");
378
386
  DEV: assert(
379
387
  isNumber(radiusX) && radiusX >= 0,
380
- "ovalfill() 3rd parameter must be a positive number or zero",
388
+ "ovalfill() 3rd parameter must be a non-negative number",
381
389
  );
382
390
  DEV: assert(
383
391
  isNumber(radiusY) && radiusY >= 0,
384
- "ovalfill() 4th parameter must be a positive number or zero",
392
+ "ovalfill() 4th parameter must be a non-negative number",
385
393
  );
386
394
  DEV: assert(
387
395
  null == color || (isNumber(color) && color >= 0),
388
- "ovalfill() 5th parameter must be a positive number or zero",
396
+ "ovalfill() 5th parameter must be a non-negative number",
389
397
  );
390
398
  beginPath(_ctx);
391
399
  _ctx.ellipse(~~x, ~~y, ~~radiusX, ~~radiusY, 0, 0, TWO_PI);
@@ -396,11 +404,11 @@
396
404
  DEV: assert(isNumber(y), "circ() 2nd parameter must be a number");
397
405
  DEV: assert(
398
406
  isNumber(radius) && radius >= 0,
399
- "circ() 3rd parameter must be a positive number or zero",
407
+ "circ() 3rd parameter must be a non-negative number",
400
408
  );
401
409
  DEV: assert(
402
410
  null == color || (isNumber(color) && color >= 0),
403
- "circ() 4th parameter must be a positive number or zero",
411
+ "circ() 4th parameter must be a non-negative number",
404
412
  );
405
413
  instance.oval(x, y, radius, radius, color);
406
414
  },
@@ -409,11 +417,11 @@
409
417
  DEV: assert(isNumber(y), "circfill() 2nd parameter must be a number");
410
418
  DEV: assert(
411
419
  isNumber(radius) && radius >= 0,
412
- "circfill() 3rd parameter must be a positive number or zero",
420
+ "circfill() 3rd parameter must be a non-negative number",
413
421
  );
414
422
  DEV: assert(
415
423
  null == color || (isNumber(color) && color >= 0),
416
- "circfill() 4th parameter must be a positive number or zero",
424
+ "circfill() 4th parameter must be a non-negative number",
417
425
  );
418
426
  instance.ovalfill(x, y, radius, radius, color);
419
427
  },
@@ -428,10 +436,10 @@
428
436
  );
429
437
  beginPath(_ctx);
430
438
  for (let i = 0; i < points.length; i += 2) {
431
- if (0 === i) {
432
- _ctx.moveTo(~~points[i], ~~points[i + 1]);
433
- } else {
439
+ if (i) {
434
440
  _ctx.lineTo(~~points[i], ~~points[i + 1]);
441
+ } else {
442
+ _ctx.moveTo(~~points[i], ~~points[i + 1]);
435
443
  }
436
444
  }
437
445
  _ctx.lineTo(~~points[0], ~~points[1]);
@@ -441,19 +449,19 @@
441
449
  DEV: assert(isNumber(y1), "line() 2nd parameter must be a number");
442
450
  DEV: assert(
443
451
  isNumber(x2),
444
- "line() 3rd parameter must be a positive number or zero",
452
+ "line() 3rd parameter must be a non-negative number",
445
453
  );
446
454
  DEV: assert(
447
455
  isNumber(y2),
448
- "line() 4th parameter must be a positive number or zero",
456
+ "line() 4th parameter must be a non-negative number",
449
457
  );
450
458
  DEV: assert(
451
459
  null == color || (isNumber(color) && color >= 0),
452
- "line() 5th parameter must be a positive number or zero",
460
+ "line() 5th parameter must be a non-negative number",
453
461
  );
454
462
  beginPath(_ctx);
455
- let xfix = _outline_fix !== 0 && ~~x1 === ~~x2 ? 0.5 : 0;
456
- let yfix = _outline_fix !== 0 && ~~y1 === ~~y2 ? 0.5 : 0;
463
+ let xfix = _outline_fix && ~~x1 === ~~x2 ? 0.5 : 0;
464
+ let yfix = _outline_fix && ~~y1 === ~~y2 ? 0.5 : 0;
457
465
  _ctx.moveTo(~~x1 + xfix, ~~y1 + yfix);
458
466
  _ctx.lineTo(~~x2 + xfix, ~~y2 + yfix);
459
467
  instance.stroke(color);
@@ -461,10 +469,10 @@
461
469
  linewidth(value) {
462
470
  DEV: assert(
463
471
  isNumber(value) && value >= 0,
464
- "linewidth() 1st parameter must be a positive number or zero",
472
+ "linewidth() 1st parameter must be a non-negative integer",
465
473
  );
466
474
  _ctx.lineWidth = ~~value;
467
- _outline_fix = 0 === ~~value % 2 ? 0 : 0.5;
475
+ _outline_fix = ~~value % 2 ? 0.5 : 0;
468
476
  },
469
477
  linedash(segments, offset = 0) {
470
478
  DEV: assert(
@@ -483,7 +491,7 @@
483
491
  DEV: assert(isNumber(y), "text() 2nd parameter must be a number");
484
492
  DEV: assert(
485
493
  null == color || (isNumber(color) && color >= 0),
486
- "text() 4th parameter must be a positive number or zero",
494
+ "text() 4th parameter must be a non-negative number",
487
495
  );
488
496
  DEV: assert(
489
497
  "string" === typeof fontStyle,
@@ -554,18 +562,19 @@
554
562
  "string" === typeof pixels,
555
563
  "spr() 3rd parameter must be a string",
556
564
  );
557
- const rows = pixels.trim().split("\n");
558
- for (let row = 0; row < rows.length; row++) {
559
- const chars = rows[row].trim();
560
- for (let col = 0; col < chars.length; col++) {
561
- const char = chars[col];
562
- if (char !== "." && char !== " ") {
565
+ const rows = pixels
566
+ .replace(/[^\w.\n]/g, "")
567
+ .split("\n")
568
+ .filter((s) => s);
569
+ for (let i = 0; i < rows.length; i++) {
570
+ for (let j = 0; j < rows[i].length; j++) {
571
+ if (rows[i][j] !== ".") {
563
572
  instance.rectfill(
564
- x + col,
565
- y + row,
573
+ x + j,
574
+ y + i,
566
575
  1,
567
576
  1,
568
- parseInt(char, 36) || 0,
577
+ parseInt(rows[i][j], 36) || 0,
569
578
  );
570
579
  }
571
580
  }
@@ -617,8 +626,31 @@
617
626
  }
618
627
  return _ctx;
619
628
  },
620
- push() {
629
+ push(
630
+ translateX = 0,
631
+ translateY = translateX,
632
+ rotation = 0,
633
+ scaleX = 1,
634
+ scaleY = scaleX,
635
+ ) {
636
+ DEV: assert(
637
+ isNumber(translateX),
638
+ "push() 1st parameter must be a number",
639
+ );
640
+ DEV: assert(
641
+ isNumber(translateY),
642
+ "push() 2nd parameter must be a number",
643
+ );
644
+ DEV: assert(
645
+ isNumber(rotation),
646
+ "push() 3rd parameter must be a number",
647
+ );
648
+ DEV: assert(isNumber(scaleX), "push() 4th parameter must be a number");
649
+ DEV: assert(isNumber(scaleY), "push() 5th parameter must be a number");
621
650
  _ctx.save();
651
+ instance.translate(translateX, translateY);
652
+ instance.rotate(rotation);
653
+ instance.scale(scaleX, scaleY);
622
654
  },
623
655
  pop() {
624
656
  _ctx.restore();
@@ -647,7 +679,7 @@
647
679
  fill(color) {
648
680
  DEV: assert(
649
681
  null == color || (isNumber(color) && color >= 0),
650
- "fill() 1st parameter must be a positive number or zero",
682
+ "fill() 1st parameter must be a non-negative number",
651
683
  );
652
684
  _ctx.fillStyle = getColor(color);
653
685
  _ctx.fill();
@@ -655,7 +687,7 @@
655
687
  stroke(color) {
656
688
  DEV: assert(
657
689
  null == color || (isNumber(color) && color >= 0),
658
- "stroke() 1st parameter must be a positive number or zero",
690
+ "stroke() 1st parameter must be a non-negative number",
659
691
  );
660
692
  _ctx.strokeStyle = getColor(color);
661
693
  _ctx.stroke();
@@ -700,7 +732,7 @@
700
732
  volume(value) {
701
733
  DEV: assert(
702
734
  isNumber(value) && value >= 0,
703
- "volume() 1st parameter must be a positive number or zero",
735
+ "volume() 1st parameter must be a non-negative number",
704
736
  );
705
737
  root.zzfxV = value;
706
738
  },
@@ -770,7 +802,7 @@
770
802
  );
771
803
  DEV: assert(
772
804
  isNumber(textColor) && textColor >= 0,
773
- "pal() 2nd parameter must be a positive number or zero",
805
+ "pal() 2nd parameter must be a non-negative number",
774
806
  );
775
807
  _colorPalette = colors || defaultPalette;
776
808
  _colorPaletteState = [];
@@ -786,7 +818,7 @@
786
818
  isNumber(a) ? isNumber(b) && b >= 0 : null == b,
787
819
  "palc() 2nd parameter must be a positive number",
788
820
  );
789
- if (a == null) {
821
+ if (null == a) {
790
822
  _colorPaletteState = [];
791
823
  } else {
792
824
  _colorPaletteState[a] = b;
@@ -810,7 +842,7 @@
810
842
  timescale(value) {
811
843
  DEV: assert(
812
844
  isNumber(value) && value >= 0,
813
- "timescale() 1st parameter must be a positive number or zero",
845
+ "timescale() 1st parameter must be a non-negative number",
814
846
  );
815
847
  _timeScale = value;
816
848
  },
@@ -921,7 +953,7 @@
921
953
  _checkTapped = (tap) => tap && perf.now() - tap.t <= 300;
922
954
  let _pressingMouse = false;
923
955
  on(_canvas, "mousedown", (ev) => {
924
- if (ev.button === 0) {
956
+ if (!ev.button) {
925
957
  preventDefault(ev);
926
958
  const [x, y] = _getXY(ev);
927
959
  instance.emit("tap", x, y, 0);
@@ -930,7 +962,7 @@
930
962
  }
931
963
  });
932
964
  on(_canvas, "mouseup", (ev) => {
933
- if (ev.button === 0) {
965
+ if (!ev.button) {
934
966
  preventDefault(ev);
935
967
  const tap = _taps.get(0);
936
968
  const [x, y] = _getXY(ev);
package/dist/dist.js CHANGED
@@ -179,6 +179,9 @@
179
179
  rad2deg: (rads) => {
180
180
  return (180 / math.PI) * rads;
181
181
  },
182
+ mod(a, b) {
183
+ return ((a % b) + b) % b || 0;
184
+ },
182
185
  round: (n, precision = 0) => {
183
186
  if (!precision) {
184
187
  return math.round(n);
@@ -260,25 +263,25 @@
260
263
  shape(points) {
261
264
  beginPath(_ctx);
262
265
  for (let i = 0; i < points.length; i += 2) {
263
- if (0 === i) {
264
- _ctx.moveTo(~~points[i], ~~points[i + 1]);
265
- } else {
266
+ if (i) {
266
267
  _ctx.lineTo(~~points[i], ~~points[i + 1]);
268
+ } else {
269
+ _ctx.moveTo(~~points[i], ~~points[i + 1]);
267
270
  }
268
271
  }
269
272
  _ctx.lineTo(~~points[0], ~~points[1]);
270
273
  },
271
274
  line(x1, y1, x2, y2, color) {
272
275
  beginPath(_ctx);
273
- let xfix = _outline_fix !== 0 && ~~x1 === ~~x2 ? 0.5 : 0;
274
- let yfix = _outline_fix !== 0 && ~~y1 === ~~y2 ? 0.5 : 0;
276
+ let xfix = _outline_fix && ~~x1 === ~~x2 ? 0.5 : 0;
277
+ let yfix = _outline_fix && ~~y1 === ~~y2 ? 0.5 : 0;
275
278
  _ctx.moveTo(~~x1 + xfix, ~~y1 + yfix);
276
279
  _ctx.lineTo(~~x2 + xfix, ~~y2 + yfix);
277
280
  instance.stroke(color);
278
281
  },
279
282
  linewidth(value) {
280
283
  _ctx.lineWidth = ~~value;
281
- _outline_fix = 0 === ~~value % 2 ? 0 : 0.5;
284
+ _outline_fix = ~~value % 2 ? 0.5 : 0;
282
285
  },
283
286
  linedash(segments, offset = 0) {
284
287
  _ctx.setLineDash(segments);
@@ -313,18 +316,19 @@
313
316
  _ctx.drawImage(source, ~~x, ~~y);
314
317
  },
315
318
  spr(x, y, pixels) {
316
- const rows = pixels.trim().split("\n");
317
- for (let row = 0; row < rows.length; row++) {
318
- const chars = rows[row].trim();
319
- for (let col = 0; col < chars.length; col++) {
320
- const char = chars[col];
321
- if (char !== "." && char !== " ") {
319
+ const rows = pixels
320
+ .replace(/[^\w.\n]/g, "")
321
+ .split("\n")
322
+ .filter((s) => s);
323
+ for (let i = 0; i < rows.length; i++) {
324
+ for (let j = 0; j < rows[i].length; j++) {
325
+ if (rows[i][j] !== ".") {
322
326
  instance.rectfill(
323
- x + col,
324
- y + row,
327
+ x + j,
328
+ y + i,
325
329
  1,
326
330
  1,
327
- parseInt(char, 36) || 0,
331
+ parseInt(rows[i][j], 36) || 0,
328
332
  );
329
333
  }
330
334
  }
@@ -348,8 +352,17 @@
348
352
  }
349
353
  return _ctx;
350
354
  },
351
- push() {
355
+ push(
356
+ translateX = 0,
357
+ translateY = translateX,
358
+ rotation = 0,
359
+ scaleX = 1,
360
+ scaleY = scaleX,
361
+ ) {
352
362
  _ctx.save();
363
+ instance.translate(translateX, translateY);
364
+ instance.rotate(rotation);
365
+ instance.scale(scaleX, scaleY);
353
366
  },
354
367
  pop() {
355
368
  _ctx.restore();
@@ -436,7 +449,7 @@
436
449
  instance.emit("pal", _colorPalette, _defaultTextColor);
437
450
  },
438
451
  palc(a, b) {
439
- if (a == null) {
452
+ if (null == a) {
440
453
  _colorPaletteState = [];
441
454
  } else {
442
455
  _colorPaletteState[a] = b;
@@ -541,7 +554,7 @@
541
554
  _checkTapped = (tap) => tap && perf.now() - tap.t <= 300;
542
555
  let _pressingMouse = false;
543
556
  on(_canvas, "mousedown", (ev) => {
544
- if (ev.button === 0) {
557
+ if (!ev.button) {
545
558
  preventDefault(ev);
546
559
  const [x, y] = _getXY(ev);
547
560
  instance.emit("tap", x, y, 0);
@@ -550,7 +563,7 @@
550
563
  }
551
564
  });
552
565
  on(_canvas, "mouseup", (ev) => {
553
- if (ev.button === 0) {
566
+ if (!ev.button) {
554
567
  preventDefault(ev);
555
568
  const tap = _taps.get(0);
556
569
  const [x, y] = _getXY(ev);
package/dist/dist.min.js CHANGED
@@ -1 +1 @@
1
- (()=>{var e=["#211e20","#555568","#a0a08b","#e9efec"];window.litecanvas=function(t={}){let a,l=window,n=Math,i=performance,o=2*n.PI,r=requestAnimationFrame,s=[],f=(e,t,a)=>{e.addEventListener(t,a,!1),s.push(()=>e.removeEventListener(t,a,!1))},d=(l.zzfxX=new AudioContext,l.zzfxV=1,(e=1,t=.05,a=220,l=0,n=0,i=.1,o=0,r=1,s=0,f=0,d=0,c=0,p=0,u=0,h=0,m=0,g=0,v=1,x=0,w=0,y=0)=>{let b=Math,z=2*b.PI,k=s*=500*z/44100/44100,E=a*=(1-t+2*t*b.random(t=[]))*z/44100,T=0,P=0,C=0,I=1,L=0,D=0,A=0,S=y<0?-1:1,H=z*S*y*2/44100,M=b.cos(H),N=b.sin,W=N(H)/4,X=1+W,q=-2*M/X,B=(1-W)/X,V=(1+S*M)/2/X,O=-(S+M)/X,R=0,F=0,G=0,Y=0;for(l=44100*l+9,x*=44100,n*=44100,i*=44100,g*=44100,f*=500*z/85766121e6,h*=z/44100,d*=z/44100,c*=44100,p=44100*p|0,e*=.3*zzfxV,S=l+x+n+i+g|0;C<S;t[C++]=A*e)++D%(100*m|0)||(A=o?1<o?2<o?3<o?N(T*T):b.max(b.min(b.tan(T),1),-1):1-(2*T/z%2+2)%2:1-4*b.abs(b.round(T/z)-T/z):N(T),A=(p?1-w+w*N(z*C/p):1)*(A<0?-1:1)*b.abs(A)**r*(C<l?C/l:C<l+x?1-(C-l)/x*(1-v):C<l+x+n?v:C<S-g?(S-C-g)/i*v:0),A=g?A/2+(g>C?0:(C<S-g?1:(S-C)/g)*t[C-g|0]/2/e):A,y&&(A=Y=V*R+O*(R=F)+V*(F=A)-B*G-q*(G=Y))),T+=(H=(a+=s+=f)*b.cos(h*P++))+H*u*N(C**5),I&&++I>c&&(a+=d,E+=d,I=0),!p||++L%p||(a=E,s=k,I=I||1);(e=zzfxX.createBuffer(1,S,44100)).getChannelData(0).set(t),(a=zzfxX.createBufferSource()).buffer=e,a.connect(zzfxX.destination),a.start()}),c=(t=Object.assign({width:null,height:null,autoscale:!0,canvas:null,global:!0,loop:null,tapEvents:!0,keyboardEvents:!0},t)).loop,p=!1,u,h,m=1,g,v=.5,x=1,w,y=1e3/60,b,z=0,k=3,E="sans-serif",T=20,P=1.2,C=Date.now(),I=e,L=[],D=[.5,0,1750,,,.3,1,,,,600,.1],A={},S={W:0,H:0,T:0,MX:-1,MY:-1,TWO_PI:o,HALF_PI:o/4,lerp:(e,t,a)=>e+a*(t-e),deg2rad:e=>n.PI/180*e,rad2deg:e=>180/n.PI*e,round:(e,t=0)=>{if(!t)return n.round(e);let a=10**t;return n.round(e*a)/a},clamp:(e,t,a)=>e<t?t:e>a?a:e,dist:(e,t,a,l)=>n.hypot(a-e,l-t),wrap:(e,t,a)=>e-(a-t)*n.floor((e-t)/(a-t)),map(e,t,a,l,n,i){let o=(e-t)/(a-t)*(n-l)+l;return i?S.clamp(o,l,n):o},norm:(e,t,a)=>S.map(e,t,a,0,1),rand:(e=0,t=1)=>(C=(1664525*C+0x3c6ef35f)%0x100000000)/0x100000000*(t-e)+e,randi:(e=0,t=1)=>~~S.rand(e,t+1),rseed(e){C=~~e},cls(e){null==e?g.clearRect(0,0,S.W,S.H):S.rectfill(0,0,S.W,S.H,e)},rect(e,t,a,l,n,i){g.beginPath(),g[i?"roundRect":"rect"](~~e-v,~~t-v,~~a+2*v,~~l+2*v,i),S.stroke(n)},rectfill(e,t,a,l,n,i){g.beginPath(),g[i?"roundRect":"rect"](~~e,~~t,~~a,~~l,i),S.fill(n)},oval(e,t,a,l,n){g.beginPath(),g.ellipse(~~e,~~t,~~a,~~l,0,0,o),S.stroke(n)},ovalfill(e,t,a,l,n){g.beginPath(),g.ellipse(~~e,~~t,~~a,~~l,0,0,o),S.fill(n)},circ(e,t,a,l){S.oval(e,t,a,a,l)},circfill(e,t,a,l){S.ovalfill(e,t,a,a,l)},shape(e){g.beginPath();for(let t=0;t<e.length;t+=2)0===t?g.moveTo(~~e[t],~~e[t+1]):g.lineTo(~~e[t],~~e[t+1]);g.lineTo(~~e[0],~~e[1])},line(e,t,a,l,n){g.beginPath();let i=.5*(0!==v&&~~e==~~a),o=.5*(0!==v&&~~t==~~l);g.moveTo(~~e+i,~~t+o),g.lineTo(~~a+i,~~l+o),S.stroke(n)},linewidth(e){g.lineWidth=~~e,v=.5*(0!=~~e%2)},linedash(e,t=0){g.setLineDash(e),g.lineDashOffset=t},text(e,t,a,l=k,n="normal"){g.font=`${n} ${T}px ${E}`,g.fillStyle=X(l);let i=(""+a).split("\n");for(let a=0;a<i.length;a++)g.fillText(i[a],~~e,~~t+T*P*a)},textgap(e){P=e},textfont(e){E=e},textsize(e){T=e},textalign(e,t){e&&(g.textAlign=e),t&&(g.textBaseline=t)},image(e,t,a){g.drawImage(a,~~e,~~t)},spr(e,t,a){let l=a.trim().split("\n");for(let a=0;a<l.length;a++){let n=l[a].trim();for(let l=0;l<n.length;l++){let i=n[l];"."!==i&&" "!==i&&S.rectfill(e+l,t+a,1,1,parseInt(i,36)||0)}}},paint(e,t,a,l={}){let n=l.canvas||new OffscreenCanvas(1,1),i=l.scale||1,o=g;return n.width=e*i,n.height=t*i,(g=n.getContext("2d")).scale(i,i),a(g),g=o,n.transferToImageBitmap()},ctx:e=>(e&&(g=e),g),push(){g.save()},pop(){g.restore()},translate(e,t){g.translate(~~e,~~t)},scale(e,t=e){g.scale(e,t)},rotate(e){g.rotate(e)},alpha(e){g.globalAlpha=S.clamp(e,0,1)},fill(e){g.fillStyle=X(e),g.fill()},stroke(e){g.strokeStyle=X(e),g.stroke()},clip(e){g.beginPath(),e(g),g.clip()},sfx:(e,t,a)=>!!l.zzfxV&&(!navigator.userActivation||!!navigator.userActivation.hasBeenActive)&&(e||=D,(t||a>=0)&&((e=e.slice())[0]=a*(e[0]||1),e[10]=~~e[10]+t),d.apply(0,e),e),volume(e){l.zzfxV=e},canvas:()=>h,use(e,t={}){var a=e,l=t;let n=a(S,l);for(let e in n)S.def(e,n[e])},listen:(e,t)=>{A[e=e.toLowerCase()]=A[e]||new Set,A[e].add(t)},unlisten:(e,t)=>{A[e=e.toLowerCase()]&&A[e].delete(t)},emit:(e,t,a,n,i)=>(p&&(W("before:"+(e=e.toLowerCase()),t,a,n,i),c||l[e]===S[e]||"function"!=typeof l[e]||l[e](t,a,n,i),W(e,t,a,n,i),W("after:"+e,t,a,n,i)),t),pal(t,a=3){I=t||e,L=[],k=a,S.emit("pal",I,k)},palc(e,t){null==e?L=[]:L[e]=t},def(e,a){S[e]=a,t.global&&(l[e]=a)},timescale(e){x=e},framerate(e){y=1e3/~~e},stat:e=>[t,p,y/1e3,m,A,I,D,x,l.zzfxV,C,T,E,L,P][e],pause(){u||(u=!0,z=~~cancelAnimationFrame(z),S.emit("paused"))},resume(){p&&u&&(H(),u=!1,S.emit("resumed"))},ispaused:()=>u,quit(){for(let e of(S.emit("quit"),S.pause(),p=!1,A={},s))e();if(t.global){for(let e in S)delete l[e];delete l.ENGINE}}};for(let e of"PI,sin,cos,atan2,hypot,tan,abs,ceil,floor,trunc,min,max,pow,sqrt,sign,exp".split(","))S[e]=n[e];function H(){z||(b=0,w=i.now(),z=r(M))}function M(){z=r(M);let e=i.now(),t=0,a=e-w;for(w=e,b+=a<100?a:y;b>=y;){t++,b-=y;let e=y/1e3*x;S.emit("update",e,t),S.def("T",S.T+e)}t&&(S.emit("draw",g),t>1&&(b=0))}function N(){let e=t.width>0?t.width:innerWidth,a=t.width>0?t.height||t.width:innerHeight;if(S.def("W",e),S.def("H",a),h.width=e,h.height=a,t.autoscale){let l=+t.autoscale;h.style.display||(h.style.display="block",h.style.margin="auto"),m=n.min(innerWidth/e,innerHeight/a),m=l>1&&m>l?l:m,h.style.width=e*m+"px",h.style.height=a*m+"px"}g.imageSmoothingEnabled=!1,S.textalign("start","top"),S.emit("resized",m)}function W(e,t,a,l,n){if(A[e])for(let i of A[e])i(t,a,l,n)}function X(e){return I[~~(L[e]??e)%I.length]}if(t.global){if(l.ENGINE)throw Error("only one global litecanvas is allowed");Object.assign(l,S),l.ENGINE=S}if(a=document,g=(h=(h="string"==typeof t.canvas?a.querySelector(t.canvas):t.canvas)||a.createElement("canvas")).getContext("2d"),f(h,"click",()=>focus()),N(),h.parentNode||a.body.appendChild(h),h.style.imageRendering="pixelated",h.oncontextmenu=()=>!1,c)for(let e in c)c[e]&&S.listen(e,c[e]);return r(function(){if(t.autoscale&&f(l,"resize",N),t.tapEvents){let e=e=>[(e.pageX-h.offsetLeft)/m,(e.pageY-h.offsetTop)/m],t=new Map,a=(e,a,l)=>{let n={x:a,y:l,xi:a,yi:l,t:i.now()};return t.set(e,n),n},n=(e,l,n)=>{let i=t.get(e)||a(e);i.x=l,i.y=n},o=e=>e&&i.now()-e.t<=300,r=!1;f(h,"mousedown",t=>{if(0===t.button){t.preventDefault();let[l,n]=e(t);S.emit("tap",l,n,0),a(0,l,n),r=!0}}),f(h,"mouseup",a=>{if(0===a.button){a.preventDefault();let l=t.get(0),[n,i]=e(a);o(l)&&S.emit("tapped",l.xi,l.yi,0),S.emit("untap",n,i,0),t.delete(0),r=!1}}),f(l,"mousemove",t=>{t.preventDefault();let[a,l]=e(t);S.def("MX",a),S.def("MY",l),r&&(S.emit("tapping",a,l,0),n(0,a,l))}),f(h,"touchstart",t=>{for(let l of(t.preventDefault(),t.changedTouches)){let[t,n]=e(l);S.emit("tap",t,n,l.identifier+1),a(l.identifier+1,t,n)}}),f(h,"touchmove",t=>{for(let a of(t.preventDefault(),t.changedTouches)){let[t,l]=e(a);S.emit("tapping",t,l,a.identifier+1),n(a.identifier+1,t,l)}});let s=e=>{e.preventDefault();let a=[];for(let t of e.targetTouches)a.push(t.identifier+1);for(let[e,l]of t)a.includes(e)||(o(l)&&S.emit("tapped",l.xi,l.yi,e),S.emit("untap",l.x,l.y,e),t.delete(e))};f(h,"touchend",s),f(h,"touchcancel",s),f(l,"blur",()=>{for(let[e,a]of(r=!1,t))S.emit("untap",a.x,a.y,e),t.delete(e)})}if(t.keyboardEvents){let e=new Set,t=new Set,a=(e,t="")=>(t=t.toLowerCase())?e.has("space"===t?" ":t):e.size>0,n="";f(l,"keydown",a=>{let l=a.key.toLowerCase();e.has(l)||(e.add(l),t.add(l),n=" "===l?"space":l)}),f(l,"keyup",t=>{e.delete(t.key.toLowerCase())}),f(l,"blur",()=>e.clear()),S.listen("after:update",()=>t.clear()),S.def("iskeydown",t=>a(e,t)),S.def("iskeypressed",e=>a(t,e)),S.def("lastkey",()=>n)}p=!0,S.emit("init",S),u||H()}),S}})();
1
+ (()=>{var e=["#211e20","#555568","#a0a08b","#e9efec"];window.litecanvas=function(t={}){let a,l=window,n=Math,i=performance,o=2*n.PI,r=requestAnimationFrame,s=[],f=(e,t,a)=>{e.addEventListener(t,a,!1),s.push(()=>e.removeEventListener(t,a,!1))},d=(l.zzfxX=new AudioContext,l.zzfxV=1,(e=1,t=.05,a=220,l=0,n=0,i=.1,o=0,r=1,s=0,f=0,d=0,c=0,p=0,u=0,h=0,m=0,g=0,v=1,w=0,x=0,y=0)=>{let b=Math,z=2*b.PI,k=s*=500*z/44100/44100,E=a*=(1-t+2*t*b.random(t=[]))*z/44100,T=0,P=0,C=0,I=1,L=0,D=0,A=0,S=y<0?-1:1,H=z*S*y*2/44100,M=b.cos(H),N=b.sin,W=N(H)/4,X=1+W,q=-2*M/X,B=(1-W)/X,V=(1+S*M)/2/X,O=-(S+M)/X,R=0,F=0,G=0,Y=0;for(l=44100*l+9,w*=44100,n*=44100,i*=44100,g*=44100,f*=500*z/85766121e6,h*=z/44100,d*=z/44100,c*=44100,p=44100*p|0,e*=.3*zzfxV,S=l+w+n+i+g|0;C<S;t[C++]=A*e)++D%(100*m|0)||(A=o?1<o?2<o?3<o?N(T*T):b.max(b.min(b.tan(T),1),-1):1-(2*T/z%2+2)%2:1-4*b.abs(b.round(T/z)-T/z):N(T),A=(p?1-x+x*N(z*C/p):1)*(A<0?-1:1)*b.abs(A)**r*(C<l?C/l:C<l+w?1-(C-l)/w*(1-v):C<l+w+n?v:C<S-g?(S-C-g)/i*v:0),A=g?A/2+(g>C?0:(C<S-g?1:(S-C)/g)*t[C-g|0]/2/e):A,y&&(A=Y=V*R+O*(R=F)+V*(F=A)-B*G-q*(G=Y))),T+=(H=(a+=s+=f)*b.cos(h*P++))+H*u*N(C**5),I&&++I>c&&(a+=d,E+=d,I=0),!p||++L%p||(a=E,s=k,I=I||1);(e=zzfxX.createBuffer(1,S,44100)).getChannelData(0).set(t),(a=zzfxX.createBufferSource()).buffer=e,a.connect(zzfxX.destination),a.start()}),c=(t=Object.assign({width:null,height:null,autoscale:!0,canvas:null,global:!0,loop:null,tapEvents:!0,keyboardEvents:!0},t)).loop,p=!1,u,h,m=1,g,v=.5,w=1,x,y=1e3/60,b,z=0,k=3,E="sans-serif",T=20,P=1.2,C=Date.now(),I=e,L=[],D=[.5,0,1750,,,.3,1,,,,600,.1],A={},S={W:0,H:0,T:0,MX:-1,MY:-1,TWO_PI:o,HALF_PI:o/4,lerp:(e,t,a)=>e+a*(t-e),deg2rad:e=>n.PI/180*e,rad2deg:e=>180/n.PI*e,mod:(e,t)=>(e%t+t)%t||0,round:(e,t=0)=>{if(!t)return n.round(e);let a=10**t;return n.round(e*a)/a},clamp:(e,t,a)=>e<t?t:e>a?a:e,dist:(e,t,a,l)=>n.hypot(a-e,l-t),wrap:(e,t,a)=>e-(a-t)*n.floor((e-t)/(a-t)),map(e,t,a,l,n,i){let o=(e-t)/(a-t)*(n-l)+l;return i?S.clamp(o,l,n):o},norm:(e,t,a)=>S.map(e,t,a,0,1),rand:(e=0,t=1)=>(C=(1664525*C+0x3c6ef35f)%0x100000000)/0x100000000*(t-e)+e,randi:(e=0,t=1)=>~~S.rand(e,t+1),rseed(e){C=~~e},cls(e){null==e?g.clearRect(0,0,S.W,S.H):S.rectfill(0,0,S.W,S.H,e)},rect(e,t,a,l,n,i){g.beginPath(),g[i?"roundRect":"rect"](~~e-v,~~t-v,~~a+2*v,~~l+2*v,i),S.stroke(n)},rectfill(e,t,a,l,n,i){g.beginPath(),g[i?"roundRect":"rect"](~~e,~~t,~~a,~~l,i),S.fill(n)},oval(e,t,a,l,n){g.beginPath(),g.ellipse(~~e,~~t,~~a,~~l,0,0,o),S.stroke(n)},ovalfill(e,t,a,l,n){g.beginPath(),g.ellipse(~~e,~~t,~~a,~~l,0,0,o),S.fill(n)},circ(e,t,a,l){S.oval(e,t,a,a,l)},circfill(e,t,a,l){S.ovalfill(e,t,a,a,l)},shape(e){g.beginPath();for(let t=0;t<e.length;t+=2)t?g.lineTo(~~e[t],~~e[t+1]):g.moveTo(~~e[t],~~e[t+1]);g.lineTo(~~e[0],~~e[1])},line(e,t,a,l,n){g.beginPath();let i=v&&~~e==~~a?.5:0,o=v&&~~t==~~l?.5:0;g.moveTo(~~e+i,~~t+o),g.lineTo(~~a+i,~~l+o),S.stroke(n)},linewidth(e){g.lineWidth=~~e,v=~~e%2?.5:0},linedash(e,t=0){g.setLineDash(e),g.lineDashOffset=t},text(e,t,a,l=k,n="normal"){g.font=`${n} ${T}px ${E}`,g.fillStyle=X(l);let i=(""+a).split("\n");for(let a=0;a<i.length;a++)g.fillText(i[a],~~e,~~t+T*P*a)},textgap(e){P=e},textfont(e){E=e},textsize(e){T=e},textalign(e,t){e&&(g.textAlign=e),t&&(g.textBaseline=t)},image(e,t,a){g.drawImage(a,~~e,~~t)},spr(e,t,a){let l=a.replace(/[^\w.\n]/g,"").split("\n").filter(e=>e);for(let a=0;a<l.length;a++)for(let n=0;n<l[a].length;n++)"."!==l[a][n]&&S.rectfill(e+n,t+a,1,1,parseInt(l[a][n],36)||0)},paint(e,t,a,l={}){let n=l.canvas||new OffscreenCanvas(1,1),i=l.scale||1,o=g;return n.width=e*i,n.height=t*i,(g=n.getContext("2d")).scale(i,i),a(g),g=o,n.transferToImageBitmap()},ctx:e=>(e&&(g=e),g),push(e=0,t=e,a=0,l=1,n=l){g.save(),S.translate(e,t),S.rotate(a),S.scale(l,n)},pop(){g.restore()},translate(e,t){g.translate(~~e,~~t)},scale(e,t=e){g.scale(e,t)},rotate(e){g.rotate(e)},alpha(e){g.globalAlpha=S.clamp(e,0,1)},fill(e){g.fillStyle=X(e),g.fill()},stroke(e){g.strokeStyle=X(e),g.stroke()},clip(e){g.beginPath(),e(g),g.clip()},sfx:(e,t,a)=>!!l.zzfxV&&(!navigator.userActivation||!!navigator.userActivation.hasBeenActive)&&(e||=D,(t||a>=0)&&((e=e.slice())[0]=a*(e[0]||1),e[10]=~~e[10]+t),d.apply(0,e),e),volume(e){l.zzfxV=e},canvas:()=>h,use(e,t={}){var a=e,l=t;let n=a(S,l);for(let e in n)S.def(e,n[e])},listen:(e,t)=>{A[e=e.toLowerCase()]=A[e]||new Set,A[e].add(t)},unlisten:(e,t)=>{A[e=e.toLowerCase()]&&A[e].delete(t)},emit:(e,t,a,n,i)=>(p&&(W("before:"+(e=e.toLowerCase()),t,a,n,i),c||l[e]===S[e]||"function"!=typeof l[e]||l[e](t,a,n,i),W(e,t,a,n,i),W("after:"+e,t,a,n,i)),t),pal(t,a=3){I=t||e,L=[],k=a,S.emit("pal",I,k)},palc(e,t){null==e?L=[]:L[e]=t},def(e,a){S[e]=a,t.global&&(l[e]=a)},timescale(e){w=e},framerate(e){y=1e3/~~e},stat:e=>[t,p,y/1e3,m,A,I,D,w,l.zzfxV,C,T,E,L,P][e],pause(){u||(u=!0,z=~~cancelAnimationFrame(z),S.emit("paused"))},resume(){p&&u&&(H(),u=!1,S.emit("resumed"))},ispaused:()=>u,quit(){for(let e of(S.emit("quit"),S.pause(),p=!1,A={},s))e();if(t.global){for(let e in S)delete l[e];delete l.ENGINE}}};for(let e of"PI,sin,cos,atan2,hypot,tan,abs,ceil,floor,trunc,min,max,pow,sqrt,sign,exp".split(","))S[e]=n[e];function H(){z||(b=0,x=i.now(),z=r(M))}function M(){z=r(M);let e=i.now(),t=0,a=e-x;for(x=e,b+=a<100?a:y;b>=y;){t++,b-=y;let e=y/1e3*w;S.emit("update",e,t),S.def("T",S.T+e)}t&&(S.emit("draw",g),t>1&&(b=0))}function N(){let e=t.width>0?t.width:innerWidth,a=t.width>0?t.height||t.width:innerHeight;if(S.def("W",e),S.def("H",a),h.width=e,h.height=a,t.autoscale){let l=+t.autoscale;h.style.display||(h.style.display="block",h.style.margin="auto"),m=n.min(innerWidth/e,innerHeight/a),m=l>1&&m>l?l:m,h.style.width=e*m+"px",h.style.height=a*m+"px"}g.imageSmoothingEnabled=!1,S.textalign("start","top"),S.emit("resized",m)}function W(e,t,a,l,n){if(A[e])for(let i of A[e])i(t,a,l,n)}function X(e){return I[~~(L[e]??e)%I.length]}if(t.global){if(l.ENGINE)throw Error("only one global litecanvas is allowed");Object.assign(l,S),l.ENGINE=S}if(a=document,g=(h=(h="string"==typeof t.canvas?a.querySelector(t.canvas):t.canvas)||a.createElement("canvas")).getContext("2d"),f(h,"click",()=>focus()),N(),h.parentNode||a.body.appendChild(h),h.style.imageRendering="pixelated",h.oncontextmenu=()=>!1,c)for(let e in c)c[e]&&S.listen(e,c[e]);return r(function(){if(t.autoscale&&f(l,"resize",N),t.tapEvents){let e=e=>[(e.pageX-h.offsetLeft)/m,(e.pageY-h.offsetTop)/m],t=new Map,a=(e,a,l)=>{let n={x:a,y:l,xi:a,yi:l,t:i.now()};return t.set(e,n),n},n=(e,l,n)=>{let i=t.get(e)||a(e);i.x=l,i.y=n},o=e=>e&&i.now()-e.t<=300,r=!1;f(h,"mousedown",t=>{if(!t.button){t.preventDefault();let[l,n]=e(t);S.emit("tap",l,n,0),a(0,l,n),r=!0}}),f(h,"mouseup",a=>{if(!a.button){a.preventDefault();let l=t.get(0),[n,i]=e(a);o(l)&&S.emit("tapped",l.xi,l.yi,0),S.emit("untap",n,i,0),t.delete(0),r=!1}}),f(l,"mousemove",t=>{t.preventDefault();let[a,l]=e(t);S.def("MX",a),S.def("MY",l),r&&(S.emit("tapping",a,l,0),n(0,a,l))}),f(h,"touchstart",t=>{for(let l of(t.preventDefault(),t.changedTouches)){let[t,n]=e(l);S.emit("tap",t,n,l.identifier+1),a(l.identifier+1,t,n)}}),f(h,"touchmove",t=>{for(let a of(t.preventDefault(),t.changedTouches)){let[t,l]=e(a);S.emit("tapping",t,l,a.identifier+1),n(a.identifier+1,t,l)}});let s=e=>{e.preventDefault();let a=[];for(let t of e.targetTouches)a.push(t.identifier+1);for(let[e,l]of t)a.includes(e)||(o(l)&&S.emit("tapped",l.xi,l.yi,e),S.emit("untap",l.x,l.y,e),t.delete(e))};f(h,"touchend",s),f(h,"touchcancel",s),f(l,"blur",()=>{for(let[e,a]of(r=!1,t))S.emit("untap",a.x,a.y,e),t.delete(e)})}if(t.keyboardEvents){let e=new Set,t=new Set,a=(e,t="")=>(t=t.toLowerCase())?e.has("space"===t?" ":t):e.size>0,n="";f(l,"keydown",a=>{let l=a.key.toLowerCase();e.has(l)||(e.add(l),t.add(l),n=" "===l?"space":l)}),f(l,"keyup",t=>{e.delete(t.key.toLowerCase())}),f(l,"blur",()=>e.clear()),S.listen("after:update",()=>t.clear()),S.def("iskeydown",t=>a(e,t)),S.def("iskeypressed",e=>a(t,e)),S.def("lastkey",()=>n)}p=!0,S.emit("init",S),u||H()}),S}})();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "litecanvas",
3
- "version": "0.207.2",
3
+ "version": "0.209.0",
4
4
  "description": "Lightweight HTML5 canvas 2D game engine suitable for small projects and creative coding. Inspired by PICO-8 and p5.js/Processing.",
5
5
  "license": "MIT",
6
6
  "author": "Luiz Bills <luizbills@pm.me>",
package/src/index.js CHANGED
@@ -45,7 +45,7 @@ export default function litecanvas(settings = {}) {
45
45
 
46
46
  DEV: assert(
47
47
  null == settings || 'object' === typeof settings,
48
- 'litecanvas() 1st parameter must be a object or null'
48
+ 'litecanvas() 1st parameter must be a object'
49
49
  )
50
50
 
51
51
  // setup the settings default values
@@ -173,6 +173,25 @@ export default function litecanvas(settings = {}) {
173
173
  return (180 / math.PI) * rads
174
174
  },
175
175
 
176
+ /**
177
+ * Modulus (Euclidean division).
178
+ *
179
+ * Note: When `b == 0` returns `0`, rather than `NaN`.
180
+ *
181
+ * @param {number} a dividend
182
+ * @param {number} b divisor
183
+ * @returns {number} the remainder
184
+ * @example
185
+ * mod(-1, 5) // => 4
186
+ * -1 % 5 // => -1
187
+ */
188
+ mod(a, b) {
189
+ DEV: assert(isNumber(a), 'mod() 1st parameter must be a number')
190
+ DEV: assert(isNumber(b) && b >= 0, 'mod() 2nd parameter must be a non-negative number')
191
+
192
+ return ((a % b) + b) % b || 0
193
+ },
194
+
176
195
  /**
177
196
  * Returns the rounded value of an number to optional precision (number of digits after the decimal point).
178
197
  *
@@ -186,7 +205,7 @@ export default function litecanvas(settings = {}) {
186
205
  DEV: assert(isNumber(n), 'round() 1st parameter must be a number')
187
206
  DEV: assert(
188
207
  isNumber(precision) && precision >= 0,
189
- 'round() 2nd parameter must be a positive number or zero'
208
+ 'round() 2nd parameter must be a non-negative number'
190
209
  )
191
210
 
192
211
  if (!precision) {
@@ -347,7 +366,7 @@ export default function litecanvas(settings = {}) {
347
366
  rseed(value) {
348
367
  DEV: assert(
349
368
  isNumber(value) && value >= 0,
350
- 'rseed() 1st parameter must be a positive integer or zero'
369
+ 'rseed() 1st parameter must be a non-negative integer'
351
370
  )
352
371
 
353
372
  _rngSeed = ~~value
@@ -355,14 +374,14 @@ export default function litecanvas(settings = {}) {
355
374
 
356
375
  /** BASIC GRAPHICS API */
357
376
  /**
358
- * Clear the game screen with an optional color
377
+ * Clear the game screen with an optional color.
359
378
  *
360
379
  * @param {number} [color] The background color (index) or null/undefined (for transparent)
361
380
  */
362
381
  cls(color) {
363
382
  DEV: assert(
364
383
  null == color || (isNumber(color) && color >= 0),
365
- 'cls() 1st parameter must be a positive number or zero or undefined'
384
+ 'cls() 1st parameter must be a non-negative number'
366
385
  )
367
386
 
368
387
  if (null == color) {
@@ -393,11 +412,11 @@ export default function litecanvas(settings = {}) {
393
412
  )
394
413
  DEV: assert(
395
414
  isNumber(height) && height >= 0,
396
- 'rect() 4th parameter must be a positive number or zero'
415
+ 'rect() 4th parameter must be a non-negative number'
397
416
  )
398
417
  DEV: assert(
399
418
  null == color || (isNumber(color) && color >= 0),
400
- 'rect() 5th parameter must be a positive number or zero'
419
+ 'rect() 5th parameter must be a non-negative number'
401
420
  )
402
421
  DEV: assert(
403
422
  null == radii || isNumber(radii) || (Array.isArray(radii) && radii.length >= 1),
@@ -405,6 +424,7 @@ export default function litecanvas(settings = {}) {
405
424
  )
406
425
 
407
426
  beginPath(_ctx)
427
+
408
428
  _ctx[radii ? 'roundRect' : 'rect'](
409
429
  ~~x - _outline_fix,
410
430
  ~~y - _outline_fix,
@@ -430,15 +450,15 @@ export default function litecanvas(settings = {}) {
430
450
  DEV: assert(isNumber(y), 'rectfill() 2nd parameter must be a number')
431
451
  DEV: assert(
432
452
  isNumber(width) && width >= 0,
433
- 'rectfill() 3rd parameter must be a positive number or zero'
453
+ 'rectfill() 3rd parameter must be a non-negative number'
434
454
  )
435
455
  DEV: assert(
436
456
  isNumber(height) && height >= 0,
437
- 'rectfill() 4th parameter must be a positive number or zero'
457
+ 'rectfill() 4th parameter must be a non-negative number'
438
458
  )
439
459
  DEV: assert(
440
460
  null == color || (isNumber(color) && color >= 0),
441
- 'rectfill() 5th parameter must be a positive number or zero'
461
+ 'rectfill() 5th parameter must be a non-negative number'
442
462
  )
443
463
  DEV: assert(
444
464
  null == radii || isNumber(radii) || (Array.isArray(radii) && radii.length >= 1),
@@ -447,6 +467,7 @@ export default function litecanvas(settings = {}) {
447
467
  )
448
468
 
449
469
  beginPath(_ctx)
470
+
450
471
  _ctx[radii ? 'roundRect' : 'rect'](~~x, ~~y, ~~width, ~~height, radii)
451
472
  instance.fill(color)
452
473
  },
@@ -465,18 +486,19 @@ export default function litecanvas(settings = {}) {
465
486
  DEV: assert(isNumber(y), 'oval() 2nd parameter must be a number')
466
487
  DEV: assert(
467
488
  isNumber(radiusX) && radiusX >= 0,
468
- 'oval() 3rd parameter must be a positive number or zero'
489
+ 'oval() 3rd parameter must be a non-negative number'
469
490
  )
470
491
  DEV: assert(
471
492
  isNumber(radiusY) && radiusY >= 0,
472
- 'oval() 4th parameter must be a positive number or zero'
493
+ 'oval() 4th parameter must be a non-negative number'
473
494
  )
474
495
  DEV: assert(
475
496
  null == color || (isNumber(color) && color >= 0),
476
- 'oval() 5th parameter must be a positive number or zero'
497
+ 'oval() 5th parameter must be a non-negative number'
477
498
  )
478
499
 
479
500
  beginPath(_ctx)
501
+
480
502
  _ctx.ellipse(~~x, ~~y, ~~radiusX, ~~radiusY, 0, 0, TWO_PI)
481
503
  instance.stroke(color)
482
504
  },
@@ -495,18 +517,19 @@ export default function litecanvas(settings = {}) {
495
517
  DEV: assert(isNumber(y), 'ovalfill() 2nd parameter must be a number')
496
518
  DEV: assert(
497
519
  isNumber(radiusX) && radiusX >= 0,
498
- 'ovalfill() 3rd parameter must be a positive number or zero'
520
+ 'ovalfill() 3rd parameter must be a non-negative number'
499
521
  )
500
522
  DEV: assert(
501
523
  isNumber(radiusY) && radiusY >= 0,
502
- 'ovalfill() 4th parameter must be a positive number or zero'
524
+ 'ovalfill() 4th parameter must be a non-negative number'
503
525
  )
504
526
  DEV: assert(
505
527
  null == color || (isNumber(color) && color >= 0),
506
- 'ovalfill() 5th parameter must be a positive number or zero'
528
+ 'ovalfill() 5th parameter must be a non-negative number'
507
529
  )
508
530
 
509
531
  beginPath(_ctx)
532
+
510
533
  _ctx.ellipse(~~x, ~~y, ~~radiusX, ~~radiusY, 0, 0, TWO_PI)
511
534
  instance.fill(color)
512
535
  },
@@ -524,11 +547,11 @@ export default function litecanvas(settings = {}) {
524
547
  DEV: assert(isNumber(y), 'circ() 2nd parameter must be a number')
525
548
  DEV: assert(
526
549
  isNumber(radius) && radius >= 0,
527
- 'circ() 3rd parameter must be a positive number or zero'
550
+ 'circ() 3rd parameter must be a non-negative number'
528
551
  )
529
552
  DEV: assert(
530
553
  null == color || (isNumber(color) && color >= 0),
531
- 'circ() 4th parameter must be a positive number or zero'
554
+ 'circ() 4th parameter must be a non-negative number'
532
555
  )
533
556
 
534
557
  instance.oval(x, y, radius, radius, color)
@@ -547,11 +570,11 @@ export default function litecanvas(settings = {}) {
547
570
  DEV: assert(isNumber(y), 'circfill() 2nd parameter must be a number')
548
571
  DEV: assert(
549
572
  isNumber(radius) && radius >= 0,
550
- 'circfill() 3rd parameter must be a positive number or zero'
573
+ 'circfill() 3rd parameter must be a non-negative number'
551
574
  )
552
575
  DEV: assert(
553
576
  null == color || (isNumber(color) && color >= 0),
554
- 'circfill() 4th parameter must be a positive number or zero'
577
+ 'circfill() 4th parameter must be a non-negative number'
555
578
  )
556
579
 
557
580
  instance.ovalfill(x, y, radius, radius, color)
@@ -567,15 +590,16 @@ export default function litecanvas(settings = {}) {
567
590
  DEV: assert(Array.isArray(points), 'shape() 1st parameter must be an array of numbers')
568
591
  DEV: assert(
569
592
  points.length >= 6,
570
-
571
593
  'shape() 1st parameter must be an array with at least 6 numbers (3 points)'
572
594
  )
595
+
573
596
  beginPath(_ctx)
597
+
574
598
  for (let i = 0; i < points.length; i += 2) {
575
- if (0 === i) {
576
- _ctx.moveTo(~~points[i], ~~points[i + 1])
577
- } else {
599
+ if (i) {
578
600
  _ctx.lineTo(~~points[i], ~~points[i + 1])
601
+ } else {
602
+ _ctx.moveTo(~~points[i], ~~points[i + 1])
579
603
  }
580
604
  }
581
605
  _ctx.lineTo(~~points[0], ~~points[1])
@@ -593,17 +617,17 @@ export default function litecanvas(settings = {}) {
593
617
  line(x1, y1, x2, y2, color) {
594
618
  DEV: assert(isNumber(x1), 'line() 1st parameter must be a number')
595
619
  DEV: assert(isNumber(y1), 'line() 2nd parameter must be a number')
596
- DEV: assert(isNumber(x2), 'line() 3rd parameter must be a positive number or zero')
597
- DEV: assert(isNumber(y2), 'line() 4th parameter must be a positive number or zero')
620
+ DEV: assert(isNumber(x2), 'line() 3rd parameter must be a non-negative number')
621
+ DEV: assert(isNumber(y2), 'line() 4th parameter must be a non-negative number')
598
622
  DEV: assert(
599
623
  null == color || (isNumber(color) && color >= 0),
600
- 'line() 5th parameter must be a positive number or zero'
624
+ 'line() 5th parameter must be a non-negative number'
601
625
  )
602
626
 
603
627
  beginPath(_ctx)
604
628
 
605
- let xfix = _outline_fix !== 0 && ~~x1 === ~~x2 ? 0.5 : 0
606
- let yfix = _outline_fix !== 0 && ~~y1 === ~~y2 ? 0.5 : 0
629
+ let xfix = _outline_fix && ~~x1 === ~~x2 ? 0.5 : 0
630
+ let yfix = _outline_fix && ~~y1 === ~~y2 ? 0.5 : 0
607
631
 
608
632
  _ctx.moveTo(~~x1 + xfix, ~~y1 + yfix)
609
633
  _ctx.lineTo(~~x2 + xfix, ~~y2 + yfix)
@@ -620,11 +644,11 @@ export default function litecanvas(settings = {}) {
620
644
  linewidth(value) {
621
645
  DEV: assert(
622
646
  isNumber(value) && value >= 0,
623
- 'linewidth() 1st parameter must be a positive number or zero'
647
+ 'linewidth() 1st parameter must be a non-negative integer'
624
648
  )
625
649
 
626
650
  _ctx.lineWidth = ~~value
627
- _outline_fix = 0 === ~~value % 2 ? 0 : 0.5
651
+ _outline_fix = ~~value % 2 ? 0.5 : 0
628
652
  },
629
653
 
630
654
  /**
@@ -661,7 +685,7 @@ export default function litecanvas(settings = {}) {
661
685
  DEV: assert(isNumber(y), 'text() 2nd parameter must be a number')
662
686
  DEV: assert(
663
687
  null == color || (isNumber(color) && color >= 0),
664
- 'text() 4th parameter must be a positive number or zero'
688
+ 'text() 4th parameter must be a non-negative number'
665
689
  )
666
690
  DEV: assert('string' === typeof fontStyle, 'text() 5th parameter must be a string')
667
691
 
@@ -752,7 +776,11 @@ export default function litecanvas(settings = {}) {
752
776
  },
753
777
 
754
778
  /**
755
- * Draw a sprite pixel by pixel represented by a string. Each pixel must be a base 36 number (0-9 or a-z) or a dot.
779
+ * Draw a sprite, using a string of rows and columns representing a bitmask.
780
+ * - Each colored pixel must be a base 36 number (0-9 or a-z).
781
+ * - Use "." (dot) for transparent pixels.
782
+ * - Any other characters (like symbols) are ignored.
783
+ * - empty lines are ignored
756
784
  *
757
785
  * @param {number} x
758
786
  * @param {number} y
@@ -763,14 +791,15 @@ export default function litecanvas(settings = {}) {
763
791
  DEV: assert(isNumber(y), 'spr() 2nd parameter must be a number')
764
792
  DEV: assert('string' === typeof pixels, 'spr() 3rd parameter must be a string')
765
793
 
766
- const rows = pixels.trim().split('\n')
794
+ const rows = pixels
795
+ .replace(/[^\w.\n]/g, '')
796
+ .split('\n')
797
+ .filter((s) => s)
767
798
 
768
- for (let row = 0; row < rows.length; row++) {
769
- const chars = rows[row].trim()
770
- for (let col = 0; col < chars.length; col++) {
771
- const char = chars[col]
772
- if (char !== '.' && char !== ' ') {
773
- instance.rectfill(x + col, y + row, 1, 1, parseInt(char, 36) || 0)
799
+ for (let i = 0; i < rows.length; i++) {
800
+ for (let j = 0; j < rows[i].length; j++) {
801
+ if (rows[i][j] !== '.') {
802
+ instance.rectfill(x + j, y + i, 1, 1, parseInt(rows[i][j], 36) || 0)
774
803
  }
775
804
  }
776
805
  }
@@ -844,16 +873,32 @@ export default function litecanvas(settings = {}) {
844
873
  if (context) {
845
874
  _ctx = context
846
875
  }
876
+
847
877
  return _ctx
848
878
  },
849
879
 
850
880
  /**
851
- * saves the current drawing style settings and transformations
881
+ * Saves the current drawing style settings and, optionally, transforms (translate/rotate/scale) the canvas.
882
+ *
883
+ * @param {number} [translateX]
884
+ * @param {number} [translateY]
885
+ * @param {number} [rotation] in radians
886
+ * @param {number} [scaleX]
887
+ * @param {number} [scaleY]
852
888
  *
853
889
  * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/save
854
890
  */
855
- push() {
891
+ push(translateX = 0, translateY = translateX, rotation = 0, scaleX = 1, scaleY = scaleX) {
892
+ DEV: assert(isNumber(translateX), 'push() 1st parameter must be a number')
893
+ DEV: assert(isNumber(translateY), 'push() 2nd parameter must be a number')
894
+ DEV: assert(isNumber(rotation), 'push() 3rd parameter must be a number')
895
+ DEV: assert(isNumber(scaleX), 'push() 4th parameter must be a number')
896
+ DEV: assert(isNumber(scaleY), 'push() 5th parameter must be a number')
897
+
856
898
  _ctx.save()
899
+ instance.translate(translateX, translateY)
900
+ instance.rotate(rotation)
901
+ instance.scale(scaleX, scaleY)
857
902
  },
858
903
 
859
904
  /**
@@ -922,7 +967,7 @@ export default function litecanvas(settings = {}) {
922
967
  fill(color) {
923
968
  DEV: assert(
924
969
  null == color || (isNumber(color) && color >= 0),
925
- 'fill() 1st parameter must be a positive number or zero'
970
+ 'fill() 1st parameter must be a non-negative number'
926
971
  )
927
972
 
928
973
  _ctx.fillStyle = getColor(color)
@@ -937,7 +982,7 @@ export default function litecanvas(settings = {}) {
937
982
  stroke(color) {
938
983
  DEV: assert(
939
984
  null == color || (isNumber(color) && color >= 0),
940
- 'stroke() 1st parameter must be a positive number or zero'
985
+ 'stroke() 1st parameter must be a non-negative number'
941
986
  )
942
987
 
943
988
  _ctx.strokeStyle = getColor(color)
@@ -1017,7 +1062,7 @@ export default function litecanvas(settings = {}) {
1017
1062
  volume(value) {
1018
1063
  DEV: assert(
1019
1064
  isNumber(value) && value >= 0,
1020
- 'volume() 1st parameter must be a positive number or zero'
1065
+ 'volume() 1st parameter must be a non-negative number'
1021
1066
  )
1022
1067
 
1023
1068
  root.zzfxV = value
@@ -1137,7 +1182,7 @@ export default function litecanvas(settings = {}) {
1137
1182
  )
1138
1183
  DEV: assert(
1139
1184
  isNumber(textColor) && textColor >= 0,
1140
- 'pal() 2nd parameter must be a positive number or zero'
1185
+ 'pal() 2nd parameter must be a non-negative number'
1141
1186
  )
1142
1187
 
1143
1188
  _colorPalette = colors || defaultPalette
@@ -1167,7 +1212,7 @@ export default function litecanvas(settings = {}) {
1167
1212
  'palc() 2nd parameter must be a positive number'
1168
1213
  )
1169
1214
 
1170
- if (a == null) {
1215
+ if (null == a) {
1171
1216
  _colorPaletteState = []
1172
1217
  } else {
1173
1218
  _colorPaletteState[a] = b
@@ -1209,7 +1254,7 @@ export default function litecanvas(settings = {}) {
1209
1254
  timescale(value) {
1210
1255
  DEV: assert(
1211
1256
  isNumber(value) && value >= 0,
1212
- 'timescale() 1st parameter must be a positive number or zero'
1257
+ 'timescale() 1st parameter must be a non-negative number'
1213
1258
  )
1214
1259
 
1215
1260
  _timeScale = value
@@ -1391,6 +1436,9 @@ export default function litecanvas(settings = {}) {
1391
1436
  (ev.pageX - _canvas.offsetLeft) / _canvasScale,
1392
1437
  (ev.pageY - _canvas.offsetTop) / _canvasScale,
1393
1438
  ],
1439
+ /**
1440
+ * @type {Map<number,{x:number, y:number, xi: number, yi: number, t:number}>}
1441
+ */
1394
1442
  _taps = new Map(),
1395
1443
  _registerTap =
1396
1444
  /**
@@ -1440,7 +1488,7 @@ export default function litecanvas(settings = {}) {
1440
1488
  * @param {MouseEvent} ev
1441
1489
  */
1442
1490
  (ev) => {
1443
- if (ev.button === 0) {
1491
+ if (!ev.button) {
1444
1492
  preventDefault(ev)
1445
1493
  const [x, y] = _getXY(ev)
1446
1494
  instance.emit('tap', x, y, 0)
@@ -1457,7 +1505,7 @@ export default function litecanvas(settings = {}) {
1457
1505
  * @param {MouseEvent} ev
1458
1506
  */
1459
1507
  (ev) => {
1460
- if (ev.button === 0) {
1508
+ if (!ev.button) {
1461
1509
  preventDefault(ev)
1462
1510
  const tap = _taps.get(0)
1463
1511
  const [x, y] = _getXY(ev)
package/src/version.js CHANGED
@@ -1,2 +1,2 @@
1
1
  // Generated by genversion.
2
- export const version = '0.207.2'
2
+ export const version = '0.209.0'
package/types/global.d.ts CHANGED
@@ -59,6 +59,19 @@ declare global {
59
59
  * @returns the value in degrees
60
60
  */
61
61
  function rad2deg(rads: number): number
62
+ /**
63
+ * Modulus (Euclidean division).
64
+ *
65
+ * Note: When `b == 0` returns `0`, rather than `NaN`.
66
+ *
67
+ * @param a dividend
68
+ * @param b divisor
69
+ * @returns the remainder
70
+ * @example
71
+ * mod(-1, 5) // => 4
72
+ * -1 % 5 // => -1
73
+ */
74
+ function mod(a: number, b: number): number
62
75
  /**
63
76
  * Returns the rounded value of an number to optional precision (number of digits after the decimal point).
64
77
  *
@@ -388,15 +401,32 @@ declare global {
388
401
  */
389
402
  function image(x: number, y: number, source: CanvasImageSource): void
390
403
  /**
391
- * Draw a sprite pixel by pixel represented by a string. Each pixel must be a base 36 number or a dot:
392
- *
393
- * - A base 36 number (`0-9` or `a-z`) represent a pixel color (supporting color palettes with max 36 colors).
394
- * - A dot (`.`) represent a transparent pixel.
395
- * - Spaces are ignored and can be used to improve the visualization.
404
+ * Draw a sprite, using a string of rows and columns representing a bitmask.
405
+ * - Each colored pixel must be a base 36 number (0-9 or a-z).
406
+ * - Use "." (dot) for transparent pixels.
407
+ * - Any other characters (like symbols) are ignored.
408
+ * - empty lines are ignored
396
409
  *
397
- * @param x the position X of the first pixel
398
- * @param y the position Y of the first pixel
410
+ * @param x
411
+ * @param y
399
412
  * @param pixels
413
+ * @see https://litecanvas.js.org/tools/pixel-art-editor.html
414
+ * @example
415
+ * function draw() {
416
+ * // a little white key 8x8 sprite
417
+ * const littleKeySprite = `
418
+ * ........
419
+ * .3......
420
+ * 323.....
421
+ * 3.333333
422
+ * 3.322323
423
+ * 232..2.2
424
+ * .2......
425
+ * ........
426
+ * `
427
+ * // draw the sprite pixels at position x=10, y=10
428
+ * spr(10, 10, littleKeySprite)
429
+ * }
400
430
  */
401
431
  function spr(x: number, y: number, pixels: string): void
402
432
  /**
@@ -430,10 +460,23 @@ declare global {
430
460
  context?: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D
431
461
  ): CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D
432
462
  /**
433
- * saves the current drawing style settings and transformations
463
+ * Saves the current drawing style settings and, optionally, transforms (translate/rotate/scale) the canvas.
464
+ *
465
+ * @param [translateX]
466
+ * @param [translateY]
467
+ * @param [rotation] in radians
468
+ * @param [scaleX]
469
+ * @param [scaleY]
470
+ *
434
471
  * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/save
435
472
  */
436
- function push(): void
473
+ function push(
474
+ translateX?: number,
475
+ translateY?: number,
476
+ rotation?: number,
477
+ scaleX?: number,
478
+ scaleY?: number
479
+ ): void
437
480
  /**
438
481
  * restores the drawing style settings and transformations
439
482
  * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/restore
package/types/types.d.ts CHANGED
@@ -5,9 +5,9 @@ type LitecanvasInstance = {
5
5
  H: number
6
6
  /** the amount of time (in seconds) since the game started */
7
7
  T: number
8
- /** The current mouse's horizontal (X) position or -1 (if the mouse was not used or detected) */
8
+ /** The current mouse's horizontal (X) position or `-1` (if the mouse was not used or detected) */
9
9
  MX: number
10
- /** The current mouse's vertical (Y) position or -1 (if the mouse was not used or detected) */
10
+ /** The current mouse's vertical (Y) position or `-1` (if the mouse was not used or detected) */
11
11
  MY: number
12
12
 
13
13
  /** MATH API */
@@ -53,6 +53,19 @@ type LitecanvasInstance = {
53
53
  * @returns the value in degrees
54
54
  */
55
55
  rad2deg(rads: number): number
56
+ /**
57
+ * Modulus (Euclidean division).
58
+ *
59
+ * Note: When `b == 0` returns `0`, rather than `NaN`.
60
+ *
61
+ * @param a dividend
62
+ * @param b divisor
63
+ * @returns the remainder
64
+ * @example
65
+ * mod(-1, 5) // => 4
66
+ * -1 % 5 // => -1
67
+ */
68
+ mod(a: number, b: number): number
56
69
  /**
57
70
  * Returns the rounded value of an number to optional precision (number of digits after the decimal point).
58
71
  *
@@ -376,15 +389,32 @@ type LitecanvasInstance = {
376
389
  */
377
390
  image(x: number, y: number, source: CanvasImageSource): void
378
391
  /**
379
- * Draw a sprite pixel by pixel represented by a string. Each pixel must be a base 36 number or a dot:
380
- *
381
- * - A base 36 number (`0-9` or `a-z`) represent a pixel color (supporting color palettes with max 36 colors).
382
- * - A dot (`.`) represent a transparent pixel.
383
- * - Spaces are ignored and can be used to improve the visualization.
392
+ * Draw a sprite, using a string of rows and columns representing a bitmask.
393
+ * - Each colored pixel must be a base 36 number (0-9 or a-z).
394
+ * - Use "." (dot) for transparent pixels.
395
+ * - Any other characters (like symbols) are ignored.
396
+ * - empty lines are ignored
384
397
  *
385
- * @param x the position X of the first pixel
386
- * @param y the position Y of the first pixel
398
+ * @param x
399
+ * @param y
387
400
  * @param pixels
401
+ * @see https://litecanvas.js.org/tools/pixel-art-editor.html
402
+ * @example
403
+ * function draw() {
404
+ * // a little white key 8x8 sprite
405
+ * const littleKeySprite = `
406
+ * ........
407
+ * .3......
408
+ * 323.....
409
+ * 3.333333
410
+ * 3.322323
411
+ * 232..2.2
412
+ * .2......
413
+ * ........
414
+ * `
415
+ * // draw the sprite pixels at position x=10, y=10
416
+ * spr(10, 10, littleKeySprite)
417
+ * }
388
418
  */
389
419
  spr(x: number, y: number, pixels: string): void
390
420
  /**
@@ -418,10 +448,23 @@ type LitecanvasInstance = {
418
448
  context?: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D
419
449
  ): CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D
420
450
  /**
421
- * saves the current drawing style settings and transformations
451
+ * Saves the current drawing style settings and, optionally, transforms (translate/rotate/scale) the canvas.
452
+ *
453
+ * @param [translateX]
454
+ * @param [translateY]
455
+ * @param [rotation] in radians
456
+ * @param [scaleX]
457
+ * @param [scaleY]
458
+ *
422
459
  * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/save
423
460
  */
424
- push(): void
461
+ push(
462
+ translateX?: number,
463
+ translateY?: number,
464
+ rotation?: number,
465
+ scaleX?: number,
466
+ scaleY?: number
467
+ ): void
425
468
  /**
426
469
  * restores the drawing style settings and transformations
427
470
  * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/restore