litecanvas 0.85.1 → 0.86.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
@@ -203,6 +203,7 @@
203
203
  DEV: assert(isNumber(value), "norm: 1st param must be a number");
204
204
  DEV: assert(isNumber(start), "norm: 2nd param must be a number");
205
205
  DEV: assert(isNumber(stop), "norm: 3rd param must be a number");
206
+ DEV: assert(start !== stop, "norm: the 2nd param must be different than the 3rd param");
206
207
  return instance.map(value, start, stop, 0, 1);
207
208
  },
208
209
  /**
@@ -403,6 +404,62 @@
403
404
  _ctx.arc(~~x, ~~y, ~~radius, 0, TWO_PI);
404
405
  instance.fill(color);
405
406
  },
407
+ /**
408
+ * Draw a ellipse outline
409
+ *
410
+ * @param {number} x
411
+ * @param {number} y
412
+ * @param {number} radiusX
413
+ * @param {number} radiusY
414
+ * @param {number} [color=0] the color index
415
+ */
416
+ oval(x, y, radiusX, radiusY, color) {
417
+ DEV: assert(isNumber(x), "oval: 1st param must be a number");
418
+ DEV: assert(isNumber(y), "oval: 2nd param must be a number");
419
+ DEV: assert(
420
+ isNumber(radiusX) && radiusX >= 0,
421
+ "oval: 3rd param must be a positive number or zero"
422
+ );
423
+ DEV: assert(
424
+ isNumber(radiusY) && radiusY >= 0,
425
+ "oval: 4th param must be a positive number or zero"
426
+ );
427
+ DEV: assert(
428
+ null == color || isNumber(color) && color >= 0,
429
+ "oval: 5th param must be a positive number or zero"
430
+ );
431
+ _ctx.beginPath();
432
+ _ctx.ellipse(~~x, ~~y, ~~radiusX, ~~radiusY, 0, 0, TWO_PI);
433
+ instance.stroke(color);
434
+ },
435
+ /**
436
+ * Draw a color-filled ellipse
437
+ *
438
+ * @param {number} x
439
+ * @param {number} y
440
+ * @param {number} radiusX
441
+ * @param {number} radiusY
442
+ * @param {number} [color=0] the color index
443
+ */
444
+ ovalfill(x, y, radiusX, radiusY, color) {
445
+ DEV: assert(isNumber(x), "ovalfill: 1st param must be a number");
446
+ DEV: assert(isNumber(y), "ovalfill: 2nd param must be a number");
447
+ DEV: assert(
448
+ isNumber(radiusX) && radiusX >= 0,
449
+ "ovalfill: 3rd param must be a positive number or zero"
450
+ );
451
+ DEV: assert(
452
+ isNumber(radiusY) && radiusY >= 0,
453
+ "ovalfill: 4th param must be a positive number or zero"
454
+ );
455
+ DEV: assert(
456
+ null == color || isNumber(color) && color >= 0,
457
+ "ovalfill: 5th param must be a positive number or zero"
458
+ );
459
+ _ctx.beginPath();
460
+ _ctx.ellipse(~~x, ~~y, ~~radiusX, ~~radiusY, 0, 0, TWO_PI);
461
+ instance.fill(color);
462
+ },
406
463
  /**
407
464
  * Draw a line
408
465
  *
@@ -1224,17 +1281,19 @@
1224
1281
  `Litecanvas' option "width" is required when the option "height" is defined`
1225
1282
  );
1226
1283
  const width = settings.width || root.innerWidth, height = settings.height || settings.width || root.innerHeight;
1227
- instance.def("W", _canvas.width = width);
1228
- instance.def("H", _canvas.height = height);
1284
+ instance.def("W", width);
1285
+ instance.def("H", height);
1286
+ _canvas.width = width;
1287
+ _canvas.height = height;
1229
1288
  if (settings.autoscale) {
1230
1289
  if (!_canvas.style.display) {
1231
1290
  _canvas.style.display = "block";
1232
1291
  _canvas.style.margin = "auto";
1233
1292
  }
1234
- _scale = math.min(root.innerWidth / instance.W, root.innerHeight / instance.H);
1293
+ _scale = math.min(root.innerWidth / width, root.innerHeight / height);
1235
1294
  _scale = (settings.pixelart ? ~~_scale : _scale) || 1;
1236
- _canvas.style.width = instance.W * _scale + "px";
1237
- _canvas.style.height = instance.H * _scale + "px";
1295
+ _canvas.style.width = width * _scale + "px";
1296
+ _canvas.style.height = height * _scale + "px";
1238
1297
  }
1239
1298
  if (!settings.antialias || settings.pixelart) {
1240
1299
  _ctx.imageSmoothingEnabled = false;
package/dist/dist.js CHANGED
@@ -297,6 +297,34 @@
297
297
  _ctx.arc(~~x, ~~y, ~~radius, 0, TWO_PI);
298
298
  instance.fill(color);
299
299
  },
300
+ /**
301
+ * Draw a ellipse outline
302
+ *
303
+ * @param {number} x
304
+ * @param {number} y
305
+ * @param {number} radiusX
306
+ * @param {number} radiusY
307
+ * @param {number} [color=0] the color index
308
+ */
309
+ oval(x, y, radiusX, radiusY, color) {
310
+ _ctx.beginPath();
311
+ _ctx.ellipse(~~x, ~~y, ~~radiusX, ~~radiusY, 0, 0, TWO_PI);
312
+ instance.stroke(color);
313
+ },
314
+ /**
315
+ * Draw a color-filled ellipse
316
+ *
317
+ * @param {number} x
318
+ * @param {number} y
319
+ * @param {number} radiusX
320
+ * @param {number} radiusY
321
+ * @param {number} [color=0] the color index
322
+ */
323
+ ovalfill(x, y, radiusX, radiusY, color) {
324
+ _ctx.beginPath();
325
+ _ctx.ellipse(~~x, ~~y, ~~radiusX, ~~radiusY, 0, 0, TWO_PI);
326
+ instance.fill(color);
327
+ },
300
328
  /**
301
329
  * Draw a line
302
330
  *
@@ -982,17 +1010,19 @@
982
1010
  }
983
1011
  function resizeCanvas() {
984
1012
  const width = settings.width || root.innerWidth, height = settings.height || settings.width || root.innerHeight;
985
- instance.def("W", _canvas.width = width);
986
- instance.def("H", _canvas.height = height);
1013
+ instance.def("W", width);
1014
+ instance.def("H", height);
1015
+ _canvas.width = width;
1016
+ _canvas.height = height;
987
1017
  if (settings.autoscale) {
988
1018
  if (!_canvas.style.display) {
989
1019
  _canvas.style.display = "block";
990
1020
  _canvas.style.margin = "auto";
991
1021
  }
992
- _scale = math.min(root.innerWidth / instance.W, root.innerHeight / instance.H);
1022
+ _scale = math.min(root.innerWidth / width, root.innerHeight / height);
993
1023
  _scale = (settings.pixelart ? ~~_scale : _scale) || 1;
994
- _canvas.style.width = instance.W * _scale + "px";
995
- _canvas.style.height = instance.H * _scale + "px";
1024
+ _canvas.style.width = width * _scale + "px";
1025
+ _canvas.style.height = height * _scale + "px";
996
1026
  }
997
1027
  if (!settings.antialias || settings.pixelart) {
998
1028
  _ctx.imageSmoothingEnabled = false;
package/dist/dist.min.js CHANGED
@@ -1 +1 @@
1
- (()=>{var e=["#111","#6a7799","#aec2c2","#FFF1E8","#e83b3b","#fabc20","#155fd9","#3cbcfc","#327345","#63c64d","#6c2c1f","#ac7c00"];globalThis.litecanvas=function(t={}){let a=window,n=Math,i=2*n.PI,l=requestAnimationFrame,r=[],o=(e,t,a)=>{e.addEventListener(t,a,!1),r.push(()=>e.removeEventListener(t,a,!1))},s=(e=>{let t=new AudioContext;return e.zzfxV=1,(a=1,n=.05,i=220,l=0,r=0,o=.1,s=0,f=1,c=0,d=0,p=0,u=0,h=0,g=0,m=0,w=0,v=0,x=1,b=0,y=0,k=0)=>{let E=Math,z=2*E.PI,T=c*=500*z/44100/44100,C=i*=(1-n+2*n*E.random(n=[]))*z/44100,I=0,P=0,A=0,L=1,S=0,X=0,Y=0,M=k<0?-1:1,D=z*M*k*2/44100,H=E.cos(D),N=E.sin,W=N(D)/4,F=1+W,q=-2*H/F,B=(1-W)/F,O=(1+M*H)/2/F,V=-(M+H)/F,R=0,G=0,$=0,j=0;for(l=44100*l+9,b*=44100,r*=44100,o*=44100,v*=44100,d*=500*z/85766121e6,m*=z/44100,p*=z/44100,u*=44100,h=44100*h|0,a*=.3*e.zzfxV,M=l+b+r+o+v|0;A<M;n[A++]=Y*a)++X%(100*w|0)||(Y=s?1<s?2<s?3<s?N(I*I):E.max(E.min(E.tan(I),1),-1):1-(2*I/z%2+2)%2:1-4*E.abs(E.round(I/z)-I/z):N(I),Y=(h?1-y+y*N(z*A/h):1)*(Y<0?-1:1)*E.abs(Y)**f*(A<l?A/l:A<l+b?1-(A-l)/b*(1-x):A<l+b+r?x:A<M-v?(M-A-v)/o*x:0),Y=v?Y/2+(v>A?0:(A<M-v?1:(M-A)/v)*n[A-v|0]/2/a):Y,k&&(Y=j=O*R+V*(R=G)+O*(G=Y)-B*$-q*($=j))),I+=(D=(i+=c+=d)*E.cos(m*P++))+D*g*N(A**5),L&&++L>u&&(i+=p,C+=p,L=0),!h||++S%h||(i=C,c=T,L=L||1);(a=t.createBuffer(1,M,44100)).getChannelData(0).set(n),(i=t.createBufferSource()).buffer=a,i.connect(t.destination),i.start()}})(a);t=Object.assign({width:null,height:null,autoscale:!0,pixelart:!1,antialias:!1,canvas:null,global:!0,loop:null,tapEvents:!0,keyboardEvents:!0,animate:!0},t);let f=!1,c=[],d,p=1,u,h=.5,g=1,m,w=1/60,v=0,x,b="sans-serif",y=20,k=Date.now(),E=e,z=[.5,0,1750,,,.3,1,,,,600,.1],T={},C={W:0,H:0,T:0,MX:-1,MY:-1,TWO_PI:i,HALF_PI:i/4,lerp:(e,t,a)=>a*(t-e)+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,wrap:(e,t,a)=>e-(a-t)*n.floor((e-t)/(a-t)),map(e,t,a,n,i,l){let r=(e-t)/(a-t)*(i-n)+n;return l?C.clamp(r,n,i):r},norm:(e,t,a)=>C.map(e,t,a,0,1),wave:(e,t,a,n=Math.sin)=>e+(n(a)+1)/2*(t-e),rand:(e=0,t=1)=>(k=(1664525*k+0x3c6ef35f)%0x100000000)/0x100000000*(t-e)+e,randi:(e=0,t=1)=>n.floor(C.rand(e,t+1)),rseed(e){k=~~e},cls(e){null==e?u.clearRect(0,0,u.canvas.width,u.canvas.height):C.rectfill(0,0,u.canvas.width,u.canvas.height,e)},rect(e,t,a,n,i,l){u.beginPath(),u[l?"roundRect":"rect"](~~e-h,~~t-h,~~a+2*h,~~n+2*h,l),C.stroke(i)},rectfill(e,t,a,n,i,l){u.beginPath(),u[l?"roundRect":"rect"](~~e,~~t,~~a,~~n,l),C.fill(i)},circ(e,t,a,n){u.beginPath(),u.arc(~~e,~~t,~~a,0,i),C.stroke(n)},circfill(e,t,a,n){u.beginPath(),u.arc(~~e,~~t,~~a,0,i),C.fill(n)},line(e,t,a,n,i){u.beginPath();let l=.5*(0!==h&&~~e==~~a),r=.5*(0!==h&&~~t==~~n);u.moveTo(~~e+l,~~t+r),u.lineTo(~~a+l,~~n+r),C.stroke(i)},linewidth(e){u.lineWidth=~~e,h=.5*(0!=~~e%2)},linedash(e,t=0){u.setLineDash(e),u.lineDashOffset=t},text(e,t,a,n=3,i="normal"){u.font=`${i} ${y}px ${b}`,u.fillStyle=E[~~n%E.length],u.fillText(a,~~e,~~t)},textfont(e){b=e},textsize(e){y=e},textalign(e,t){e&&(u.textAlign=e),t&&(u.textBaseline=t)},image(e,t,a){u.drawImage(a,~~e,~~t)},paint(e,t,a,n={}){let i=n.canvas||new OffscreenCanvas(1,1),l=n.scale||1,r=u;if(i.width=e*l,i.height=t*l,(u=i.getContext("2d")).scale(l,l),Array.isArray(a)){let e=0,t=0;for(let n of(u.imageSmoothingEnabled=!1,a)){for(let a of n)" "!==a&&"."!==a&&C.rectfill(e,t,1,1,parseInt(a,16)),e++;t++,e=0}}else a(u);return u=r,i.transferToImageBitmap()},ctx:e=>(e&&(u=e),u),push:()=>u.save(),pop:()=>u.restore(),translate:(e,t)=>u.translate(~~e,~~t),scale:(e,t)=>u.scale(e,t||e),rotate:e=>u.rotate(e),alpha(e){u.globalAlpha=C.clamp(e,0,1)},path:e=>new Path2D(e),fill(e,t){u.fillStyle=E[~~e%E.length],t?u.fill(t):u.fill()},stroke(e,t){u.strokeStyle=E[~~e%E.length],t?u.stroke(t):u.stroke()},clip(e){u.clip(e)},sfx:(e,t=0,n=1)=>!(a.zzfxV<=0)&&(!navigator.userActivation||!!navigator.userActivation.hasBeenActive)&&(e=e||z,(0!==t||1!==n)&&((e=e.slice())[0]=n*(e[0]||1),e[10]=~~e[10]+t),s.apply(0,e),e),volume(e){a.zzfxV=e},canvas:()=>d,use(e,t={}){f?S(e,t):c.push([e,t])},listen:(e,t)=>(T[e=e.toLowerCase()]=T[e]||new Set,T[e].add(t),()=>T&&T[e].delete(t)),emit(e,t,a,n,i){f&&(L("before:"+(e=e.toLowerCase()),t,a,n,i),L(e,t,a,n,i),L("after:"+e,t,a,n,i))},pal(t=e){E=t},def(e,n){C[e]=n,t.global&&(a[e]=n)},timescale(e){g=e},framerate(e){w=1/~~e},stat(e){let n={index:e,value:[t,f,x,p,T,E,z,g,a.zzfxV||1,k,y,b][e]};return C.emit("stat",n),n.value},quit(){for(let e of(cancelAnimationFrame(x),x=0,C.emit("quit"),T={},r))e();if(t.global){for(let e in C)delete a[e];delete a.ENGINE}f=!1}};for(let e of"PI,sin,cos,atan2,hypot,tan,abs,ceil,floor,trunc,min,max,pow,sqrt,sign,exp".split(","))C[e]=n[e];function I(){let e=t.loop?t.loop:a;for(let t of"init,update,draw,tap,untap,tapping,tapped,resized".split(","))e[t]&&C.listen(t,e[t]);for(let[e,t]of c)S(e,t);if(t.autoscale&&o(a,"resize",A),t.tapEvents){let e=(e,t)=>[(e-d.offsetLeft)/p,(t-d.offsetTop)/p],t=new Map,n=(e,a,n)=>{let i={x:a,y:n,startX:a,startY:n,ts:performance.now()};return t.set(e,i),i},i=(e,a,i)=>{let l=t.get(e)||n(e);l.x=a,l.y=i},l=e=>e&&performance.now()-e.ts<=300,r=e=>e.preventDefault(),s=!1;o(d,"mousedown",t=>{if(0===t.button){r(t);let[a,i]=e(t.pageX,t.pageY);C.emit("tap",a,i,0),n(0,a,i),s=!0}}),o(d,"mouseup",a=>{if(0===a.button){r(a);let n=t.get(0),[i,o]=e(a.pageX,a.pageY);l(n)&&C.emit("tapped",n.startX,n.startY,0),C.emit("untap",i,o,0),t.delete(0),s=!1}}),o(d,"mousemove",t=>{r(t);let[a,n]=e(t.pageX,t.pageY);C.def("MX",a),C.def("MY",n),s&&(C.emit("tapping",a,n,0),i(0,a,n))}),o(d,"touchstart",t=>{for(let a of(r(t),t.changedTouches)){let[t,i]=e(a.pageX,a.pageY);C.emit("tap",t,i,a.identifier+1),n(a.identifier+1,t,i)}}),o(d,"touchmove",t=>{for(let a of(r(t),t.changedTouches)){let[t,n]=e(a.pageX,a.pageY);C.emit("tapping",t,n,a.identifier+1),i(a.identifier+1,t,n)}});let f=e=>{r(e);let a=[];if(e.targetTouches.length>0)for(let t of e.targetTouches)a.push(t.identifier+1);for(let[e,n]of t)a.includes(e)||(l(n)&&C.emit("tapped",n.startX,n.startY,e),C.emit("untap",n.x,n.y,e),t.delete(e))};o(d,"touchend",f),o(d,"touchcancel",f),o(a,"blur",()=>{for(let[e,a]of(s=!1,t))C.emit("untap",a.x,a.y,e),t.delete(e)})}if(t.keyboardEvents){let e=new Set,t=new Set,n=(e,t="")=>(t=t.toLowerCase())?e.has("space"===t?" ":t):e.size>0;o(a,"keydown",a=>{let n=a.key.toLowerCase();e.has(n)||(e.add(n),t.add(n))}),o(a,"keyup",t=>{e.delete(t.key.toLowerCase())}),o(a,"blur",()=>e.clear()),C.listen("after:update",()=>t.clear()),C.def("iskeydown",t=>n(e,t)),C.def("iskeypressed",e=>n(t,e))}f=!0,C.emit("init",C),m=performance.now(),x=l(P)}function P(e){let a=0;if(t.animate){for(v+=n.min(.1,(e-m)/1e3),m=e;v>=w;)a++,C.emit("update",w*g,a),C.def("T",C.T+w*g),v-=w;x&&(x=l(P))}else a=1;a&&(C.textalign("start","top"),C.emit("draw"))}function A(){let e=t.width||a.innerWidth,i=t.height||t.width||a.innerHeight;C.def("W",d.width=e),C.def("H",d.height=i),t.autoscale&&(d.style.display||(d.style.display="block",d.style.margin="auto"),p=n.min(a.innerWidth/C.W,a.innerHeight/C.H),p=(t.pixelart?~~p:p)||1,d.style.width=C.W*p+"px",d.style.height=C.H*p+"px"),(!t.antialias||t.pixelart)&&(u.imageSmoothingEnabled=!1,d.style.imageRendering="pixelated"),C.emit("resized",p),C.cls(0),t.animate||l(P)}function L(e,t,a,n,i){if(T[e])for(let l of T[e])l(t,a,n,i)}function S(e,t){let a=e(C,t);for(let e in a)C.def(e,a[e])}if(t.global){if(a.ENGINE)throw Error("two global litecanvas detected");Object.assign(a,C),a.ENGINE=C}return u=(d=(d="string"==typeof t.canvas?document.querySelector(t.canvas):t.canvas)||document.createElement("canvas")).getContext("2d"),o(d,"click",()=>a.focus()),d.style="",A(),d.parentNode||document.body.appendChild(d),"loading"===document.readyState?o(a,"DOMContentLoaded",()=>l(I)):l(I),C}})();
1
+ (()=>{var e=["#111","#6a7799","#aec2c2","#FFF1E8","#e83b3b","#fabc20","#155fd9","#3cbcfc","#327345","#63c64d","#6c2c1f","#ac7c00"];globalThis.litecanvas=function(t={}){let a=window,i=Math,n=2*i.PI,l=requestAnimationFrame,r=[],o=(e,t,a)=>{e.addEventListener(t,a,!1),r.push(()=>e.removeEventListener(t,a,!1))},s=(e=>{let t=new AudioContext;return e.zzfxV=1,(a=1,i=.05,n=220,l=0,r=0,o=.1,s=0,f=1,c=0,d=0,p=0,u=0,h=0,g=0,m=0,v=0,w=0,b=1,x=0,y=0,k=0)=>{let E=Math,z=2*E.PI,P=c*=500*z/44100/44100,T=n*=(1-i+2*i*E.random(i=[]))*z/44100,C=0,I=0,A=0,L=1,S=0,X=0,Y=0,M=k<0?-1:1,D=z*M*k*2/44100,N=E.cos(D),F=E.sin,q=F(D)/4,B=1+q,H=-2*N/B,O=(1-q)/B,V=(1+M*N)/2/B,W=-(M+N)/B,R=0,G=0,$=0,j=0;for(l=44100*l+9,x*=44100,r*=44100,o*=44100,w*=44100,d*=500*z/85766121e6,m*=z/44100,p*=z/44100,u*=44100,h=44100*h|0,a*=.3*e.zzfxV,M=l+x+r+o+w|0;A<M;i[A++]=Y*a)++X%(100*v|0)||(Y=s?1<s?2<s?3<s?F(C*C):E.max(E.min(E.tan(C),1),-1):1-(2*C/z%2+2)%2:1-4*E.abs(E.round(C/z)-C/z):F(C),Y=(h?1-y+y*F(z*A/h):1)*(Y<0?-1:1)*E.abs(Y)**f*(A<l?A/l:A<l+x?1-(A-l)/x*(1-b):A<l+x+r?b:A<M-w?(M-A-w)/o*b:0),Y=w?Y/2+(w>A?0:(A<M-w?1:(M-A)/w)*i[A-w|0]/2/a):Y,k&&(Y=j=V*R+W*(R=G)+V*(G=Y)-O*$-H*($=j))),C+=(D=(n+=c+=d)*E.cos(m*I++))+D*g*F(A**5),L&&++L>u&&(n+=p,T+=p,L=0),!h||++S%h||(n=T,c=P,L=L||1);(a=t.createBuffer(1,M,44100)).getChannelData(0).set(i),(n=t.createBufferSource()).buffer=a,n.connect(t.destination),n.start()}})(a);t=Object.assign({width:null,height:null,autoscale:!0,pixelart:!1,antialias:!1,canvas:null,global:!0,loop:null,tapEvents:!0,keyboardEvents:!0,animate:!0},t);let f=!1,c=[],d,p=1,u,h=.5,g=1,m,v=1/60,w=0,b,x="sans-serif",y=20,k=Date.now(),E=e,z=[.5,0,1750,,,.3,1,,,,600,.1],P={},T={W:0,H:0,T:0,MX:-1,MY:-1,TWO_PI:n,HALF_PI:n/4,lerp:(e,t,a)=>a*(t-e)+e,deg2rad:e=>i.PI/180*e,rad2deg:e=>180/i.PI*e,round:(e,t=0)=>{if(!t)return i.round(e);let a=10**t;return i.round(e*a)/a},clamp:(e,t,a)=>e<t?t:e>a?a:e,wrap:(e,t,a)=>e-(a-t)*i.floor((e-t)/(a-t)),map(e,t,a,i,n,l){let r=(e-t)/(a-t)*(n-i)+i;return l?T.clamp(r,i,n):r},norm:(e,t,a)=>T.map(e,t,a,0,1),wave:(e,t,a,i=Math.sin)=>e+(i(a)+1)/2*(t-e),rand:(e=0,t=1)=>(k=(1664525*k+0x3c6ef35f)%0x100000000)/0x100000000*(t-e)+e,randi:(e=0,t=1)=>i.floor(T.rand(e,t+1)),rseed(e){k=~~e},cls(e){null==e?u.clearRect(0,0,u.canvas.width,u.canvas.height):T.rectfill(0,0,u.canvas.width,u.canvas.height,e)},rect(e,t,a,i,n,l){u.beginPath(),u[l?"roundRect":"rect"](~~e-h,~~t-h,~~a+2*h,~~i+2*h,l),T.stroke(n)},rectfill(e,t,a,i,n,l){u.beginPath(),u[l?"roundRect":"rect"](~~e,~~t,~~a,~~i,l),T.fill(n)},circ(e,t,a,i){u.beginPath(),u.arc(~~e,~~t,~~a,0,n),T.stroke(i)},circfill(e,t,a,i){u.beginPath(),u.arc(~~e,~~t,~~a,0,n),T.fill(i)},oval(e,t,a,i,l){u.beginPath(),u.ellipse(~~e,~~t,~~a,~~i,0,0,n),T.stroke(l)},ovalfill(e,t,a,i,l){u.beginPath(),u.ellipse(~~e,~~t,~~a,~~i,0,0,n),T.fill(l)},line(e,t,a,i,n){u.beginPath();let l=.5*(0!==h&&~~e==~~a),r=.5*(0!==h&&~~t==~~i);u.moveTo(~~e+l,~~t+r),u.lineTo(~~a+l,~~i+r),T.stroke(n)},linewidth(e){u.lineWidth=~~e,h=.5*(0!=~~e%2)},linedash(e,t=0){u.setLineDash(e),u.lineDashOffset=t},text(e,t,a,i=3,n="normal"){u.font=`${n} ${y}px ${x}`,u.fillStyle=E[~~i%E.length],u.fillText(a,~~e,~~t)},textfont(e){x=e},textsize(e){y=e},textalign(e,t){e&&(u.textAlign=e),t&&(u.textBaseline=t)},image(e,t,a){u.drawImage(a,~~e,~~t)},paint(e,t,a,i={}){let n=i.canvas||new OffscreenCanvas(1,1),l=i.scale||1,r=u;if(n.width=e*l,n.height=t*l,(u=n.getContext("2d")).scale(l,l),Array.isArray(a)){let e=0,t=0;for(let i of(u.imageSmoothingEnabled=!1,a)){for(let a of i)" "!==a&&"."!==a&&T.rectfill(e,t,1,1,parseInt(a,16)),e++;t++,e=0}}else a(u);return u=r,n.transferToImageBitmap()},ctx:e=>(e&&(u=e),u),push:()=>u.save(),pop:()=>u.restore(),translate:(e,t)=>u.translate(~~e,~~t),scale:(e,t)=>u.scale(e,t||e),rotate:e=>u.rotate(e),alpha(e){u.globalAlpha=T.clamp(e,0,1)},path:e=>new Path2D(e),fill(e,t){u.fillStyle=E[~~e%E.length],t?u.fill(t):u.fill()},stroke(e,t){u.strokeStyle=E[~~e%E.length],t?u.stroke(t):u.stroke()},clip(e){u.clip(e)},sfx:(e,t=0,i=1)=>!(a.zzfxV<=0)&&(!navigator.userActivation||!!navigator.userActivation.hasBeenActive)&&(e=e||z,(0!==t||1!==i)&&((e=e.slice())[0]=i*(e[0]||1),e[10]=~~e[10]+t),s.apply(0,e),e),volume(e){a.zzfxV=e},canvas:()=>d,use(e,t={}){f?S(e,t):c.push([e,t])},listen:(e,t)=>(P[e=e.toLowerCase()]=P[e]||new Set,P[e].add(t),()=>P&&P[e].delete(t)),emit(e,t,a,i,n){f&&(L("before:"+(e=e.toLowerCase()),t,a,i,n),L(e,t,a,i,n),L("after:"+e,t,a,i,n))},pal(t=e){E=t},def(e,i){T[e]=i,t.global&&(a[e]=i)},timescale(e){g=e},framerate(e){v=1/~~e},stat(e){let i={index:e,value:[t,f,b,p,P,E,z,g,a.zzfxV||1,k,y,x][e]};return T.emit("stat",i),i.value},quit(){for(let e of(cancelAnimationFrame(b),b=0,T.emit("quit"),P={},r))e();if(t.global){for(let e in T)delete a[e];delete a.ENGINE}f=!1}};for(let e of"PI,sin,cos,atan2,hypot,tan,abs,ceil,floor,trunc,min,max,pow,sqrt,sign,exp".split(","))T[e]=i[e];function C(){let e=t.loop?t.loop:a;for(let t of"init,update,draw,tap,untap,tapping,tapped,resized".split(","))e[t]&&T.listen(t,e[t]);for(let[e,t]of c)S(e,t);if(t.autoscale&&o(a,"resize",A),t.tapEvents){let e=(e,t)=>[(e-d.offsetLeft)/p,(t-d.offsetTop)/p],t=new Map,i=(e,a,i)=>{let n={x:a,y:i,startX:a,startY:i,ts:performance.now()};return t.set(e,n),n},n=(e,a,n)=>{let l=t.get(e)||i(e);l.x=a,l.y=n},l=e=>e&&performance.now()-e.ts<=300,r=e=>e.preventDefault(),s=!1;o(d,"mousedown",t=>{if(0===t.button){r(t);let[a,n]=e(t.pageX,t.pageY);T.emit("tap",a,n,0),i(0,a,n),s=!0}}),o(d,"mouseup",a=>{if(0===a.button){r(a);let i=t.get(0),[n,o]=e(a.pageX,a.pageY);l(i)&&T.emit("tapped",i.startX,i.startY,0),T.emit("untap",n,o,0),t.delete(0),s=!1}}),o(d,"mousemove",t=>{r(t);let[a,i]=e(t.pageX,t.pageY);T.def("MX",a),T.def("MY",i),s&&(T.emit("tapping",a,i,0),n(0,a,i))}),o(d,"touchstart",t=>{for(let a of(r(t),t.changedTouches)){let[t,n]=e(a.pageX,a.pageY);T.emit("tap",t,n,a.identifier+1),i(a.identifier+1,t,n)}}),o(d,"touchmove",t=>{for(let a of(r(t),t.changedTouches)){let[t,i]=e(a.pageX,a.pageY);T.emit("tapping",t,i,a.identifier+1),n(a.identifier+1,t,i)}});let f=e=>{r(e);let a=[];if(e.targetTouches.length>0)for(let t of e.targetTouches)a.push(t.identifier+1);for(let[e,i]of t)a.includes(e)||(l(i)&&T.emit("tapped",i.startX,i.startY,e),T.emit("untap",i.x,i.y,e),t.delete(e))};o(d,"touchend",f),o(d,"touchcancel",f),o(a,"blur",()=>{for(let[e,a]of(s=!1,t))T.emit("untap",a.x,a.y,e),t.delete(e)})}if(t.keyboardEvents){let e=new Set,t=new Set,i=(e,t="")=>(t=t.toLowerCase())?e.has("space"===t?" ":t):e.size>0;o(a,"keydown",a=>{let i=a.key.toLowerCase();e.has(i)||(e.add(i),t.add(i))}),o(a,"keyup",t=>{e.delete(t.key.toLowerCase())}),o(a,"blur",()=>e.clear()),T.listen("after:update",()=>t.clear()),T.def("iskeydown",t=>i(e,t)),T.def("iskeypressed",e=>i(t,e))}f=!0,T.emit("init",T),m=performance.now(),b=l(I)}function I(e){let a=0;if(t.animate){for(w+=i.min(.1,(e-m)/1e3),m=e;w>=v;)a++,T.emit("update",v*g,a),T.def("T",T.T+v*g),w-=v;b&&(b=l(I))}else a=1;a&&(T.textalign("start","top"),T.emit("draw"))}function A(){let e=t.width||a.innerWidth,n=t.height||t.width||a.innerHeight;T.def("W",e),T.def("H",n),d.width=e,d.height=n,t.autoscale&&(d.style.display||(d.style.display="block",d.style.margin="auto"),p=i.min(a.innerWidth/e,a.innerHeight/n),p=(t.pixelart?~~p:p)||1,d.style.width=e*p+"px",d.style.height=n*p+"px"),(!t.antialias||t.pixelart)&&(u.imageSmoothingEnabled=!1,d.style.imageRendering="pixelated"),T.emit("resized",p),T.cls(0),t.animate||l(I)}function L(e,t,a,i,n){if(P[e])for(let l of P[e])l(t,a,i,n)}function S(e,t){let a=e(T,t);for(let e in a)T.def(e,a[e])}if(t.global){if(a.ENGINE)throw Error("two global litecanvas detected");Object.assign(a,T),a.ENGINE=T}return u=(d=(d="string"==typeof t.canvas?document.querySelector(t.canvas):t.canvas)||document.createElement("canvas")).getContext("2d"),o(d,"click",()=>a.focus()),d.style="",A(),d.parentNode||document.body.appendChild(d),"loading"===document.readyState?o(a,"DOMContentLoaded",()=>l(C)):l(C),T}})();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "litecanvas",
3
- "version": "0.85.1",
3
+ "version": "0.86.0",
4
4
  "description": "Lightweight HTML5 canvas 2D game engine suitable for small projects and creative coding. Inspired by PICO-8 and P5/Processing.",
5
5
  "license": "MIT",
6
6
  "author": "Luiz Bills <luizbills@pm.me>",
package/src/index.js CHANGED
@@ -258,6 +258,7 @@ export default function litecanvas(settings = {}) {
258
258
  DEV: assert(isNumber(value), 'norm: 1st param must be a number')
259
259
  DEV: assert(isNumber(start), 'norm: 2nd param must be a number')
260
260
  DEV: assert(isNumber(stop), 'norm: 3rd param must be a number')
261
+ DEV: assert(start !== stop, 'norm: the 2nd param must be different than the 3rd param')
261
262
 
262
263
  return instance.map(value, start, stop, 0, 1)
263
264
  },
@@ -479,6 +480,66 @@ export default function litecanvas(settings = {}) {
479
480
  instance.fill(color)
480
481
  },
481
482
 
483
+ /**
484
+ * Draw a ellipse outline
485
+ *
486
+ * @param {number} x
487
+ * @param {number} y
488
+ * @param {number} radiusX
489
+ * @param {number} radiusY
490
+ * @param {number} [color=0] the color index
491
+ */
492
+ oval(x, y, radiusX, radiusY, color) {
493
+ DEV: assert(isNumber(x), 'oval: 1st param must be a number')
494
+ DEV: assert(isNumber(y), 'oval: 2nd param must be a number')
495
+ DEV: assert(
496
+ isNumber(radiusX) && radiusX >= 0,
497
+ 'oval: 3rd param must be a positive number or zero'
498
+ )
499
+ DEV: assert(
500
+ isNumber(radiusY) && radiusY >= 0,
501
+ 'oval: 4th param must be a positive number or zero'
502
+ )
503
+ DEV: assert(
504
+ null == color || (isNumber(color) && color >= 0),
505
+ 'oval: 5th param must be a positive number or zero'
506
+ )
507
+
508
+ _ctx.beginPath()
509
+ _ctx.ellipse(~~x, ~~y, ~~radiusX, ~~radiusY, 0, 0, TWO_PI)
510
+ instance.stroke(color)
511
+ },
512
+
513
+ /**
514
+ * Draw a color-filled ellipse
515
+ *
516
+ * @param {number} x
517
+ * @param {number} y
518
+ * @param {number} radiusX
519
+ * @param {number} radiusY
520
+ * @param {number} [color=0] the color index
521
+ */
522
+ ovalfill(x, y, radiusX, radiusY, color) {
523
+ DEV: assert(isNumber(x), 'ovalfill: 1st param must be a number')
524
+ DEV: assert(isNumber(y), 'ovalfill: 2nd param must be a number')
525
+ DEV: assert(
526
+ isNumber(radiusX) && radiusX >= 0,
527
+ 'ovalfill: 3rd param must be a positive number or zero'
528
+ )
529
+ DEV: assert(
530
+ isNumber(radiusY) && radiusY >= 0,
531
+ 'ovalfill: 4th param must be a positive number or zero'
532
+ )
533
+ DEV: assert(
534
+ null == color || (isNumber(color) && color >= 0),
535
+ 'ovalfill: 5th param must be a positive number or zero'
536
+ )
537
+
538
+ _ctx.beginPath()
539
+ _ctx.ellipse(~~x, ~~y, ~~radiusX, ~~radiusY, 0, 0, TWO_PI)
540
+ instance.fill(color)
541
+ },
542
+
482
543
  /**
483
544
  * Draw a line
484
545
  *
@@ -1480,8 +1541,11 @@ export default function litecanvas(settings = {}) {
1480
1541
  const width = settings.width || root.innerWidth,
1481
1542
  height = settings.height || settings.width || root.innerHeight
1482
1543
 
1483
- instance.def('W', (_canvas.width = width))
1484
- instance.def('H', (_canvas.height = height))
1544
+ instance.def('W', width)
1545
+ instance.def('H', height)
1546
+
1547
+ _canvas.width = width
1548
+ _canvas.height = height
1485
1549
 
1486
1550
  if (settings.autoscale) {
1487
1551
  if (!_canvas.style.display) {
@@ -1489,11 +1553,11 @@ export default function litecanvas(settings = {}) {
1489
1553
  _canvas.style.margin = 'auto'
1490
1554
  }
1491
1555
 
1492
- _scale = math.min(root.innerWidth / instance.W, root.innerHeight / instance.H)
1556
+ _scale = math.min(root.innerWidth / width, root.innerHeight / height)
1493
1557
  _scale = (settings.pixelart ? ~~_scale : _scale) || 1
1494
1558
 
1495
- _canvas.style.width = instance.W * _scale + 'px'
1496
- _canvas.style.height = instance.H * _scale + 'px'
1559
+ _canvas.style.width = width * _scale + 'px'
1560
+ _canvas.style.height = height * _scale + 'px'
1497
1561
  }
1498
1562
 
1499
1563
  // restore canvas image rendering properties
package/types/index.d.ts CHANGED
@@ -283,6 +283,26 @@ declare global {
283
283
  * @param [color=0] the color index
284
284
  */
285
285
  function circfill(x: number, y: number, radius: number, color?: number): void
286
+ /**
287
+ * Draw a ellipse outline
288
+ *
289
+ * @param x
290
+ * @param y
291
+ * @param radiusX
292
+ * @param radiusY
293
+ * @param [color=0] the color index
294
+ */
295
+ function oval(x: number, y: number, radiusX: number, radiusY: number, color?: number): void
296
+ /**
297
+ * Draw a color-filled ellipse
298
+ *
299
+ * @param x
300
+ * @param y
301
+ * @param radiusX
302
+ * @param radiusY
303
+ * @param [color=0] the color index
304
+ */
305
+ function ovalfill(x: number, y: number, radiusX: number, radiusY: number, color?: number): void
286
306
  /**
287
307
  * Draw a line
288
308
  *
package/types/types.d.ts CHANGED
@@ -274,6 +274,26 @@ type LitecanvasInstance = {
274
274
  * @param [color=0] the color index
275
275
  */
276
276
  circfill(x: number, y: number, radius: number, color?: number): void
277
+ /**
278
+ * Draw a ellipse outline
279
+ *
280
+ * @param x
281
+ * @param y
282
+ * @param radiusX
283
+ * @param radiusY
284
+ * @param [color=0] the color index
285
+ */
286
+ oval(x: number, y: number, radiusX: number, radiusY: number, color?: number): void
287
+ /**
288
+ * Draw a color-filled ellipse
289
+ *
290
+ * @param x
291
+ * @param y
292
+ * @param radiusX
293
+ * @param radiusY
294
+ * @param [color=0] the color index
295
+ */
296
+ ovalfill(x: number, y: number, radiusX: number, radiusY: number, color?: number): void
277
297
  /**
278
298
  * Draw a line
279
299
  *