@arcgis/core
Version:
ArcGIS Maps SDK for JavaScript: A complete 2D and 3D mapping and data visualization API
6 lines (5 loc) • 6.68 kB
JavaScript
/*
All material copyright ESRI, All Rights Reserved, unless otherwise specified.
See https://js.arcgis.com/4.33/esri/copyright.txt for details.
*/
import{pt2px as e}from"../../core/screenUtils.js";import{backgroundPadding as t}from"../support/textUtils.js";function i(e){return`rgb(${e.slice(0,3).toString()})`}function n(e){return`rgba(${e.slice(0,3).toString()},${e[3]})`}class s{constructor(e){e&&(this._textRasterizationCanvas=e)}rasterizeText(e,s){this._textRasterizationCanvas||(this._textRasterizationCanvas=document.createElement("canvas"));const a=this._textRasterizationCanvas,h=a.getContext("2d",{willReadFrequently:!0});r(h,s),this._parameters=s,this._textLines=e.split(/\r?\n/),this._lineHeight=this._computeLineHeight();const{decoration:l,weight:d}=s.font;this._lineThroughWidthOffset=l&&"line-through"===l?.1*this._lineHeight:0;const c=null!=s.backgroundColor||null!=s.borderLine,_=c?t:0,u=this._computeTextWidth(h,s)+2*_,g=this._lineHeight*this._textLines.length+2*_;if(a.width=u+2*this._lineThroughWidthOffset,a.height=g,0===a.width||0===a.height)return a.width=a.height=1,{size:[0,0],image:new Uint32Array(0),sdf:!1,simplePattern:!1,anchorX:0,anchorY:0,canvas:a};this._renderedLineHeight=Math.round(this._lineHeight),this._renderedOutlineSize=(s.outline.size||0)*s.pixelRatio,this._renderedHaloSize=(s.halo.size||0)*s.pixelRatio,this._renderedWidth=u,this._renderedHeight=g,this._lineThroughWidthOffset*=s.pixelRatio;const f=(s.outline&&s.outline.color)??[0,0,0,0],m=s.color??[0,0,0,0],p=s.halo&&s.halo.color?s.halo.color:[0,0,0,0];this._fillStyle=n(m),this._outlineStyle=n(f),this._haloStyle=i(p);const x=this._renderedLineHeight,z=this._renderedOutlineSize,b=this._renderedHaloSize;h.save(),h.clearRect(0,0,a.width,a.height),r(h,s);const w=_*s.pixelRatio,v=o(h.textAlign,this._renderedWidth-2*w,this._renderedHaloSize+this._renderedOutlineSize)+w,S=b+z+w,y=b>0;let R=this._lineThroughWidthOffset,C=0;if(c){h.save();const e=s.backgroundColor??[0,0,0,0],t=s.borderLine?.color??[0,0,0,0],i=2*(s.borderLine?.size??0);h.fillStyle=n(e),h.strokeStyle=n(t),h.lineWidth=i,h.fillRect(0,0,a.width,a.height),h.strokeRect(0,0,a.width,a.height),h.restore()}y&&this._renderHalo(h,v,S,R,C,s),z>0&&this._renderOutline(h,v,S,R,C,s),C+=S,R+=v;for(const t of this._textLines)y?(h.globalCompositeOperation="destination-out",h.fillStyle="rgb(0, 0, 0)",h.fillText(t,R,C),h.globalCompositeOperation="source-over",h.fillStyle=this._fillStyle,h.fillText(t,R,C)):(h.fillStyle=this._fillStyle,h.fillText(t,R,C)),l&&"none"!==l&&this._renderDecoration(h,R,C,l,d),C+=x;h.restore();const H=this._renderedWidth+2*this._lineThroughWidthOffset,W=this._renderedHeight,T=h.getImageData(0,0,H,W),k=new Uint8Array(T.data);if(s.premultiplyColors){let e;for(let t=0;t<k.length;t+=4)e=k[t+3]/255,k[t]=k[t]*e,k[t+1]=k[t+1]*e,k[t+2]=k[t+2]*e}let L,O;switch(s.horizontalAlignment){case"left":L=-.5;break;case"right":L=.5;break;default:L=0}switch(s.verticalAlignment){case"bottom":O=-.5;break;case"top":O=.5;break;case"baseline":O=-1/6;break;default:O=0}return{size:[H,W],image:new Uint32Array(k.buffer),sdf:!1,simplePattern:!1,anchorX:L,anchorY:O,canvas:a}}_renderHalo(e,t,i,n,s,o){const a=this._renderedWidth,h=this._renderedHeight;this._outlineRasterizationCanvas||(this._outlineRasterizationCanvas=document.createElement("canvas")),this._outlineRasterizationCanvas.width=a,this._outlineRasterizationCanvas.height=h;const l=this._outlineRasterizationCanvas,d=l.getContext("2d");d.clearRect(0,0,a,h),r(d,o);const{decoration:c,weight:_}=o.font;d.fillStyle=this._haloStyle,d.strokeStyle=this._haloStyle,d.lineJoin="round",this._renderOutlineNative(d,t,i,c,_,this._renderedHaloSize+this._renderedOutlineSize),e.globalAlpha=this._parameters.halo.color[3],e.drawImage(l,0,0,a,h,n,s,a,h),e.globalAlpha=1}_renderOutline(e,t,i,n,s,o){const a=this._renderedWidth,h=this._renderedHeight;this._outlineRasterizationCanvas||(this._outlineRasterizationCanvas=document.createElement("canvas")),this._outlineRasterizationCanvas.width=a,this._outlineRasterizationCanvas.height=h;const l=this._outlineRasterizationCanvas,d=l.getContext("2d");d.clearRect(0,0,a,h),r(d,o);const{decoration:c,weight:_}=o.font;d.fillStyle=this._outlineStyle,d.strokeStyle=this._outlineStyle,d.lineJoin="round",this._renderOutlineNative(d,t,i,c,_,this._renderedOutlineSize),e.globalAlpha=this._parameters.outline.color[3],e.drawImage(l,0,0,a,h,n,s,a,h),e.globalAlpha=1}_renderOutlineNative(e,t,i,n,s,r){const o=this._renderedLineHeight;for(const a of this._textLines){const h=2*r,l=5,d=.1;for(let r=0;r<l;r++){const o=(1-(l-1)*d+r*d)*h;e.lineWidth=o,e.strokeText(a,t,i),n&&"none"!==n&&this._renderDecoration(e,t,i,n,s,o)}i+=o}}computeTextSize(e,t){this._textRasterizationCanvas||(this._textRasterizationCanvas=document.createElement("canvas"));const i=this._textRasterizationCanvas,n=i.getContext("2d");r(n,t),this._parameters=t,this._textLines=e.split(/\r?\n/),this._lineHeight=this._computeLineHeight();const s=this._computeTextWidth(n,t),o=this._lineHeight*this._textLines.length;return i.width=s,i.height=o,[s*t.pixelRatio,o*t.pixelRatio]}_computeTextWidth(t,i){let n=0;for(const e of this._textLines)n=Math.max(n,t.measureText(e).width);const s=i.font;return("italic"===s.style||"oblique"===s.style||"string"==typeof s.weight&&("bold"===s.weight||"bolder"===s.weight)||"number"==typeof s.weight&&s.weight>600)&&(n+=.3*t.measureText("w").width),n+=2*e(this._parameters.halo.size),Math.round(n)}_computeLineHeightBase(){return 1.275*this._parameters.size}_computeLineHeight(){let t=this._computeLineHeightBase();const i=this._parameters.font.decoration;return i&&"underline"===i&&(t*=1.3),Math.round(t+2*e(this._parameters.halo.size))}_renderDecoration(e,t,i,n,s,r){let o=.9*this._lineHeight;const a="bold"===s?.06:"bolder"===s?.09:.04;switch(e.textAlign){case"center":t-=this._renderedWidth/2;break;case"right":t-=this._renderedWidth}const h=e.textBaseline;if("underline"===n)switch(o=.9*this._computeLineHeightBase(),h){case"top":i+=o;break;case"middle":i+=o/2}else if("line-through"===n)switch(h){case"top":i+=o/1.5;break;case"middle":i+=o/3}const l=r?1.5*r:Math.ceil(o*a);e.save(),e.beginPath(),e.strokeStyle=e.fillStyle,e.lineWidth=l,e.moveTo(t-this._lineThroughWidthOffset,i),e.lineTo(t+this._renderedWidth+2*this._lineThroughWidthOffset,i),e.stroke(),e.restore()}}function r(t,i){const n=Math.max(i.size,.5),s=i.font,r=`${s.style} ${s.weight} ${e(n).toFixed(1)}px ${s.family}, sans-serif`;let o;switch(t.font=r,t.textBaseline="top",i.horizontalAlignment){case"left":default:o="left";break;case"right":o="right";break;case"center":o="center"}t.textAlign=o}function o(e,t,i){return"center"===e?.5*t:"right"===e?t-i:i}export{s as default};