UNPKG

fabric

Version:

Object model for HTML5 canvas, and SVG-to-canvas parser. Backed by jsdom and node-canvas.

3 lines (2 loc) 16.5 kB
import{defineProperty as t,objectSpread2 as e,objectWithoutProperties as i}from"../../../_virtual/_rollupPluginBabelHelpers.min.mjs";import{cache as s}from"../../cache.min.mjs";import{STROKE as n,BOTTOM as h,TOP as r,CENTER as o,RIGHT as l,FILL as a,LEFT as d,DEFAULT_SVG_FONT_SIZE as f}from"../../constants.min.mjs";import{StyledText as c}from"./StyledText.min.mjs";import{SHARED_ATTRIBUTES as g}from"../../parser/attributes.min.mjs";import{parseAttributes as p}from"../../parser/parseAttributes.min.mjs";import{classRegistry as _}from"../../ClassRegistry.min.mjs";import{graphemeSplit as u}from"../../util/lang_string.min.mjs";import{createCanvasElementFor as m}from"../../util/misc/dom.min.mjs";import{hasStyleChanged as x,stylesToArray as S,stylesFromArray as y}from"../../util/misc/textStyles.min.mjs";import{getPathSegmentsInfo as T,getPointOnPath as L}from"../../util/path/index.min.mjs";import"../Object/FabricObject.min.mjs";import{TextSVGExportMixin as O}from"./TextSVGExportMixin.min.mjs";import{applyMixins as w}from"../../util/applyMixins.min.mjs";import{JUSTIFY as C,JUSTIFY_CENTER as k,JUSTIFY_RIGHT as W,JUSTIFY_LEFT as v,TEXT_DECORATION_THICKNESS as H,additionalProps as A,textLayoutProperties as P,textDefaultValues as D}from"./constants.min.mjs";import{isFiller as b}from"../../util/typeAssertions.min.mjs";import{cacheProperties as j}from"../Object/defaultValues.min.mjs";const z=["textAnchor","textDecoration","dx","dy","top","left","fontSize","strokeWidth"];let F;class B extends c{static getDefaults(){return e(e({},super.getDefaults()),B.ownDefaults)}constructor(e,i){super(),t(this,"__charBounds",[]),Object.assign(this,B.ownDefaults),this.setOptions(i),this.styles||(this.styles={}),this.text=e,this.initialized=!0,this.path&&this.setPathInfo(),this.initDimensions(),this.setCoords()}setPathInfo(){const t=this.path;t&&(t.segmentsInfo=T(t.path))}_splitText(){const t=this._splitTextIntoLines(this.text);return this.textLines=t.lines,this._textLines=t.graphemeLines,this._unwrappedTextLines=t._unwrappedLines,this._text=t.graphemeText,t}initDimensions(){this._splitText(),this._clearCache(),this.dirty=!0,this.path?(this.width=this.path.width,this.height=this.path.height):(this.width=this.calcTextWidth()||this.cursorWidth||this.MIN_TEXT_WIDTH,this.height=this.calcTextHeight()),this.textAlign.includes(C)&&this.enlargeSpaces()}enlargeSpaces(){let t,e,i,s,n,h,r;for(let o=0,l=this._textLines.length;o<l;o++)if((this.textAlign===C||o!==l-1&&!this.isEndOfWrapping(o))&&(s=0,n=this._textLines[o],e=this.getLineWidth(o),e<this.width&&(r=this.textLines[o].match(this._reSpacesAndTabs)))){i=r.length,t=(this.width-e)/i;for(let e=0;e<=n.length;e++)h=this.__charBounds[o][e],this._reSpaceAndTab.test(n[e])?(h.width+=t,h.kernedWidth+=t,h.left+=s,s+=t):h.left+=s}}isEndOfWrapping(t){return t===this._textLines.length-1}missingNewlineOffset(t){return 1}get2DCursorLocation(t,e){const i=e?this._unwrappedTextLines:this._textLines;let s;for(s=0;s<i.length;s++){if(t<=i[s].length)return{lineIndex:s,charIndex:t};t-=i[s].length+this.missingNewlineOffset(s,e)}return{lineIndex:s-1,charIndex:i[s-1].length<t?i[s-1].length:t}}toString(){return"#<Text (".concat(this.complexity(),'): { "text": "').concat(this.text,'", "fontFamily": "').concat(this.fontFamily,'" }>')}_getCacheCanvasDimensions(){const t=super._getCacheCanvasDimensions(),e=this.fontSize;return t.width+=e*t.zoomX,t.height+=e*t.zoomY,t}_render(t){const e=this.path;e&&!e.isNotVisible()&&e._render(t),this._setTextStyles(t),this._renderTextLinesBackground(t),this._renderTextDecoration(t,"underline"),this._renderText(t),this._renderTextDecoration(t,"overline"),this._renderTextDecoration(t,"linethrough")}_renderText(t){this.paintFirst===n?(this._renderTextStroke(t),this._renderTextFill(t)):(this._renderTextFill(t),this._renderTextStroke(t))}_setTextStyles(t,e,i){if(t.textBaseline="alphabetic",this.path)switch(this.pathAlign){case o:t.textBaseline="middle";break;case"ascender":t.textBaseline=r;break;case"descender":t.textBaseline=h}t.font=this._getFontDeclaration(e,i)}calcTextWidth(){let t=this.getLineWidth(0);for(let e=1,i=this._textLines.length;e<i;e++){const i=this.getLineWidth(e);i>t&&(t=i)}return t}_renderTextLine(t,e,i,s,n,h){this._renderChars(t,e,i,s,n,h)}_renderTextLinesBackground(t){if(!this.textBackgroundColor&&!this.styleHas("textBackgroundColor"))return;const e=t.fillStyle,i=this._getLeftOffset();let s=this._getTopOffset();for(let e=0,n=this._textLines.length;e<n;e++){const n=this.getHeightOfLine(e);if(!this.textBackgroundColor&&!this.styleHas("textBackgroundColor",e)){s+=n;continue}const h=this._textLines[e].length,r=this._getLineLeftOffset(e);let o,l,a=0,d=0,f=this.getValueOfPropertyAt(e,0,"textBackgroundColor");for(let c=0;c<h;c++){const h=this.__charBounds[e][c];l=this.getValueOfPropertyAt(e,c,"textBackgroundColor"),this.path?(t.save(),t.translate(h.renderLeft,h.renderTop),t.rotate(h.angle),t.fillStyle=l,l&&t.fillRect(-h.width/2,-n/this.lineHeight*(1-this._fontSizeFraction),h.width,n/this.lineHeight),t.restore()):l!==f?(o=i+r+d,"rtl"===this.direction&&(o=this.width-o-a),t.fillStyle=f,f&&t.fillRect(o,s,a,n/this.lineHeight),d=h.left,a=h.width,f=l):a+=h.kernedWidth}l&&!this.path&&(o=i+r+d,"rtl"===this.direction&&(o=this.width-o-a),t.fillStyle=l,t.fillRect(o,s,a,n/this.lineHeight)),s+=n}t.fillStyle=e,this._removeShadow(t)}_measureChar(t,e,i,n){const h=s.getFontCache(e),r=this._getFontDeclaration(e),o=i+t,l=i&&r===this._getFontDeclaration(n),a=e.fontSize/this.CACHE_FONT_SIZE;let d,f,c,g;if(i&&void 0!==h[i]&&(c=h[i]),void 0!==h[t]&&(g=d=h[t]),l&&void 0!==h[o]&&(f=h[o],g=f-c),void 0===d||void 0===c||void 0===f){const s=function(){if(!F){const t=m({width:0,height:0});F=t.getContext("2d")}return F}();this._setTextStyles(s,e,!0),void 0===d&&(g=d=s.measureText(t).width,h[t]=d),void 0===c&&l&&i&&(c=s.measureText(i).width,h[i]=c),l&&void 0===f&&(f=s.measureText(o).width,h[o]=f,g=f-c)}return{width:d*a,kernedWidth:g*a}}getHeightOfChar(t,e){return this.getValueOfPropertyAt(t,e,"fontSize")}measureLine(t){const e=this._measureLine(t);return 0!==this.charSpacing&&(e.width-=this._getWidthOfCharSpacing()),e.width<0&&(e.width=0),e}_measureLine(t){let e,i,s=0;const n=this.pathSide===l,h=this.path,r=this._textLines[t],a=r.length,f=new Array(a);this.__charBounds[t]=f;for(let n=0;n<a;n++){const h=r[n];i=this._getGraphemeBox(h,t,n,e),f[n]=i,s+=i.kernedWidth,e=h}if(f[a]={left:i?i.left+i.width:0,width:0,kernedWidth:0,height:this.fontSize,deltaY:0},h&&h.segmentsInfo){let t=0;const e=h.segmentsInfo[h.segmentsInfo.length-1].length;switch(this.textAlign){case d:t=n?e-s:0;break;case o:t=(e-s)/2;break;case l:t=n?0:e-s}t+=this.pathStartOffset*(n?-1:1);for(let s=n?a-1:0;n?s>=0:s<a;n?s--:s++)i=f[s],t>e?t%=e:t<0&&(t+=e),this._setGraphemeOnPath(t,i),t+=i.kernedWidth}return{width:s,numOfSpaces:0}}_setGraphemeOnPath(t,e){const i=t+e.kernedWidth/2,s=this.path,n=L(s.path,i,s.segmentsInfo);e.renderLeft=n.x-s.pathOffset.x,e.renderTop=n.y-s.pathOffset.y,e.angle=n.angle+(this.pathSide===l?Math.PI:0)}_getGraphemeBox(t,e,i,s,n){const h=this.getCompleteStyleDeclaration(e,i),r=s?this.getCompleteStyleDeclaration(e,i-1):{},o=this._measureChar(t,h,s,r);let l,a=o.kernedWidth,d=o.width;0!==this.charSpacing&&(l=this._getWidthOfCharSpacing(),d+=l,a+=l);const f={width:d,left:0,height:h.fontSize,kernedWidth:a,deltaY:h.deltaY};if(i>0&&!n){const t=this.__charBounds[e][i-1];f.left=t.left+t.width+o.kernedWidth-o.width}return f}getHeightOfLine(t){if(this.__lineHeights[t])return this.__lineHeights[t];let e=this.getHeightOfChar(t,0);for(let i=1,s=this._textLines[t].length;i<s;i++)e=Math.max(this.getHeightOfChar(t,i),e);return this.__lineHeights[t]=e*this.lineHeight*this._fontSizeMult}calcTextHeight(){let t,e=0;for(let i=0,s=this._textLines.length;i<s;i++)t=this.getHeightOfLine(i),e+=i===s-1?t/this.lineHeight:t;return e}_getLeftOffset(){return"ltr"===this.direction?-this.width/2:this.width/2}_getTopOffset(){return-this.height/2}_renderTextCommon(t,e){t.save();let i=0;const s=this._getLeftOffset(),n=this._getTopOffset();for(let h=0,r=this._textLines.length;h<r;h++){const r=this.getHeightOfLine(h),o=r/this.lineHeight,l=this._getLineLeftOffset(h);this._renderTextLine(e,t,this._textLines[h],s+l,n+i+o,h),i+=r}t.restore()}_renderTextFill(t){(this.fill||this.styleHas(a))&&this._renderTextCommon(t,"fillText")}_renderTextStroke(t){(this.stroke&&0!==this.strokeWidth||!this.isEmptyStyles())&&(this.shadow&&!this.shadow.affectStroke&&this._removeShadow(t),t.save(),this._setLineDash(t,this.strokeDashArray),t.beginPath(),this._renderTextCommon(t,"strokeText"),t.closePath(),t.restore())}_renderChars(t,e,i,s,n,h){const r=this.getHeightOfLine(h),o=this.textAlign.includes(C),a=this.path,f=!o&&0===this.charSpacing&&this.isEmptyStyles(h)&&!a,c="ltr"===this.direction,g="ltr"===this.direction?1:-1,p=e.direction;let _,u,m,S,y,T="",L=0;if(e.save(),p!==this.direction&&(e.canvas.setAttribute("dir",c?"ltr":"rtl"),e.direction=c?"ltr":"rtl",e.textAlign=c?d:l),n-=r*this._fontSizeFraction/this.lineHeight,f)return this._renderChar(t,e,h,0,i.join(""),s,n),void e.restore();for(let r=0,l=i.length-1;r<=l;r++)S=r===l||this.charSpacing||a,T+=i[r],m=this.__charBounds[h][r],0===L?(s+=g*(m.kernedWidth-m.width),L+=m.width):L+=m.kernedWidth,o&&!S&&this._reSpaceAndTab.test(i[r])&&(S=!0),S||(_=_||this.getCompleteStyleDeclaration(h,r),u=this.getCompleteStyleDeclaration(h,r+1),S=x(_,u,!1)),S&&(a?(e.save(),e.translate(m.renderLeft,m.renderTop),e.rotate(m.angle),this._renderChar(t,e,h,r,T,-L/2,0),e.restore()):(y=s,this._renderChar(t,e,h,r,T,y,n)),T="",_=u,s+=g*L,L=0);e.restore()}_applyPatternGradientTransformText(t){const e=this.width+this.strokeWidth,i=this.height+this.strokeWidth,s=m({width:e,height:i}),n=s.getContext("2d");return s.width=e,s.height=i,n.beginPath(),n.moveTo(0,0),n.lineTo(e,0),n.lineTo(e,i),n.lineTo(0,i),n.closePath(),n.translate(e/2,i/2),n.fillStyle=t.toLive(n),this._applyPatternGradientTransform(n,t),n.fill(),n.createPattern(s,"no-repeat")}handleFiller(t,e,i){let s,n;return b(i)?"percentage"===i.gradientUnits||i.gradientTransform||i.patternTransform?(s=-this.width/2,n=-this.height/2,t.translate(s,n),t[e]=this._applyPatternGradientTransformText(i),{offsetX:s,offsetY:n}):(t[e]=i.toLive(t),this._applyPatternGradientTransform(t,i)):(t[e]=i,{offsetX:0,offsetY:0})}_setStrokeStyles(t,e){let{stroke:i,strokeWidth:s}=e;return t.lineWidth=s,t.lineCap=this.strokeLineCap,t.lineDashOffset=this.strokeDashOffset,t.lineJoin=this.strokeLineJoin,t.miterLimit=this.strokeMiterLimit,this.handleFiller(t,"strokeStyle",i)}_setFillStyles(t,e){let{fill:i}=e;return this.handleFiller(t,"fillStyle",i)}_renderChar(t,e,i,s,n,h,r){const o=this._getStyleDeclaration(i,s),l=this.getCompleteStyleDeclaration(i,s),a="fillText"===t&&l.fill,d="strokeText"===t&&l.stroke&&l.strokeWidth;if(d||a){if(e.save(),e.font=this._getFontDeclaration(l),o.textBackgroundColor&&this._removeShadow(e),o.deltaY&&(r+=o.deltaY),a){const t=this._setFillStyles(e,l);e.fillText(n,h-t.offsetX,r-t.offsetY)}if(d){const t=this._setStrokeStyles(e,l);e.strokeText(n,h-t.offsetX,r-t.offsetY)}e.restore()}}setSuperscript(t,e){this._setScript(t,e,this.superscript)}setSubscript(t,e){this._setScript(t,e,this.subscript)}_setScript(t,e,i){const s=this.get2DCursorLocation(t,!0),n=this.getValueOfPropertyAt(s.lineIndex,s.charIndex,"fontSize"),h=this.getValueOfPropertyAt(s.lineIndex,s.charIndex,"deltaY"),r={fontSize:n*i.size,deltaY:h+n*i.baseline};this.setSelectionStyles(r,t,e)}_getLineLeftOffset(t){const e=this.getLineWidth(t),i=this.width-e,s=this.textAlign,n=this.direction,h=this.isEndOfWrapping(t);let r=0;return s===C||s===k&&!h||s===W&&!h||s===v&&!h?0:(s===o&&(r=i/2),s===l&&(r=i),s===k&&(r=i/2),s===W&&(r=i),"rtl"===n&&(s===l||s===C||s===W?r=0:s===d||s===v?r=-i:s!==o&&s!==k||(r=-i/2)),r)}_clearCache(){this._forceClearCache=!1,this.__lineWidths=[],this.__lineHeights=[],this.__charBounds=[]}getLineWidth(t){if(void 0!==this.__lineWidths[t])return this.__lineWidths[t];const{width:e}=this.measureLine(t);return this.__lineWidths[t]=e,e}_getWidthOfCharSpacing(){return 0!==this.charSpacing?this.fontSize*this.charSpacing/1e3:0}getValueOfPropertyAt(t,e,i){var s;return null!==(s=this._getStyleDeclaration(t,e)[i])&&void 0!==s?s:this[i]}_renderTextDecoration(t,e){if(!this[e]&&!this.styleHas(e))return;let i=this._getTopOffset();const s=this._getLeftOffset(),n=this.path,h=this._getWidthOfCharSpacing(),r="linethrough"===e?.5:"overline"===e?1:0,o=this.offsets[e];for(let l=0,d=this._textLines.length;l<d;l++){const d=this.getHeightOfLine(l);if(!this[e]&&!this.styleHas(e,l)){i+=d;continue}const f=this._textLines[l],c=d/this.lineHeight,g=this._getLineLeftOffset(l);let p=0,_=0,u=this.getValueOfPropertyAt(l,0,e),m=this.getValueOfPropertyAt(l,0,a),x=this.getValueOfPropertyAt(l,0,H),S=u,y=m,T=x;const L=i+c*(1-this._fontSizeFraction);let O=this.getHeightOfChar(l,0),w=this.getValueOfPropertyAt(l,0,"deltaY");for(let i=0,h=f.length;i<h;i++){const h=this.__charBounds[l][i];S=this.getValueOfPropertyAt(l,i,e),y=this.getValueOfPropertyAt(l,i,a),T=this.getValueOfPropertyAt(l,i,H);const d=this.getHeightOfChar(l,i),f=this.getValueOfPropertyAt(l,i,"deltaY");if(n&&S&&y){const e=this.fontSize*T/1e3;t.save(),t.fillStyle=m,t.translate(h.renderLeft,h.renderTop),t.rotate(h.angle),t.fillRect(-h.kernedWidth/2,o*d+f-r*e,h.kernedWidth,e),t.restore()}else if((S!==u||y!==m||d!==O||T!==x||f!==w)&&_>0){const e=this.fontSize*x/1e3;let i=s+g+p;"rtl"===this.direction&&(i=this.width-i-_),u&&m&&x&&(t.fillStyle=m,t.fillRect(i,L+o*O+w-r*e,_,e)),p=h.left,_=h.width,u=S,x=T,m=y,O=d,w=f}else _+=h.kernedWidth}let C=s+g+p;"rtl"===this.direction&&(C=this.width-C-_),t.fillStyle=y;const k=this.fontSize*T/1e3;S&&y&&T&&t.fillRect(C,L+o*O+w-r*k,_-h,k),i+=d}this._removeShadow(t)}_getFontDeclaration(){let{fontFamily:t=this.fontFamily,fontStyle:e=this.fontStyle,fontWeight:i=this.fontWeight,fontSize:s=this.fontSize}=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=arguments.length>1?arguments[1]:void 0;const h=t.includes("'")||t.includes('"')||t.includes(",")||B.genericFonts.includes(t.toLowerCase())?t:'"'.concat(t,'"');return[e,i,"".concat(n?this.CACHE_FONT_SIZE:s,"px"),h].join(" ")}render(t){this.visible&&(this.canvas&&this.canvas.skipOffscreen&&!this.group&&!this.isOnScreen()||(this._forceClearCache&&this.initDimensions(),super.render(t)))}graphemeSplit(t){return u(t)}_splitTextIntoLines(t){const e=t.split(this._reNewline),i=new Array(e.length),s=["\n"];let n=[];for(let t=0;t<e.length;t++)i[t]=this.graphemeSplit(e[t]),n=n.concat(i[t],s);return n.pop(),{_unwrappedLines:i,lines:e,graphemeText:n,graphemeLines:i}}toObject(){let t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[];return e(e({},super.toObject([...A,...t])),{},{styles:S(this.styles,this.text)},this.path?{path:this.path.toObject()}:{})}set(t,e){const{textLayoutProperties:i}=this.constructor;super.set(t,e);let s=!1,n=!1;if("object"==typeof t)for(const e in t)"path"===e&&this.setPathInfo(),s=s||i.includes(e),n=n||"path"===e;else s=i.includes(t),n="path"===t;return n&&this.setPathInfo(),s&&this.initialized&&(this.initDimensions(),this.setCoords()),this}complexity(){return 1}static async fromElement(t,s,n){const h=p(t,B.ATTRIBUTE_NAMES,n),r=e(e({},s),h),{textAnchor:a=d,textDecoration:c="",dx:g=0,dy:_=0,top:u=0,left:m=0,fontSize:x=f,strokeWidth:S=1}=r,y=i(r,z),T=new this((t.textContent||"").replace(/^\s+|\s+$|\n+/g,"").replace(/\s+/g," "),e({left:m+g,top:u+_,underline:c.includes("underline"),overline:c.includes("overline"),linethrough:c.includes("line-through"),strokeWidth:0,fontSize:x},y)),L=T.getScaledHeight()/T.height,O=((T.height+T.strokeWidth)*T.lineHeight-T.height)*L,w=T.getScaledHeight()+O;let C=0;return a===o&&(C=T.getScaledWidth()/2),a===l&&(C=T.getScaledWidth()),T.set({left:T.left-C,top:T.top-(w-T.fontSize*(.07+T._fontSizeFraction))/T.lineHeight,strokeWidth:S}),T}static fromObject(t){return this._fromObject(e(e({},t),{},{styles:y(t.styles||{},t.text)}),{extraParam:"text"})}}t(B,"textLayoutProperties",P),t(B,"cacheProperties",[...j,...A]),t(B,"ownDefaults",D),t(B,"type","Text"),t(B,"genericFonts",["serif","sans-serif","monospace","cursive","fantasy","system-ui","ui-serif","ui-sans-serif","ui-monospace","ui-rounded","math","emoji","fangsong"]),t(B,"ATTRIBUTE_NAMES",g.concat("x","y","dx","dy","font-family","font-style","font-weight","font-size","letter-spacing","text-decoration","text-anchor")),w(B,[O]),_.setClass(B),_.setSVGClass(B);export{B as FabricText}; //# sourceMappingURL=Text.min.mjs.map