modern-text 0.0.7 → 0.0.9

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/index.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});class w{static get defaultStyle(){return{width:"auto",height:"auto",color:"#000000",fontSize:14,fontWeight:"normal",fontFamily:"sans-serif",fontStyle:"normal",fontKerning:"normal",textWrap:"wrap",textAlign:"start",verticalAlign:"baseline",textDecoration:null,textStrokeWidth:0,textStrokeColor:"#000000",direction:"inherit",lineHeight:1,letterSpacing:0,shadowColor:"#000000",shadowOffsetX:0,shadowOffsetY:0,shadowBlur:0}}constructor(o={}){const{view:t=document.createElement("canvas"),pixelRatio:l=window.devicePixelRatio||1,content:e="",style:x}=o;this.view=t,this.context=t.getContext("2d"),this.pixelRatio=l,this.content=e,this.style={...w.defaultStyle,...x},this.update()}measure(){let{width:o}=this.style;o==="auto"&&(o=0);let t=this._createParagraphs(this.content);t=this._createWrapedParagraphs(t,o);const l=this.context;let e=0;for(let h=t.length,s=0;s<h;s++){const i=t[s];i.contentBox.top=e;let c=0,d=null;for(const n of i.fragments){this._setContextStyle({...n.style,textAlign:"left",verticalAlign:"baseline"});const r=l.measureText(n.content);n.inlineBox.left=c,n.inlineBox.top=e,n.inlineBox.width=r.width,n.inlineBox.height=n.style.fontSize*n.style.lineHeight,n.contentBox.left=n.inlineBox.left,n.contentBox.width=n.inlineBox.width,n.contentBox.height=n.style.fontSize,n.contentBox.top=n.inlineBox.top+(n.inlineBox.height-n.contentBox.height)/2,n.textBox.width=r.actualBoundingBoxLeft+r.actualBoundingBoxRight,n.textBox.height=r.actualBoundingBoxAscent+r.actualBoundingBoxDescent,n.textBox.left=n.contentBox.left+(n.contentBox.width-n.textBox.width)/2,n.textBox.top=n.contentBox.top+(n.contentBox.height-n.textBox.height)/2,n.baseline=n.textBox.top+r.actualBoundingBoxAscent,c+=n.contentBox.width+n.style.letterSpacing,i.contentBox.height<n.contentBox.height&&(d=n),i.contentBox.left=Math.min(i.contentBox.left,n.contentBox.left),i.contentBox.top=Math.min(i.contentBox.top,n.contentBox.top),i.contentBox.height=Math.max(i.contentBox.height,n.contentBox.height),i.lineBox.height=Math.max(i.lineBox.height,n.inlineBox.height)}const B=i.fragments[i.fragments.length-1];i.contentBox.width=Math.max(i.contentBox.width,B?B.contentBox.left+Math.max(B.contentBox.width,B.textBox.width):0),i.lineBox.left=0,i.lineBox.top=e,i.lineBox.width=Math.max(o,i.contentBox.width),this._setContextStyle({...(d??i).style,textAlign:"left",verticalAlign:"baseline"});const f=l.measureText("X");i.baseline=i.lineBox.top+(i.lineBox.height-f.actualBoundingBoxAscent+f.actualBoundingBoxDescent)/2+f.actualBoundingBoxAscent,e+=i.lineBox.height}for(let h=t.length,s=0;s<h;s++){const i=t[s];i.fragments.forEach(c=>{const d=c.inlineBox.left,B=c.inlineBox.top,f=i.lineBox.height-c.inlineBox.height;switch(c.style.textAlign){case"end":case"right":c.inlineBox.left+=i.lineBox.width-i.contentBox.width;break;case"center":c.inlineBox.left+=(i.lineBox.width-i.contentBox.width)/2;break;case"start":case"left":default:c.inlineBox.left+=i.lineBox.left;break}switch(c.style.verticalAlign){case"top":c.inlineBox.top=i.lineBox.top;break;case"middle":c.inlineBox.top=i.lineBox.top+f/2;break;case"bottom":c.inlineBox.top=i.lineBox.top+f;break;case"sub":case"text-top":case"text-bottom":break;case"baseline":default:c.inlineBox.height<i.lineBox.height&&(c.inlineBox.top+=i.baseline-c.baseline);break}const n=c.inlineBox.left-d,r=c.inlineBox.top-B;c.contentBox.left+=n,c.contentBox.top+=r,c.textBox.left+=n,c.textBox.top+=r})}const x=t.reduce((h,s)=>(h.left=Math.min(h.left,s.contentBox.left),h.top=Math.min(h.top,s.contentBox.top),h.width=Math.max(h.width,s.contentBox.width),h.height+=s.contentBox.height,h),{left:0,top:0,width:0,height:0});return{lineBox:t.reduce((h,s)=>(h.left=Math.min(h.left,s.lineBox.left),h.top=Math.min(h.top,s.lineBox.top),h.width=Math.max(h.width,s.lineBox.width),h.height+=s.lineBox.height,h),{left:0,top:0,width:0,height:0}),contentBox:x,paragraphs:t}}_createParagraphs(o){const t=(x={})=>{const{width:a,height:h,...s}=this.style;return{contentBox:{left:0,top:0,width:0,height:0},lineBox:{left:0,top:0,width:0,height:0},baseline:0,fragments:[],...x,style:{...s,...x.style}}},l=(x={})=>{const a=[],{width:h,height:s,...i}=this.style;return a.push({contentBox:{left:0,top:0,width:0,height:0},inlineBox:{left:0,top:0,width:0,height:0},textBox:{left:0,top:0,width:0,height:0},baseline:0,...x,style:{...i,...x.style},content:x.content??""}),a},e=[];if(typeof o=="string")e.push(t({fragments:l({content:o})}));else{o=Array.isArray(o)?o:[o];for(const x of o)if("fragments"in x){const{fragments:a,...h}=x,s=t({style:h});for(const i of a){const{content:c,...d}=i;s.fragments.push(...l({content:c,style:{...h,...d}}))}e.push(s)}else if("content"in x){const{content:a,...h}=x,s=t({style:h});s.fragments.push(...l({content:a,style:h})),e.push(s)}}return e}_createWrapedParagraphs(o,t){const l=s=>JSON.parse(JSON.stringify(s)),e=[],x=o.slice();let a,h;for(;a=x.shift();){const s=a.fragments.slice();let i=0;const c=[];for(;h=s.shift();){const d=h.style;this._setContextStyle(d);let B="",f=!1;for(const n of h.content){const r=this.context.measureText(n).width,u=/^[\r\n]$/.test(n);if(u||d.textWrap==="wrap"&&t&&i+r>t){let g=u?B.length+1:B.length;!i&&!g&&(B+=n,g++),B.length&&c.push({...l(h),content:B}),c.length&&(e.push({...l(a),fragments:c.slice()}),c.length=0);const p=h.content.substring(g);(p.length||s.length)&&x.unshift({...l(a),fragments:(p.length?[{...l(h),content:p}]:[]).concat(s.slice())}),s.length=0,f=!0;break}else i+=r;B+=n}f||c.push(l(h))}c.length&&e.push({...l(a),fragments:c})}return e}_draw(o){const t=this.context;this.style.backgroundColor&&(t.fillStyle=this.style.backgroundColor,t.fillRect(0,0,t.canvas.width,t.canvas.height)),o.forEach(l=>{l.style.backgroundColor&&(t.fillStyle=l.style.backgroundColor,t.fillRect(l.lineBox.left,l.lineBox.top,l.lineBox.width,l.lineBox.height))}),o.forEach(l=>{l.fragments.forEach(e=>{switch(e.style.backgroundColor&&(t.fillStyle=e.style.backgroundColor,t.fillRect(e.inlineBox.left,e.inlineBox.top,e.inlineBox.width,e.inlineBox.height)),this._setContextStyle({...e.style,textAlign:"left",verticalAlign:"top"}),e.style.textStrokeWidth&&t.strokeText(e.content,e.contentBox.left,e.contentBox.top),t.fillText(e.content,e.contentBox.left,e.contentBox.top),e.style.textDecoration){case"underline":t.beginPath(),t.moveTo(e.contentBox.left,e.contentBox.top+e.contentBox.height-2),t.lineTo(e.contentBox.left+e.contentBox.width,e.contentBox.top+e.contentBox.height-2),t.stroke();break;case"line-through":t.beginPath(),t.moveTo(e.contentBox.left,e.contentBox.top+e.contentBox.height/2),t.lineTo(e.contentBox.left+e.contentBox.width,e.contentBox.top+e.contentBox.height/2),t.stroke();break}})})}_resizeView(o,t){const l=this.view;l.style.width=`${o}px`,l.style.height=`${t}px`,l.dataset.width=String(o),l.dataset.height=String(t),l.width=Math.max(1,Math.floor(o*this.pixelRatio)),l.height=Math.max(1,Math.floor(t*this.pixelRatio))}_setContextStyle(o){const t=this.context;switch(t.shadowColor=o.shadowColor,t.shadowOffsetX=o.shadowOffsetX,t.shadowOffsetY=o.shadowOffsetY,t.shadowBlur=o.shadowBlur,t.strokeStyle=o.textStrokeColor,t.lineWidth=o.textStrokeWidth,t.fillStyle=o.color,t.direction=o.direction,t.textAlign=o.textAlign,o.verticalAlign){case"baseline":t.textBaseline="alphabetic";break;case"top":case"middle":case"bottom":t.textBaseline=o.verticalAlign;break}t.font=[o.fontStyle,o.fontWeight,`${o.fontSize}px`,o.fontFamily].join(" "),t.fontKerning=o.fontKerning,t.letterSpacing=`${o.letterSpacing}px`}update(){const o=this.context;let{width:t,height:l}=this.style;t==="auto"&&(t=0),l==="auto"&&(l=0);const{lineBox:e,paragraphs:x}=this.measure();t||(t=e.width),l=Math.max(l,e.height),this._resizeView(t,l);const a=this.pixelRatio;o.scale(a,a),o.clearRect(0,0,o.canvas.width,o.canvas.height),this._draw(x)}}exports.Text=w;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});class w{static get defaultStyle(){return{width:"auto",height:"auto",color:"#000000",fontSize:14,fontWeight:"normal",fontFamily:"sans-serif",fontStyle:"normal",fontKerning:"normal",textWrap:"wrap",textAlign:"start",verticalAlign:"baseline",textDecoration:null,textStrokeWidth:0,textStrokeColor:"#000000",direction:"inherit",lineHeight:1,letterSpacing:0,shadowColor:"#000000",shadowOffsetX:0,shadowOffsetY:0,shadowBlur:0}}constructor(n={}){const{view:t=document.createElement("canvas"),pixelRatio:l=window.devicePixelRatio||1,content:e="",style:a}=n;this.view=t,this.context=t.getContext("2d"),this.pixelRatio=l,this.content=e,this.style={...w.defaultStyle,...a},this.update()}measure(){let{width:n}=this.style;n==="auto"&&(n=0);let t=this._createParagraphs(this.content);t=this._createWrapedParagraphs(t,n);const l=this.context;let e=0;for(let h=t.length,c=0;c<h;c++){const i=t[c];i.contentBox.top=e;let s=0,d=null;for(const o of i.fragments){this._setContextStyle({...o.style,textAlign:"center",verticalAlign:"baseline"});const B=l.measureText(o.content),p=B.width,f=o.style.fontSize;o.inlineBox.left=s,o.inlineBox.top=e,o.inlineBox.width=p,o.inlineBox.height=f*o.style.lineHeight,o.contentBox.left=o.inlineBox.left,o.contentBox.width=p,o.contentBox.height=f,o.contentBox.top=o.inlineBox.top+(o.inlineBox.height-o.contentBox.height)/2,o.glyphBox.width=B.actualBoundingBoxLeft+B.actualBoundingBoxRight,o.glyphBox.height=B.actualBoundingBoxAscent+B.actualBoundingBoxDescent,o.glyphBox.left=o.contentBox.left+(o.contentBox.width-o.glyphBox.width)/2,o.glyphBox.top=o.contentBox.top+(o.contentBox.height-o.glyphBox.height)/2,o.centerX=o.glyphBox.left+B.actualBoundingBoxLeft,o.baseline=o.glyphBox.top+B.actualBoundingBoxAscent,s+=o.contentBox.width+o.style.letterSpacing,i.contentBox.height<o.contentBox.height&&(d=o),i.contentBox.left=Math.min(i.contentBox.left,o.contentBox.left),i.contentBox.top=Math.min(i.contentBox.top,o.contentBox.top),i.contentBox.height=Math.max(i.contentBox.height,o.contentBox.height),i.lineBox.height=Math.max(i.lineBox.height,o.inlineBox.height)}const r=i.fragments[i.fragments.length-1];i.contentBox.width=Math.max(i.contentBox.width,r?r.contentBox.left+Math.max(r.contentBox.width,r.glyphBox.width):0),i.lineBox.left=0,i.lineBox.top=e,i.lineBox.width=Math.max(n,i.contentBox.width),this._setContextStyle({...(d??i).style,textAlign:"left",verticalAlign:"baseline"});const g=l.measureText("X");i.baseline=i.lineBox.top+(i.lineBox.height-g.actualBoundingBoxAscent+g.actualBoundingBoxDescent)/2+g.actualBoundingBoxAscent,e+=i.lineBox.height}for(let h=t.length,c=0;c<h;c++){const i=t[c];i.fragments.forEach(s=>{const d=s.inlineBox.left,r=s.inlineBox.top,g=i.lineBox.height-s.inlineBox.height;switch(s.style.textAlign){case"end":case"right":s.inlineBox.left+=i.lineBox.width-i.contentBox.width;break;case"center":s.inlineBox.left+=(i.lineBox.width-i.contentBox.width)/2;break;case"start":case"left":default:s.inlineBox.left+=i.lineBox.left;break}switch(s.style.verticalAlign){case"top":s.inlineBox.top=i.lineBox.top;break;case"middle":s.inlineBox.top=i.lineBox.top+g/2;break;case"bottom":s.inlineBox.top=i.lineBox.top+g;break;case"sub":case"text-top":case"text-bottom":break;case"baseline":default:s.inlineBox.height<i.lineBox.height&&(s.inlineBox.top+=i.baseline-s.baseline);break}const o=s.inlineBox.left-d,B=s.inlineBox.top-r;s.contentBox.left+=o,s.contentBox.top+=B,s.glyphBox.left+=o,s.glyphBox.top+=B,s.baseline+=B,s.centerX+=o})}const a=t.reduce((h,c)=>(h.left=Math.min(h.left,c.contentBox.left),h.top=Math.min(h.top,c.contentBox.top),h.width=Math.max(h.width,c.contentBox.width),h.height+=c.contentBox.height,h),{left:0,top:0,width:0,height:0});return{contentBox:t.reduce((h,c)=>(h.left=Math.min(h.left,c.lineBox.left),h.top=Math.min(h.top,c.lineBox.top),h.width=Math.max(h.width,c.lineBox.width),h.height+=c.lineBox.height,h),{left:0,top:0,width:0,height:0}),actualContentBox:a,paragraphs:t}}_createParagraphs(n){const t=(a={})=>{const{width:x,height:h,...c}=this.style;return{contentBox:{left:0,top:0,width:0,height:0},lineBox:{left:0,top:0,width:0,height:0},baseline:0,fragments:[],...a,style:{...c,...a.style}}},l=(a={})=>{const x=[],{width:h,height:c,...i}=this.style;return x.push({contentBox:{left:0,top:0,width:0,height:0},inlineBox:{left:0,top:0,width:0,height:0},glyphBox:{left:0,top:0,width:0,height:0},centerX:0,baseline:0,...a,style:{...i,...a.style},content:a.content??""}),x},e=[];if(typeof n=="string")e.push(t({fragments:l({content:n})}));else{n=Array.isArray(n)?n:[n];for(const a of n)if("fragments"in a){const{fragments:x,...h}=a,c=t({style:h});for(const i of x){const{content:s,...d}=i;c.fragments.push(...l({content:s,style:{...h,...d}}))}e.push(c)}else if("content"in a){const{content:x,...h}=a,c=t({style:h});c.fragments.push(...l({content:x,style:h})),e.push(c)}}return e}_createWrapedParagraphs(n,t){const l=c=>JSON.parse(JSON.stringify(c)),e=[],a=n.slice();let x,h;for(;x=a.shift();){const c=x.fragments.slice();let i=0;const s=[];for(;h=c.shift();){const d=h.style;this._setContextStyle(d);let r="",g=!1;for(const o of h.content){const B=this.context.measureText(o).width,p=/^[\r\n]$/.test(o);if(p||d.textWrap==="wrap"&&t&&i+B>t){let f=p?r.length+1:r.length;!i&&!f&&(r+=o,f++),r.length&&s.push({...l(h),content:r}),s.length&&(e.push({...l(x),fragments:s.slice()}),s.length=0);const u=h.content.substring(f);(u.length||c.length)&&a.unshift({...l(x),fragments:(u.length?[{...l(h),content:u}]:[]).concat(c.slice())}),c.length=0,g=!0;break}else i+=B;r+=o}g||s.push(l(h))}s.length&&e.push({...l(x),fragments:s})}return e}_draw(n){const t=this.context;this.style.backgroundColor&&(t.fillStyle=this.style.backgroundColor,t.fillRect(0,0,t.canvas.width,t.canvas.height)),n.forEach(l=>{l.style.backgroundColor&&(t.fillStyle=l.style.backgroundColor,t.fillRect(l.lineBox.left,l.lineBox.top,l.lineBox.width,l.lineBox.height))}),n.forEach(l=>{l.fragments.forEach(e=>{switch(e.style.backgroundColor&&(t.fillStyle=e.style.backgroundColor,t.fillRect(e.inlineBox.left,e.inlineBox.top,e.inlineBox.width,e.inlineBox.height)),this._setContextStyle({...e.style,textAlign:"left",verticalAlign:"top"}),e.style.textStrokeWidth&&t.strokeText(e.content,e.contentBox.left,e.contentBox.top),t.fillText(e.content,e.contentBox.left,e.contentBox.top),e.style.textDecoration){case"underline":t.beginPath(),t.moveTo(e.contentBox.left,e.contentBox.top+e.contentBox.height-2),t.lineTo(e.contentBox.left+e.contentBox.width,e.contentBox.top+e.contentBox.height-2),t.stroke();break;case"line-through":t.beginPath(),t.moveTo(e.contentBox.left,e.contentBox.top+e.contentBox.height/2),t.lineTo(e.contentBox.left+e.contentBox.width,e.contentBox.top+e.contentBox.height/2),t.stroke();break}})})}_resizeView(n,t){const l=this.view;l.style.width=`${n}px`,l.style.height=`${t}px`,l.dataset.width=String(n),l.dataset.height=String(t),l.width=Math.max(1,Math.floor(n*this.pixelRatio)),l.height=Math.max(1,Math.floor(t*this.pixelRatio))}_setContextStyle(n){const t=this.context;switch(t.shadowColor=n.shadowColor,t.shadowOffsetX=n.shadowOffsetX,t.shadowOffsetY=n.shadowOffsetY,t.shadowBlur=n.shadowBlur,t.strokeStyle=n.textStrokeColor,t.lineWidth=n.textStrokeWidth,t.fillStyle=n.color,t.direction=n.direction,t.textAlign=n.textAlign,n.verticalAlign){case"baseline":t.textBaseline="alphabetic";break;case"top":case"middle":case"bottom":t.textBaseline=n.verticalAlign;break}t.font=[n.fontStyle,n.fontWeight,`${n.fontSize}px`,n.fontFamily].join(" "),t.fontKerning=n.fontKerning,t.letterSpacing=`${n.letterSpacing}px`}update(){const n=this.context;let{width:t,height:l}=this.style;t==="auto"&&(t=0),l==="auto"&&(l=0);const{contentBox:e,paragraphs:a}=this.measure();t||(t=e.width),l=Math.max(l,e.height),this._resizeView(t,l);const x=this.pixelRatio;n.scale(x,x),n.clearRect(0,0,n.canvas.width,n.canvas.height),this._draw(a)}}exports.Text=w;
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- (function(p,g){typeof exports=="object"&&typeof module<"u"?g(exports):typeof define=="function"&&define.amd?define(["exports"],g):(p=typeof globalThis<"u"?globalThis:p||self,g(p.modernText={}))})(this,function(p){"use strict";class g{static get defaultStyle(){return{width:"auto",height:"auto",color:"#000000",fontSize:14,fontWeight:"normal",fontFamily:"sans-serif",fontStyle:"normal",fontKerning:"normal",textWrap:"wrap",textAlign:"start",verticalAlign:"baseline",textDecoration:null,textStrokeWidth:0,textStrokeColor:"#000000",direction:"inherit",lineHeight:1,letterSpacing:0,shadowColor:"#000000",shadowOffsetX:0,shadowOffsetY:0,shadowBlur:0}}constructor(o={}){const{view:t=document.createElement("canvas"),pixelRatio:l=window.devicePixelRatio||1,content:e="",style:x}=o;this.view=t,this.context=t.getContext("2d"),this.pixelRatio=l,this.content=e,this.style={...g.defaultStyle,...x},this.update()}measure(){let{width:o}=this.style;o==="auto"&&(o=0);let t=this._createParagraphs(this.content);t=this._createWrapedParagraphs(t,o);const l=this.context;let e=0;for(let h=t.length,s=0;s<h;s++){const i=t[s];i.contentBox.top=e;let c=0,r=null;for(const n of i.fragments){this._setContextStyle({...n.style,textAlign:"left",verticalAlign:"baseline"});const d=l.measureText(n.content);n.inlineBox.left=c,n.inlineBox.top=e,n.inlineBox.width=d.width,n.inlineBox.height=n.style.fontSize*n.style.lineHeight,n.contentBox.left=n.inlineBox.left,n.contentBox.width=n.inlineBox.width,n.contentBox.height=n.style.fontSize,n.contentBox.top=n.inlineBox.top+(n.inlineBox.height-n.contentBox.height)/2,n.textBox.width=d.actualBoundingBoxLeft+d.actualBoundingBoxRight,n.textBox.height=d.actualBoundingBoxAscent+d.actualBoundingBoxDescent,n.textBox.left=n.contentBox.left+(n.contentBox.width-n.textBox.width)/2,n.textBox.top=n.contentBox.top+(n.contentBox.height-n.textBox.height)/2,n.baseline=n.textBox.top+d.actualBoundingBoxAscent,c+=n.contentBox.width+n.style.letterSpacing,i.contentBox.height<n.contentBox.height&&(r=n),i.contentBox.left=Math.min(i.contentBox.left,n.contentBox.left),i.contentBox.top=Math.min(i.contentBox.top,n.contentBox.top),i.contentBox.height=Math.max(i.contentBox.height,n.contentBox.height),i.lineBox.height=Math.max(i.lineBox.height,n.inlineBox.height)}const B=i.fragments[i.fragments.length-1];i.contentBox.width=Math.max(i.contentBox.width,B?B.contentBox.left+Math.max(B.contentBox.width,B.textBox.width):0),i.lineBox.left=0,i.lineBox.top=e,i.lineBox.width=Math.max(o,i.contentBox.width),this._setContextStyle({...(r??i).style,textAlign:"left",verticalAlign:"baseline"});const f=l.measureText("X");i.baseline=i.lineBox.top+(i.lineBox.height-f.actualBoundingBoxAscent+f.actualBoundingBoxDescent)/2+f.actualBoundingBoxAscent,e+=i.lineBox.height}for(let h=t.length,s=0;s<h;s++){const i=t[s];i.fragments.forEach(c=>{const r=c.inlineBox.left,B=c.inlineBox.top,f=i.lineBox.height-c.inlineBox.height;switch(c.style.textAlign){case"end":case"right":c.inlineBox.left+=i.lineBox.width-i.contentBox.width;break;case"center":c.inlineBox.left+=(i.lineBox.width-i.contentBox.width)/2;break;case"start":case"left":default:c.inlineBox.left+=i.lineBox.left;break}switch(c.style.verticalAlign){case"top":c.inlineBox.top=i.lineBox.top;break;case"middle":c.inlineBox.top=i.lineBox.top+f/2;break;case"bottom":c.inlineBox.top=i.lineBox.top+f;break;case"sub":case"text-top":case"text-bottom":break;case"baseline":default:c.inlineBox.height<i.lineBox.height&&(c.inlineBox.top+=i.baseline-c.baseline);break}const n=c.inlineBox.left-r,d=c.inlineBox.top-B;c.contentBox.left+=n,c.contentBox.top+=d,c.textBox.left+=n,c.textBox.top+=d})}const x=t.reduce((h,s)=>(h.left=Math.min(h.left,s.contentBox.left),h.top=Math.min(h.top,s.contentBox.top),h.width=Math.max(h.width,s.contentBox.width),h.height+=s.contentBox.height,h),{left:0,top:0,width:0,height:0});return{lineBox:t.reduce((h,s)=>(h.left=Math.min(h.left,s.lineBox.left),h.top=Math.min(h.top,s.lineBox.top),h.width=Math.max(h.width,s.lineBox.width),h.height+=s.lineBox.height,h),{left:0,top:0,width:0,height:0}),contentBox:x,paragraphs:t}}_createParagraphs(o){const t=(x={})=>{const{width:a,height:h,...s}=this.style;return{contentBox:{left:0,top:0,width:0,height:0},lineBox:{left:0,top:0,width:0,height:0},baseline:0,fragments:[],...x,style:{...s,...x.style}}},l=(x={})=>{const a=[],{width:h,height:s,...i}=this.style;return a.push({contentBox:{left:0,top:0,width:0,height:0},inlineBox:{left:0,top:0,width:0,height:0},textBox:{left:0,top:0,width:0,height:0},baseline:0,...x,style:{...i,...x.style},content:x.content??""}),a},e=[];if(typeof o=="string")e.push(t({fragments:l({content:o})}));else{o=Array.isArray(o)?o:[o];for(const x of o)if("fragments"in x){const{fragments:a,...h}=x,s=t({style:h});for(const i of a){const{content:c,...r}=i;s.fragments.push(...l({content:c,style:{...h,...r}}))}e.push(s)}else if("content"in x){const{content:a,...h}=x,s=t({style:h});s.fragments.push(...l({content:a,style:h})),e.push(s)}}return e}_createWrapedParagraphs(o,t){const l=s=>JSON.parse(JSON.stringify(s)),e=[],x=o.slice();let a,h;for(;a=x.shift();){const s=a.fragments.slice();let i=0;const c=[];for(;h=s.shift();){const r=h.style;this._setContextStyle(r);let B="",f=!1;for(const n of h.content){const d=this.context.measureText(n).width,y=/^[\r\n]$/.test(n);if(y||r.textWrap==="wrap"&&t&&i+d>t){let u=y?B.length+1:B.length;!i&&!u&&(B+=n,u++),B.length&&c.push({...l(h),content:B}),c.length&&(e.push({...l(a),fragments:c.slice()}),c.length=0);const w=h.content.substring(u);(w.length||s.length)&&x.unshift({...l(a),fragments:(w.length?[{...l(h),content:w}]:[]).concat(s.slice())}),s.length=0,f=!0;break}else i+=d;B+=n}f||c.push(l(h))}c.length&&e.push({...l(a),fragments:c})}return e}_draw(o){const t=this.context;this.style.backgroundColor&&(t.fillStyle=this.style.backgroundColor,t.fillRect(0,0,t.canvas.width,t.canvas.height)),o.forEach(l=>{l.style.backgroundColor&&(t.fillStyle=l.style.backgroundColor,t.fillRect(l.lineBox.left,l.lineBox.top,l.lineBox.width,l.lineBox.height))}),o.forEach(l=>{l.fragments.forEach(e=>{switch(e.style.backgroundColor&&(t.fillStyle=e.style.backgroundColor,t.fillRect(e.inlineBox.left,e.inlineBox.top,e.inlineBox.width,e.inlineBox.height)),this._setContextStyle({...e.style,textAlign:"left",verticalAlign:"top"}),e.style.textStrokeWidth&&t.strokeText(e.content,e.contentBox.left,e.contentBox.top),t.fillText(e.content,e.contentBox.left,e.contentBox.top),e.style.textDecoration){case"underline":t.beginPath(),t.moveTo(e.contentBox.left,e.contentBox.top+e.contentBox.height-2),t.lineTo(e.contentBox.left+e.contentBox.width,e.contentBox.top+e.contentBox.height-2),t.stroke();break;case"line-through":t.beginPath(),t.moveTo(e.contentBox.left,e.contentBox.top+e.contentBox.height/2),t.lineTo(e.contentBox.left+e.contentBox.width,e.contentBox.top+e.contentBox.height/2),t.stroke();break}})})}_resizeView(o,t){const l=this.view;l.style.width=`${o}px`,l.style.height=`${t}px`,l.dataset.width=String(o),l.dataset.height=String(t),l.width=Math.max(1,Math.floor(o*this.pixelRatio)),l.height=Math.max(1,Math.floor(t*this.pixelRatio))}_setContextStyle(o){const t=this.context;switch(t.shadowColor=o.shadowColor,t.shadowOffsetX=o.shadowOffsetX,t.shadowOffsetY=o.shadowOffsetY,t.shadowBlur=o.shadowBlur,t.strokeStyle=o.textStrokeColor,t.lineWidth=o.textStrokeWidth,t.fillStyle=o.color,t.direction=o.direction,t.textAlign=o.textAlign,o.verticalAlign){case"baseline":t.textBaseline="alphabetic";break;case"top":case"middle":case"bottom":t.textBaseline=o.verticalAlign;break}t.font=[o.fontStyle,o.fontWeight,`${o.fontSize}px`,o.fontFamily].join(" "),t.fontKerning=o.fontKerning,t.letterSpacing=`${o.letterSpacing}px`}update(){const o=this.context;let{width:t,height:l}=this.style;t==="auto"&&(t=0),l==="auto"&&(l=0);const{lineBox:e,paragraphs:x}=this.measure();t||(t=e.width),l=Math.max(l,e.height),this._resizeView(t,l);const a=this.pixelRatio;o.scale(a,a),o.clearRect(0,0,o.canvas.width,o.canvas.height),this._draw(x)}}p.Text=g,Object.defineProperty(p,Symbol.toStringTag,{value:"Module"})});
1
+ (function(p,g){typeof exports=="object"&&typeof module<"u"?g(exports):typeof define=="function"&&define.amd?define(["exports"],g):(p=typeof globalThis<"u"?globalThis:p||self,g(p.modernText={}))})(this,function(p){"use strict";class g{static get defaultStyle(){return{width:"auto",height:"auto",color:"#000000",fontSize:14,fontWeight:"normal",fontFamily:"sans-serif",fontStyle:"normal",fontKerning:"normal",textWrap:"wrap",textAlign:"start",verticalAlign:"baseline",textDecoration:null,textStrokeWidth:0,textStrokeColor:"#000000",direction:"inherit",lineHeight:1,letterSpacing:0,shadowColor:"#000000",shadowOffsetX:0,shadowOffsetY:0,shadowBlur:0}}constructor(n={}){const{view:t=document.createElement("canvas"),pixelRatio:l=window.devicePixelRatio||1,content:e="",style:a}=n;this.view=t,this.context=t.getContext("2d"),this.pixelRatio=l,this.content=e,this.style={...g.defaultStyle,...a},this.update()}measure(){let{width:n}=this.style;n==="auto"&&(n=0);let t=this._createParagraphs(this.content);t=this._createWrapedParagraphs(t,n);const l=this.context;let e=0;for(let h=t.length,c=0;c<h;c++){const i=t[c];i.contentBox.top=e;let s=0,d=null;for(const o of i.fragments){this._setContextStyle({...o.style,textAlign:"center",verticalAlign:"baseline"});const B=l.measureText(o.content),w=B.width,u=o.style.fontSize;o.inlineBox.left=s,o.inlineBox.top=e,o.inlineBox.width=w,o.inlineBox.height=u*o.style.lineHeight,o.contentBox.left=o.inlineBox.left,o.contentBox.width=w,o.contentBox.height=u,o.contentBox.top=o.inlineBox.top+(o.inlineBox.height-o.contentBox.height)/2,o.glyphBox.width=B.actualBoundingBoxLeft+B.actualBoundingBoxRight,o.glyphBox.height=B.actualBoundingBoxAscent+B.actualBoundingBoxDescent,o.glyphBox.left=o.contentBox.left+(o.contentBox.width-o.glyphBox.width)/2,o.glyphBox.top=o.contentBox.top+(o.contentBox.height-o.glyphBox.height)/2,o.centerX=o.glyphBox.left+B.actualBoundingBoxLeft,o.baseline=o.glyphBox.top+B.actualBoundingBoxAscent,s+=o.contentBox.width+o.style.letterSpacing,i.contentBox.height<o.contentBox.height&&(d=o),i.contentBox.left=Math.min(i.contentBox.left,o.contentBox.left),i.contentBox.top=Math.min(i.contentBox.top,o.contentBox.top),i.contentBox.height=Math.max(i.contentBox.height,o.contentBox.height),i.lineBox.height=Math.max(i.lineBox.height,o.inlineBox.height)}const r=i.fragments[i.fragments.length-1];i.contentBox.width=Math.max(i.contentBox.width,r?r.contentBox.left+Math.max(r.contentBox.width,r.glyphBox.width):0),i.lineBox.left=0,i.lineBox.top=e,i.lineBox.width=Math.max(n,i.contentBox.width),this._setContextStyle({...(d??i).style,textAlign:"left",verticalAlign:"baseline"});const f=l.measureText("X");i.baseline=i.lineBox.top+(i.lineBox.height-f.actualBoundingBoxAscent+f.actualBoundingBoxDescent)/2+f.actualBoundingBoxAscent,e+=i.lineBox.height}for(let h=t.length,c=0;c<h;c++){const i=t[c];i.fragments.forEach(s=>{const d=s.inlineBox.left,r=s.inlineBox.top,f=i.lineBox.height-s.inlineBox.height;switch(s.style.textAlign){case"end":case"right":s.inlineBox.left+=i.lineBox.width-i.contentBox.width;break;case"center":s.inlineBox.left+=(i.lineBox.width-i.contentBox.width)/2;break;case"start":case"left":default:s.inlineBox.left+=i.lineBox.left;break}switch(s.style.verticalAlign){case"top":s.inlineBox.top=i.lineBox.top;break;case"middle":s.inlineBox.top=i.lineBox.top+f/2;break;case"bottom":s.inlineBox.top=i.lineBox.top+f;break;case"sub":case"text-top":case"text-bottom":break;case"baseline":default:s.inlineBox.height<i.lineBox.height&&(s.inlineBox.top+=i.baseline-s.baseline);break}const o=s.inlineBox.left-d,B=s.inlineBox.top-r;s.contentBox.left+=o,s.contentBox.top+=B,s.glyphBox.left+=o,s.glyphBox.top+=B,s.baseline+=B,s.centerX+=o})}const a=t.reduce((h,c)=>(h.left=Math.min(h.left,c.contentBox.left),h.top=Math.min(h.top,c.contentBox.top),h.width=Math.max(h.width,c.contentBox.width),h.height+=c.contentBox.height,h),{left:0,top:0,width:0,height:0});return{contentBox:t.reduce((h,c)=>(h.left=Math.min(h.left,c.lineBox.left),h.top=Math.min(h.top,c.lineBox.top),h.width=Math.max(h.width,c.lineBox.width),h.height+=c.lineBox.height,h),{left:0,top:0,width:0,height:0}),actualContentBox:a,paragraphs:t}}_createParagraphs(n){const t=(a={})=>{const{width:x,height:h,...c}=this.style;return{contentBox:{left:0,top:0,width:0,height:0},lineBox:{left:0,top:0,width:0,height:0},baseline:0,fragments:[],...a,style:{...c,...a.style}}},l=(a={})=>{const x=[],{width:h,height:c,...i}=this.style;return x.push({contentBox:{left:0,top:0,width:0,height:0},inlineBox:{left:0,top:0,width:0,height:0},glyphBox:{left:0,top:0,width:0,height:0},centerX:0,baseline:0,...a,style:{...i,...a.style},content:a.content??""}),x},e=[];if(typeof n=="string")e.push(t({fragments:l({content:n})}));else{n=Array.isArray(n)?n:[n];for(const a of n)if("fragments"in a){const{fragments:x,...h}=a,c=t({style:h});for(const i of x){const{content:s,...d}=i;c.fragments.push(...l({content:s,style:{...h,...d}}))}e.push(c)}else if("content"in a){const{content:x,...h}=a,c=t({style:h});c.fragments.push(...l({content:x,style:h})),e.push(c)}}return e}_createWrapedParagraphs(n,t){const l=c=>JSON.parse(JSON.stringify(c)),e=[],a=n.slice();let x,h;for(;x=a.shift();){const c=x.fragments.slice();let i=0;const s=[];for(;h=c.shift();){const d=h.style;this._setContextStyle(d);let r="",f=!1;for(const o of h.content){const B=this.context.measureText(o).width,w=/^[\r\n]$/.test(o);if(w||d.textWrap==="wrap"&&t&&i+B>t){let u=w?r.length+1:r.length;!i&&!u&&(r+=o,u++),r.length&&s.push({...l(h),content:r}),s.length&&(e.push({...l(x),fragments:s.slice()}),s.length=0);const y=h.content.substring(u);(y.length||c.length)&&a.unshift({...l(x),fragments:(y.length?[{...l(h),content:y}]:[]).concat(c.slice())}),c.length=0,f=!0;break}else i+=B;r+=o}f||s.push(l(h))}s.length&&e.push({...l(x),fragments:s})}return e}_draw(n){const t=this.context;this.style.backgroundColor&&(t.fillStyle=this.style.backgroundColor,t.fillRect(0,0,t.canvas.width,t.canvas.height)),n.forEach(l=>{l.style.backgroundColor&&(t.fillStyle=l.style.backgroundColor,t.fillRect(l.lineBox.left,l.lineBox.top,l.lineBox.width,l.lineBox.height))}),n.forEach(l=>{l.fragments.forEach(e=>{switch(e.style.backgroundColor&&(t.fillStyle=e.style.backgroundColor,t.fillRect(e.inlineBox.left,e.inlineBox.top,e.inlineBox.width,e.inlineBox.height)),this._setContextStyle({...e.style,textAlign:"left",verticalAlign:"top"}),e.style.textStrokeWidth&&t.strokeText(e.content,e.contentBox.left,e.contentBox.top),t.fillText(e.content,e.contentBox.left,e.contentBox.top),e.style.textDecoration){case"underline":t.beginPath(),t.moveTo(e.contentBox.left,e.contentBox.top+e.contentBox.height-2),t.lineTo(e.contentBox.left+e.contentBox.width,e.contentBox.top+e.contentBox.height-2),t.stroke();break;case"line-through":t.beginPath(),t.moveTo(e.contentBox.left,e.contentBox.top+e.contentBox.height/2),t.lineTo(e.contentBox.left+e.contentBox.width,e.contentBox.top+e.contentBox.height/2),t.stroke();break}})})}_resizeView(n,t){const l=this.view;l.style.width=`${n}px`,l.style.height=`${t}px`,l.dataset.width=String(n),l.dataset.height=String(t),l.width=Math.max(1,Math.floor(n*this.pixelRatio)),l.height=Math.max(1,Math.floor(t*this.pixelRatio))}_setContextStyle(n){const t=this.context;switch(t.shadowColor=n.shadowColor,t.shadowOffsetX=n.shadowOffsetX,t.shadowOffsetY=n.shadowOffsetY,t.shadowBlur=n.shadowBlur,t.strokeStyle=n.textStrokeColor,t.lineWidth=n.textStrokeWidth,t.fillStyle=n.color,t.direction=n.direction,t.textAlign=n.textAlign,n.verticalAlign){case"baseline":t.textBaseline="alphabetic";break;case"top":case"middle":case"bottom":t.textBaseline=n.verticalAlign;break}t.font=[n.fontStyle,n.fontWeight,`${n.fontSize}px`,n.fontFamily].join(" "),t.fontKerning=n.fontKerning,t.letterSpacing=`${n.letterSpacing}px`}update(){const n=this.context;let{width:t,height:l}=this.style;t==="auto"&&(t=0),l==="auto"&&(l=0);const{contentBox:e,paragraphs:a}=this.measure();t||(t=e.width),l=Math.max(l,e.height),this._resizeView(t,l);const x=this.pixelRatio;n.scale(x,x),n.clearRect(0,0,n.canvas.width,n.canvas.height),this._draw(a)}}p.Text=g,Object.defineProperty(p,Symbol.toStringTag,{value:"Module"})});
package/dist/index.mjs CHANGED
@@ -24,77 +24,77 @@ class u {
24
24
  shadowBlur: 0
25
25
  };
26
26
  }
27
- constructor(o = {}) {
27
+ constructor(n = {}) {
28
28
  const {
29
29
  view: t = document.createElement("canvas"),
30
30
  pixelRatio: l = window.devicePixelRatio || 1,
31
31
  content: e = "",
32
- style: x
33
- } = o;
32
+ style: a
33
+ } = n;
34
34
  this.view = t, this.context = t.getContext("2d"), this.pixelRatio = l, this.content = e, this.style = {
35
35
  ...u.defaultStyle,
36
- ...x
36
+ ...a
37
37
  }, this.update();
38
38
  }
39
39
  measure() {
40
- let { width: o } = this.style;
41
- o === "auto" && (o = 0);
40
+ let { width: n } = this.style;
41
+ n === "auto" && (n = 0);
42
42
  let t = this._createParagraphs(this.content);
43
- t = this._createWrapedParagraphs(t, o);
43
+ t = this._createWrapedParagraphs(t, n);
44
44
  const l = this.context;
45
45
  let e = 0;
46
- for (let h = t.length, s = 0; s < h; s++) {
47
- const i = t[s];
46
+ for (let h = t.length, c = 0; c < h; c++) {
47
+ const i = t[c];
48
48
  i.contentBox.top = e;
49
- let c = 0, d = null;
50
- for (const n of i.fragments) {
49
+ let s = 0, d = null;
50
+ for (const o of i.fragments) {
51
51
  this._setContextStyle({
52
- ...n.style,
53
- textAlign: "left",
52
+ ...o.style,
53
+ textAlign: "center",
54
54
  verticalAlign: "baseline"
55
55
  });
56
- const r = l.measureText(n.content);
57
- n.inlineBox.left = c, n.inlineBox.top = e, n.inlineBox.width = r.width, n.inlineBox.height = n.style.fontSize * n.style.lineHeight, n.contentBox.left = n.inlineBox.left, n.contentBox.width = n.inlineBox.width, n.contentBox.height = n.style.fontSize, n.contentBox.top = n.inlineBox.top + (n.inlineBox.height - n.contentBox.height) / 2, n.textBox.width = r.actualBoundingBoxLeft + r.actualBoundingBoxRight, n.textBox.height = r.actualBoundingBoxAscent + r.actualBoundingBoxDescent, n.textBox.left = n.contentBox.left + (n.contentBox.width - n.textBox.width) / 2, n.textBox.top = n.contentBox.top + (n.contentBox.height - n.textBox.height) / 2, n.baseline = n.textBox.top + r.actualBoundingBoxAscent, c += n.contentBox.width + n.style.letterSpacing, i.contentBox.height < n.contentBox.height && (d = n), i.contentBox.left = Math.min(i.contentBox.left, n.contentBox.left), i.contentBox.top = Math.min(i.contentBox.top, n.contentBox.top), i.contentBox.height = Math.max(i.contentBox.height, n.contentBox.height), i.lineBox.height = Math.max(i.lineBox.height, n.inlineBox.height);
56
+ const B = l.measureText(o.content), p = B.width, f = o.style.fontSize;
57
+ o.inlineBox.left = s, o.inlineBox.top = e, o.inlineBox.width = p, o.inlineBox.height = f * o.style.lineHeight, o.contentBox.left = o.inlineBox.left, o.contentBox.width = p, o.contentBox.height = f, o.contentBox.top = o.inlineBox.top + (o.inlineBox.height - o.contentBox.height) / 2, o.glyphBox.width = B.actualBoundingBoxLeft + B.actualBoundingBoxRight, o.glyphBox.height = B.actualBoundingBoxAscent + B.actualBoundingBoxDescent, o.glyphBox.left = o.contentBox.left + (o.contentBox.width - o.glyphBox.width) / 2, o.glyphBox.top = o.contentBox.top + (o.contentBox.height - o.glyphBox.height) / 2, o.centerX = o.glyphBox.left + B.actualBoundingBoxLeft, o.baseline = o.glyphBox.top + B.actualBoundingBoxAscent, s += o.contentBox.width + o.style.letterSpacing, i.contentBox.height < o.contentBox.height && (d = o), i.contentBox.left = Math.min(i.contentBox.left, o.contentBox.left), i.contentBox.top = Math.min(i.contentBox.top, o.contentBox.top), i.contentBox.height = Math.max(i.contentBox.height, o.contentBox.height), i.lineBox.height = Math.max(i.lineBox.height, o.inlineBox.height);
58
58
  }
59
- const B = i.fragments[i.fragments.length - 1];
59
+ const r = i.fragments[i.fragments.length - 1];
60
60
  i.contentBox.width = Math.max(
61
61
  i.contentBox.width,
62
- B ? B.contentBox.left + Math.max(B.contentBox.width, B.textBox.width) : 0
63
- ), i.lineBox.left = 0, i.lineBox.top = e, i.lineBox.width = Math.max(o, i.contentBox.width), this._setContextStyle({
62
+ r ? r.contentBox.left + Math.max(r.contentBox.width, r.glyphBox.width) : 0
63
+ ), i.lineBox.left = 0, i.lineBox.top = e, i.lineBox.width = Math.max(n, i.contentBox.width), this._setContextStyle({
64
64
  ...(d ?? i).style,
65
65
  textAlign: "left",
66
66
  verticalAlign: "baseline"
67
67
  });
68
- const f = l.measureText("X");
69
- i.baseline = i.lineBox.top + (i.lineBox.height - f.actualBoundingBoxAscent + f.actualBoundingBoxDescent) / 2 + f.actualBoundingBoxAscent, e += i.lineBox.height;
68
+ const g = l.measureText("X");
69
+ i.baseline = i.lineBox.top + (i.lineBox.height - g.actualBoundingBoxAscent + g.actualBoundingBoxDescent) / 2 + g.actualBoundingBoxAscent, e += i.lineBox.height;
70
70
  }
71
- for (let h = t.length, s = 0; s < h; s++) {
72
- const i = t[s];
73
- i.fragments.forEach((c) => {
74
- const d = c.inlineBox.left, B = c.inlineBox.top, f = i.lineBox.height - c.inlineBox.height;
75
- switch (c.style.textAlign) {
71
+ for (let h = t.length, c = 0; c < h; c++) {
72
+ const i = t[c];
73
+ i.fragments.forEach((s) => {
74
+ const d = s.inlineBox.left, r = s.inlineBox.top, g = i.lineBox.height - s.inlineBox.height;
75
+ switch (s.style.textAlign) {
76
76
  case "end":
77
77
  case "right":
78
- c.inlineBox.left += i.lineBox.width - i.contentBox.width;
78
+ s.inlineBox.left += i.lineBox.width - i.contentBox.width;
79
79
  break;
80
80
  case "center":
81
- c.inlineBox.left += (i.lineBox.width - i.contentBox.width) / 2;
81
+ s.inlineBox.left += (i.lineBox.width - i.contentBox.width) / 2;
82
82
  break;
83
83
  case "start":
84
84
  case "left":
85
85
  default:
86
- c.inlineBox.left += i.lineBox.left;
86
+ s.inlineBox.left += i.lineBox.left;
87
87
  break;
88
88
  }
89
- switch (c.style.verticalAlign) {
89
+ switch (s.style.verticalAlign) {
90
90
  case "top":
91
- c.inlineBox.top = i.lineBox.top;
91
+ s.inlineBox.top = i.lineBox.top;
92
92
  break;
93
93
  case "middle":
94
- c.inlineBox.top = i.lineBox.top + f / 2;
94
+ s.inlineBox.top = i.lineBox.top + g / 2;
95
95
  break;
96
96
  case "bottom":
97
- c.inlineBox.top = i.lineBox.top + f;
97
+ s.inlineBox.top = i.lineBox.top + g;
98
98
  break;
99
99
  case "sub":
100
100
  case "text-top":
@@ -102,104 +102,105 @@ class u {
102
102
  break;
103
103
  case "baseline":
104
104
  default:
105
- c.inlineBox.height < i.lineBox.height && (c.inlineBox.top += i.baseline - c.baseline);
105
+ s.inlineBox.height < i.lineBox.height && (s.inlineBox.top += i.baseline - s.baseline);
106
106
  break;
107
107
  }
108
- const n = c.inlineBox.left - d, r = c.inlineBox.top - B;
109
- c.contentBox.left += n, c.contentBox.top += r, c.textBox.left += n, c.textBox.top += r;
108
+ const o = s.inlineBox.left - d, B = s.inlineBox.top - r;
109
+ s.contentBox.left += o, s.contentBox.top += B, s.glyphBox.left += o, s.glyphBox.top += B, s.baseline += B, s.centerX += o;
110
110
  });
111
111
  }
112
- const x = t.reduce((h, s) => (h.left = Math.min(h.left, s.contentBox.left), h.top = Math.min(h.top, s.contentBox.top), h.width = Math.max(h.width, s.contentBox.width), h.height += s.contentBox.height, h), { left: 0, top: 0, width: 0, height: 0 });
113
- return { lineBox: t.reduce((h, s) => (h.left = Math.min(h.left, s.lineBox.left), h.top = Math.min(h.top, s.lineBox.top), h.width = Math.max(h.width, s.lineBox.width), h.height += s.lineBox.height, h), { left: 0, top: 0, width: 0, height: 0 }), contentBox: x, paragraphs: t };
112
+ const a = t.reduce((h, c) => (h.left = Math.min(h.left, c.contentBox.left), h.top = Math.min(h.top, c.contentBox.top), h.width = Math.max(h.width, c.contentBox.width), h.height += c.contentBox.height, h), { left: 0, top: 0, width: 0, height: 0 });
113
+ return { contentBox: t.reduce((h, c) => (h.left = Math.min(h.left, c.lineBox.left), h.top = Math.min(h.top, c.lineBox.top), h.width = Math.max(h.width, c.lineBox.width), h.height += c.lineBox.height, h), { left: 0, top: 0, width: 0, height: 0 }), actualContentBox: a, paragraphs: t };
114
114
  }
115
- _createParagraphs(o) {
116
- const t = (x = {}) => {
117
- const { width: a, height: h, ...s } = this.style;
115
+ _createParagraphs(n) {
116
+ const t = (a = {}) => {
117
+ const { width: x, height: h, ...c } = this.style;
118
118
  return {
119
119
  contentBox: { left: 0, top: 0, width: 0, height: 0 },
120
120
  lineBox: { left: 0, top: 0, width: 0, height: 0 },
121
121
  baseline: 0,
122
122
  fragments: [],
123
- ...x,
123
+ ...a,
124
124
  style: {
125
- ...s,
126
- ...x.style
125
+ ...c,
126
+ ...a.style
127
127
  }
128
128
  };
129
- }, l = (x = {}) => {
130
- const a = [], { width: h, height: s, ...i } = this.style;
131
- return a.push({
129
+ }, l = (a = {}) => {
130
+ const x = [], { width: h, height: c, ...i } = this.style;
131
+ return x.push({
132
132
  contentBox: { left: 0, top: 0, width: 0, height: 0 },
133
133
  inlineBox: { left: 0, top: 0, width: 0, height: 0 },
134
- textBox: { left: 0, top: 0, width: 0, height: 0 },
134
+ glyphBox: { left: 0, top: 0, width: 0, height: 0 },
135
+ centerX: 0,
135
136
  baseline: 0,
136
- ...x,
137
+ ...a,
137
138
  style: {
138
139
  ...i,
139
- ...x.style
140
+ ...a.style
140
141
  },
141
- content: x.content ?? ""
142
- }), a;
142
+ content: a.content ?? ""
143
+ }), x;
143
144
  }, e = [];
144
- if (typeof o == "string")
145
- e.push(t({ fragments: l({ content: o }) }));
145
+ if (typeof n == "string")
146
+ e.push(t({ fragments: l({ content: n }) }));
146
147
  else {
147
- o = Array.isArray(o) ? o : [o];
148
- for (const x of o)
149
- if ("fragments" in x) {
150
- const { fragments: a, ...h } = x, s = t({ style: h });
151
- for (const i of a) {
152
- const { content: c, ...d } = i;
153
- s.fragments.push(...l({ content: c, style: { ...h, ...d } }));
148
+ n = Array.isArray(n) ? n : [n];
149
+ for (const a of n)
150
+ if ("fragments" in a) {
151
+ const { fragments: x, ...h } = a, c = t({ style: h });
152
+ for (const i of x) {
153
+ const { content: s, ...d } = i;
154
+ c.fragments.push(...l({ content: s, style: { ...h, ...d } }));
154
155
  }
155
- e.push(s);
156
- } else if ("content" in x) {
157
- const { content: a, ...h } = x, s = t({ style: h });
158
- s.fragments.push(...l({ content: a, style: h })), e.push(s);
156
+ e.push(c);
157
+ } else if ("content" in a) {
158
+ const { content: x, ...h } = a, c = t({ style: h });
159
+ c.fragments.push(...l({ content: x, style: h })), e.push(c);
159
160
  }
160
161
  }
161
162
  return e;
162
163
  }
163
- _createWrapedParagraphs(o, t) {
164
- const l = (s) => JSON.parse(JSON.stringify(s)), e = [], x = o.slice();
165
- let a, h;
166
- for (; a = x.shift(); ) {
167
- const s = a.fragments.slice();
164
+ _createWrapedParagraphs(n, t) {
165
+ const l = (c) => JSON.parse(JSON.stringify(c)), e = [], a = n.slice();
166
+ let x, h;
167
+ for (; x = a.shift(); ) {
168
+ const c = x.fragments.slice();
168
169
  let i = 0;
169
- const c = [];
170
- for (; h = s.shift(); ) {
170
+ const s = [];
171
+ for (; h = c.shift(); ) {
171
172
  const d = h.style;
172
173
  this._setContextStyle(d);
173
- let B = "", f = !1;
174
- for (const n of h.content) {
175
- const r = this.context.measureText(n).width, w = /^[\r\n]$/.test(n);
176
- if (w || d.textWrap === "wrap" && t && i + r > t) {
177
- let g = w ? B.length + 1 : B.length;
178
- !i && !g && (B += n, g++), B.length && c.push({ ...l(h), content: B }), c.length && (e.push({
179
- ...l(a),
180
- fragments: c.slice()
181
- }), c.length = 0);
182
- const p = h.content.substring(g);
183
- (p.length || s.length) && x.unshift({
184
- ...l(a),
185
- fragments: (p.length ? [{ ...l(h), content: p }] : []).concat(s.slice())
186
- }), s.length = 0, f = !0;
174
+ let r = "", g = !1;
175
+ for (const o of h.content) {
176
+ const B = this.context.measureText(o).width, p = /^[\r\n]$/.test(o);
177
+ if (p || d.textWrap === "wrap" && t && i + B > t) {
178
+ let f = p ? r.length + 1 : r.length;
179
+ !i && !f && (r += o, f++), r.length && s.push({ ...l(h), content: r }), s.length && (e.push({
180
+ ...l(x),
181
+ fragments: s.slice()
182
+ }), s.length = 0);
183
+ const w = h.content.substring(f);
184
+ (w.length || c.length) && a.unshift({
185
+ ...l(x),
186
+ fragments: (w.length ? [{ ...l(h), content: w }] : []).concat(c.slice())
187
+ }), c.length = 0, g = !0;
187
188
  break;
188
189
  } else
189
- i += r;
190
- B += n;
190
+ i += B;
191
+ r += o;
191
192
  }
192
- f || c.push(l(h));
193
+ g || s.push(l(h));
193
194
  }
194
- c.length && e.push({ ...l(a), fragments: c });
195
+ s.length && e.push({ ...l(x), fragments: s });
195
196
  }
196
197
  return e;
197
198
  }
198
- _draw(o) {
199
+ _draw(n) {
199
200
  const t = this.context;
200
- this.style.backgroundColor && (t.fillStyle = this.style.backgroundColor, t.fillRect(0, 0, t.canvas.width, t.canvas.height)), o.forEach((l) => {
201
+ this.style.backgroundColor && (t.fillStyle = this.style.backgroundColor, t.fillRect(0, 0, t.canvas.width, t.canvas.height)), n.forEach((l) => {
201
202
  l.style.backgroundColor && (t.fillStyle = l.style.backgroundColor, t.fillRect(l.lineBox.left, l.lineBox.top, l.lineBox.width, l.lineBox.height));
202
- }), o.forEach((l) => {
203
+ }), n.forEach((l) => {
203
204
  l.fragments.forEach((e) => {
204
205
  switch (e.style.backgroundColor && (t.fillStyle = e.style.backgroundColor, t.fillRect(e.inlineBox.left, e.inlineBox.top, e.inlineBox.width, e.inlineBox.height)), this._setContextStyle({
205
206
  ...e.style,
@@ -216,37 +217,37 @@ class u {
216
217
  });
217
218
  });
218
219
  }
219
- _resizeView(o, t) {
220
+ _resizeView(n, t) {
220
221
  const l = this.view;
221
- l.style.width = `${o}px`, l.style.height = `${t}px`, l.dataset.width = String(o), l.dataset.height = String(t), l.width = Math.max(1, Math.floor(o * this.pixelRatio)), l.height = Math.max(1, Math.floor(t * this.pixelRatio));
222
+ l.style.width = `${n}px`, l.style.height = `${t}px`, l.dataset.width = String(n), l.dataset.height = String(t), l.width = Math.max(1, Math.floor(n * this.pixelRatio)), l.height = Math.max(1, Math.floor(t * this.pixelRatio));
222
223
  }
223
- _setContextStyle(o) {
224
+ _setContextStyle(n) {
224
225
  const t = this.context;
225
- switch (t.shadowColor = o.shadowColor, t.shadowOffsetX = o.shadowOffsetX, t.shadowOffsetY = o.shadowOffsetY, t.shadowBlur = o.shadowBlur, t.strokeStyle = o.textStrokeColor, t.lineWidth = o.textStrokeWidth, t.fillStyle = o.color, t.direction = o.direction, t.textAlign = o.textAlign, o.verticalAlign) {
226
+ switch (t.shadowColor = n.shadowColor, t.shadowOffsetX = n.shadowOffsetX, t.shadowOffsetY = n.shadowOffsetY, t.shadowBlur = n.shadowBlur, t.strokeStyle = n.textStrokeColor, t.lineWidth = n.textStrokeWidth, t.fillStyle = n.color, t.direction = n.direction, t.textAlign = n.textAlign, n.verticalAlign) {
226
227
  case "baseline":
227
228
  t.textBaseline = "alphabetic";
228
229
  break;
229
230
  case "top":
230
231
  case "middle":
231
232
  case "bottom":
232
- t.textBaseline = o.verticalAlign;
233
+ t.textBaseline = n.verticalAlign;
233
234
  break;
234
235
  }
235
236
  t.font = [
236
- o.fontStyle,
237
- o.fontWeight,
238
- `${o.fontSize}px`,
239
- o.fontFamily
240
- ].join(" "), t.fontKerning = o.fontKerning, t.letterSpacing = `${o.letterSpacing}px`;
237
+ n.fontStyle,
238
+ n.fontWeight,
239
+ `${n.fontSize}px`,
240
+ n.fontFamily
241
+ ].join(" "), t.fontKerning = n.fontKerning, t.letterSpacing = `${n.letterSpacing}px`;
241
242
  }
242
243
  update() {
243
- const o = this.context;
244
+ const n = this.context;
244
245
  let { width: t, height: l } = this.style;
245
246
  t === "auto" && (t = 0), l === "auto" && (l = 0);
246
- const { lineBox: e, paragraphs: x } = this.measure();
247
+ const { contentBox: e, paragraphs: a } = this.measure();
247
248
  t || (t = e.width), l = Math.max(l, e.height), this._resizeView(t, l);
248
- const a = this.pixelRatio;
249
- o.scale(a, a), o.clearRect(0, 0, o.canvas.width, o.canvas.height), this._draw(x);
249
+ const x = this.pixelRatio;
250
+ n.scale(x, x), n.clearRect(0, 0, n.canvas.width, n.canvas.height), this._draw(a);
250
251
  }
251
252
  }
252
253
  export {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "modern-text",
3
3
  "type": "module",
4
- "version": "0.0.7",
4
+ "version": "0.0.9",
5
5
  "packageManager": "pnpm@8.14.1",
6
6
  "description": "Text measurement and rendering of canvas 2d",
7
7
  "author": "wxm",
package/types/Text.d.ts CHANGED
@@ -21,7 +21,8 @@ export interface TextParagraph {
21
21
  export interface TextFragment {
22
22
  contentBox: BoundingBox;
23
23
  inlineBox: BoundingBox;
24
- textBox: BoundingBox;
24
+ glyphBox: BoundingBox;
25
+ centerX: number;
25
26
  baseline: number;
26
27
  content: string;
27
28
  style: TextFragmentStyle;
@@ -68,9 +69,9 @@ export interface TextOptions {
68
69
  content?: TextContent;
69
70
  style?: Partial<TextStyle>;
70
71
  }
71
- export interface MeasureResult {
72
+ export interface Metrics {
72
73
  contentBox: BoundingBox;
73
- lineBox: BoundingBox;
74
+ actualContentBox: BoundingBox;
74
75
  paragraphs: Array<TextParagraph>;
75
76
  }
76
77
  export declare class Text {
@@ -81,7 +82,7 @@ export declare class Text {
81
82
  style: TextStyle;
82
83
  content: TextContent;
83
84
  constructor(options?: TextOptions);
84
- measure(): MeasureResult;
85
+ measure(): Metrics;
85
86
  protected _createParagraphs(content: TextContent): Array<TextParagraph>;
86
87
  protected _createWrapedParagraphs(paragraphs: Array<TextParagraph>, width: number): Array<TextParagraph>;
87
88
  protected _draw(paragraphs: Array<TextParagraph>): void;