diff --git a/context.js b/context.js index 29e41d0..004c1d1 100644 --- a/context.js +++ b/context.js @@ -92,30 +92,30 @@ export default (function () { // entity mapping courtesy of tinymce namedEntities = createNamedToNumberedLookup( "50,nbsp,51,iexcl,52,cent,53,pound,54,curren,55,yen,56,brvbar,57,sect,58,uml,59,copy," + - "5a,ordf,5b,laquo,5c,not,5d,shy,5e,reg,5f,macr,5g,deg,5h,plusmn,5i,sup2,5j,sup3,5k,acute," + - "5l,micro,5m,para,5n,middot,5o,cedil,5p,sup1,5q,ordm,5r,raquo,5s,frac14,5t,frac12,5u,frac34," + - "5v,iquest,60,Agrave,61,Aacute,62,Acirc,63,Atilde,64,Auml,65,Aring,66,AElig,67,Ccedil," + - "68,Egrave,69,Eacute,6a,Ecirc,6b,Euml,6c,Igrave,6d,Iacute,6e,Icirc,6f,Iuml,6g,ETH,6h,Ntilde," + - "6i,Ograve,6j,Oacute,6k,Ocirc,6l,Otilde,6m,Ouml,6n,times,6o,Oslash,6p,Ugrave,6q,Uacute," + - "6r,Ucirc,6s,Uuml,6t,Yacute,6u,THORN,6v,szlig,70,agrave,71,aacute,72,acirc,73,atilde,74,auml," + - "75,aring,76,aelig,77,ccedil,78,egrave,79,eacute,7a,ecirc,7b,euml,7c,igrave,7d,iacute,7e,icirc," + - "7f,iuml,7g,eth,7h,ntilde,7i,ograve,7j,oacute,7k,ocirc,7l,otilde,7m,ouml,7n,divide,7o,oslash," + - "7p,ugrave,7q,uacute,7r,ucirc,7s,uuml,7t,yacute,7u,thorn,7v,yuml,ci,fnof,sh,Alpha,si,Beta," + - "sj,Gamma,sk,Delta,sl,Epsilon,sm,Zeta,sn,Eta,so,Theta,sp,Iota,sq,Kappa,sr,Lambda,ss,Mu," + - "st,Nu,su,Xi,sv,Omicron,t0,Pi,t1,Rho,t3,Sigma,t4,Tau,t5,Upsilon,t6,Phi,t7,Chi,t8,Psi," + - "t9,Omega,th,alpha,ti,beta,tj,gamma,tk,delta,tl,epsilon,tm,zeta,tn,eta,to,theta,tp,iota," + - "tq,kappa,tr,lambda,ts,mu,tt,nu,tu,xi,tv,omicron,u0,pi,u1,rho,u2,sigmaf,u3,sigma,u4,tau," + - "u5,upsilon,u6,phi,u7,chi,u8,psi,u9,omega,uh,thetasym,ui,upsih,um,piv,812,bull,816,hellip," + - "81i,prime,81j,Prime,81u,oline,824,frasl,88o,weierp,88h,image,88s,real,892,trade,89l,alefsym," + - "8cg,larr,8ch,uarr,8ci,rarr,8cj,darr,8ck,harr,8dl,crarr,8eg,lArr,8eh,uArr,8ei,rArr,8ej,dArr," + - "8ek,hArr,8g0,forall,8g2,part,8g3,exist,8g5,empty,8g7,nabla,8g8,isin,8g9,notin,8gb,ni,8gf,prod," + - "8gh,sum,8gi,minus,8gn,lowast,8gq,radic,8gt,prop,8gu,infin,8h0,ang,8h7,and,8h8,or,8h9,cap,8ha,cup," + - "8hb,int,8hk,there4,8hs,sim,8i5,cong,8i8,asymp,8j0,ne,8j1,equiv,8j4,le,8j5,ge,8k2,sub,8k3,sup,8k4," + - "nsub,8k6,sube,8k7,supe,8kl,oplus,8kn,otimes,8l5,perp,8m5,sdot,8o8,lceil,8o9,rceil,8oa,lfloor,8ob," + - "rfloor,8p9,lang,8pa,rang,9ea,loz,9j0,spades,9j3,clubs,9j5,hearts,9j6,diams,ai,OElig,aj,oelig,b0," + - "Scaron,b1,scaron,bo,Yuml,m6,circ,ms,tilde,802,ensp,803,emsp,809,thinsp,80c,zwnj,80d,zwj,80e,lrm," + - "80f,rlm,80j,ndash,80k,mdash,80o,lsquo,80p,rsquo,80q,sbquo,80s,ldquo,80t,rdquo,80u,bdquo,810,dagger," + - "811,Dagger,81g,permil,81p,lsaquo,81q,rsaquo,85c,euro", + "5a,ordf,5b,laquo,5c,not,5d,shy,5e,reg,5f,macr,5g,deg,5h,plusmn,5i,sup2,5j,sup3,5k,acute," + + "5l,micro,5m,para,5n,middot,5o,cedil,5p,sup1,5q,ordm,5r,raquo,5s,frac14,5t,frac12,5u,frac34," + + "5v,iquest,60,Agrave,61,Aacute,62,Acirc,63,Atilde,64,Auml,65,Aring,66,AElig,67,Ccedil," + + "68,Egrave,69,Eacute,6a,Ecirc,6b,Euml,6c,Igrave,6d,Iacute,6e,Icirc,6f,Iuml,6g,ETH,6h,Ntilde," + + "6i,Ograve,6j,Oacute,6k,Ocirc,6l,Otilde,6m,Ouml,6n,times,6o,Oslash,6p,Ugrave,6q,Uacute," + + "6r,Ucirc,6s,Uuml,6t,Yacute,6u,THORN,6v,szlig,70,agrave,71,aacute,72,acirc,73,atilde,74,auml," + + "75,aring,76,aelig,77,ccedil,78,egrave,79,eacute,7a,ecirc,7b,euml,7c,igrave,7d,iacute,7e,icirc," + + "7f,iuml,7g,eth,7h,ntilde,7i,ograve,7j,oacute,7k,ocirc,7l,otilde,7m,ouml,7n,divide,7o,oslash," + + "7p,ugrave,7q,uacute,7r,ucirc,7s,uuml,7t,yacute,7u,thorn,7v,yuml,ci,fnof,sh,Alpha,si,Beta," + + "sj,Gamma,sk,Delta,sl,Epsilon,sm,Zeta,sn,Eta,so,Theta,sp,Iota,sq,Kappa,sr,Lambda,ss,Mu," + + "st,Nu,su,Xi,sv,Omicron,t0,Pi,t1,Rho,t3,Sigma,t4,Tau,t5,Upsilon,t6,Phi,t7,Chi,t8,Psi," + + "t9,Omega,th,alpha,ti,beta,tj,gamma,tk,delta,tl,epsilon,tm,zeta,tn,eta,to,theta,tp,iota," + + "tq,kappa,tr,lambda,ts,mu,tt,nu,tu,xi,tv,omicron,u0,pi,u1,rho,u2,sigmaf,u3,sigma,u4,tau," + + "u5,upsilon,u6,phi,u7,chi,u8,psi,u9,omega,uh,thetasym,ui,upsih,um,piv,812,bull,816,hellip," + + "81i,prime,81j,Prime,81u,oline,824,frasl,88o,weierp,88h,image,88s,real,892,trade,89l,alefsym," + + "8cg,larr,8ch,uarr,8ci,rarr,8cj,darr,8ck,harr,8dl,crarr,8eg,lArr,8eh,uArr,8ei,rArr,8ej,dArr," + + "8ek,hArr,8g0,forall,8g2,part,8g3,exist,8g5,empty,8g7,nabla,8g8,isin,8g9,notin,8gb,ni,8gf,prod," + + "8gh,sum,8gi,minus,8gn,lowast,8gq,radic,8gt,prop,8gu,infin,8h0,ang,8h7,and,8h8,or,8h9,cap,8ha,cup," + + "8hb,int,8hk,there4,8hs,sim,8i5,cong,8i8,asymp,8j0,ne,8j1,equiv,8j4,le,8j5,ge,8k2,sub,8k3,sup,8k4," + + "nsub,8k6,sube,8k7,supe,8kl,oplus,8kn,otimes,8l5,perp,8m5,sdot,8o8,lceil,8o9,rceil,8oa,lfloor,8ob," + + "rfloor,8p9,lang,8pa,rang,9ea,loz,9j0,spades,9j3,clubs,9j5,hearts,9j6,diams,ai,OElig,aj,oelig,b0," + + "Scaron,b1,scaron,bo,Yuml,m6,circ,ms,tilde,802,ensp,803,emsp,809,thinsp,80c,zwnj,80d,zwj,80e,lrm," + + "80f,rlm,80j,ndash,80k,mdash,80o,lsquo,80p,rsquo,80q,sbquo,80s,ldquo,80t,rdquo,80u,bdquo,810,dagger," + + "811,Dagger,81g,permil,81p,lsaquo,81q,rsaquo,85c,euro", 32 ); @@ -355,9 +355,9 @@ export default (function () { } var element = this.__document.createElementNS( - "http://www.w3.org/2000/svg", - elementName - ), + "http://www.w3.org/2000/svg", + elementName + ), keys = Object.keys(properties), i, key; @@ -775,12 +775,26 @@ export default (function () { path = this.__currentDefaultPath; } - var pathElement = this.__createPathElement(); - this.__applyStyleToElement(pathElement, action); - pathElement.setAttribute("paint-order", "fill stroke markers"); - pathElement.setAttribute("d", path.__pathString); + if (path.__pathString.length > 0) { + var pathElement = this.__createPathElement(); + this.__applyStyleToElement(pathElement, action); + pathElement.setAttribute("paint-order", "fill stroke markers"); + pathElement.setAttribute("d", path.__pathString); + if (path2d) { + this.__applyTransformation(pathElement); + } + } + if (path2d) { - this.__applyTransformation(pathElement); + path2d.__subPaths.forEach((subPath) => { + var pathElement = this.__createPathElement(); + this.__applyStyleToElement(pathElement, action); + pathElement.setAttribute("paint-order", "fill stroke markers"); + pathElement.setAttribute("d", subPath.path.__pathString); + if (subPath.transform) { + this.__applyTransformation(pathElement, this.getTransform().multiply(subPath.transform)); + } + }); } }; @@ -1160,9 +1174,9 @@ export default (function () { */ Context.prototype.createPattern = function (image, repetition) { var pattern = this.__document.createElementNS( - "http://www.w3.org/2000/svg", - "pattern" - ), + "http://www.w3.org/2000/svg", + "pattern" + ), id = randomString(this.__ids), img; pattern.setAttribute("id", id); @@ -1351,10 +1365,10 @@ export default (function () { /** * Not yet implemented */ - Context.prototype.drawFocusRing = function () {}; - Context.prototype.createImageData = function () {}; - Context.prototype.putImageData = function () {}; - Context.prototype.globalCompositeOperation = function () {}; + Context.prototype.drawFocusRing = function () { }; + Context.prototype.createImageData = function () { }; + Context.prototype.putImageData = function () { }; + Context.prototype.globalCompositeOperation = function () { }; return Context; })(); diff --git a/path2d.js b/path2d.js index 487049c..40c66d9 100644 --- a/path2d.js +++ b/path2d.js @@ -22,6 +22,7 @@ export default (function () { } this.ctx = ctx; + this.__subPaths = []; // Array of path string/transform pairs. this.__currentPosition = { x: undefined, y: undefined }; }; @@ -29,18 +30,19 @@ export default (function () { return this.ctx.__matrixTransform(x, y); }; - Path2D.prototype.addPath = function (path, transform) { - if (transform) - console.error("transform argument to addPath is not supported"); - - this.__pathString = this.__pathString + " " + path; + Path2D.prototype.addPath = function (path, transform = undefined) { + this.__subPaths.push({ path: path, transform: transform }); }; + Path2D.prototype.appendPath = function (path) { + this.__pathString = this.__pathString + " " + path; + } + /** * Closes the current path */ Path2D.prototype.closePath = function () { - this.addPath("Z"); + this.appendPath("Z"); }; /** @@ -50,7 +52,7 @@ export default (function () { Path2D.prototype.moveTo = function (x, y) { // creates a new subpath with the given point this.__currentPosition = { x: x, y: y }; - this.addPath( + this.appendPath( format("M {x} {y}", { x: this.__matrixTransform(x, y).x, y: this.__matrixTransform(x, y).y, @@ -64,14 +66,14 @@ export default (function () { Path2D.prototype.lineTo = function (x, y) { this.__currentPosition = { x: x, y: y }; if (this.__pathString.indexOf("M") > -1) { - this.addPath( + this.appendPath( format("L {x} {y}", { x: this.__matrixTransform(x, y).x, y: this.__matrixTransform(x, y).y, }) ); } else { - this.addPath( + this.appendPath( format("M {x} {y}", { x: this.__matrixTransform(x, y).x, y: this.__matrixTransform(x, y).y, @@ -101,7 +103,7 @@ export default (function () { */ Path2D.prototype.bezierCurveTo = function (cp1x, cp1y, cp2x, cp2y, x, y) { this.__currentPosition = { x: x, y: y }; - this.addPath( + this.appendPath( format("C {cp1x} {cp1y} {cp2x} {cp2y} {x} {y}", { cp1x: this.__matrixTransform(cp1x, cp1y).x, cp1y: this.__matrixTransform(cp1x, cp1y).y, @@ -118,7 +120,7 @@ export default (function () { */ Path2D.prototype.quadraticCurveTo = function (cpx, cpy, x, y) { this.__currentPosition = { x: x, y: y }; - this.addPath( + this.appendPath( format("Q {cpx} {cpy} {x} {y}", { cpx: this.__matrixTransform(cpx, cpy).x, cpy: this.__matrixTransform(cpx, cpy).y, @@ -180,7 +182,7 @@ export default (function () { ); this.lineTo(startX, startY); - this.addPath( + this.appendPath( format( "A {rx} {ry} {xAxisRotation} {largeArcFlag} {sweepFlag} {endX} {endY}", { @@ -370,7 +372,7 @@ export default (function () { this.lineTo(startX, startY); this.ctx.__transformMatrix = currentTransform; - this.addPath( + this.appendPath( format( "A {rx} {ry} {xAxisRotation} {largeArcFlag} {sweepFlag} {endX} {endY}", { diff --git a/test/tests/path2D.js b/test/tests/path2D.js index 6a80b59..09d1aa9 100644 --- a/test/tests/path2D.js +++ b/test/tests/path2D.js @@ -45,4 +45,50 @@ export default function path2D(ctx) { ctx.fill(); ctx.restore(); ctx.restore(); + + // Scaling path versus scaling the context. + const path2 = makePath( + ctx, + `M -10 -10 + L 10 -10 + L 10 10 + L -10 10 + Z` + ); + + + ctx.save(); + ctx.translate(25, 100); + ctx.scale(2, 1); + ctx.strokeStyle = "red"; + ctx.moveTo(-10, -10); + ctx.lineTo(10, -10); + ctx.lineTo(10, 10); + ctx.lineTo(-10, 10); + ctx.closePath(); + ctx.fillStyle = "grey"; + ctx.fill(); + ctx.scale(1 / 2, 1); // Reset scale so that stroke is not scaled. + ctx.stroke(); + ctx.restore(); + + ctx.save(); + ctx.translate(100, 100); + ctx.scale(2, 1); + ctx.fillStyle = "grey"; + ctx.fill(path2); + ctx.strokeStyle = "red"; + + let pNext = makePath(ctx); + // add first path, transform path, twice size, move 100,10 + pNext.addPath(path2, new DOMMatrix([ + 2, 0, + 0, 1, + 0, + 0, + ])); + + ctx.scale(1 / 2, 1); // Reset scale so that stroke is not scaled. + ctx.stroke(pNext); + ctx.restore(); }