UNPKG

@doegis/core

Version:

DOE GIS API

3 lines (1 loc) 8.87 kB
import{clamp as t}from"../../../../core/mathUtils.js";import{isNone as e}from"../../../../core/maybe.js";import i from"../../support/debugFlags.js";class n{constructor(t,e,i,n=2048){this.text=t,this._alignment=e,this._parameters=i,this._maxSize=n,this._textWidths=[],this._lineWidths=[],this._renderPixelRatio=null,this._metricsCached=null,this.key=`TextRenderer-${this._parameters.key}-${this._alignment}--${t}`,this._lines=t.split(/\r?\n/)}get displayWidth(){return Math.ceil(this._displayWidth+2*this._backgroundHorizontalPadding)}get displayHeight(){const t=this._lineSpacing*(this._lines.length-1),e=this._lineHeight;return Math.ceil(t+e+2*this._haloSize+this._backgroundTopPadding+this._backgroundBottomPadding)}get renderedWidth(){return Math.ceil(this._toRenderUnit(this.displayWidth))}get renderedHeight(){return Math.ceil(this._toRenderUnit(this.displayHeight))}get firstRenderedBaselinePosition(){return this._toRenderUnit(this._firstLineYOffset+this._baselinePosition)}get _firstLineYOffset(){return this._backgroundTopPadding+this._haloSize}get _metrics(){if(e(this._metricsCached)){const t=o(h,d,d).getContext("2d");this._setFontProperties(t,this._fontSize);let e=2*this._haloSize;const i=this._parameters.definition.font;"italic"!==i.style&&"oblique"!==i.style&&"bold"!==i.weight&&"bolder"!==i.weight||(e+=.3*t.measureText("A").width),this._textWidths.length=0,this._lineWidths.length=0;let n,s,r=0,a=0,l=0;this._lines.forEach(((i,o)=>{const h=t.measureText(i),d=h.width,_=d+e;this._textWidths.push(d),this._lineWidths.push(_),r=Math.max(r,_),a=Math.max(a,h.actualBoundingBoxAscent),l=Math.max(l,h.actualBoundingBoxDescent),0===o&&(n=h),o===this._lines.length-1&&(s=h)}));const f=t.font;let p=u.get(f);if(!p){const e=t.measureText(_);p=new g(e.actualBoundingBoxAscent,e.actualBoundingBoxDescent),u.set(f,p)}a=Math.max(a,p.actualBoundingBoxAscent),l=Math.max(l,p.actualBoundingBoxDescent);const m=a+l,x=this._hasBackground?n.actualBoundingBoxAscent:a,R=this._hasBackground?s.actualBoundingBoxDescent:l;this._metricsCached=new c(a-x,l-R,m,r,a)}return this._metricsCached}get _lineSpacing(){return(this._lineHeight+this._linePadding)*this._parameters.definition.lineSpacingFactor}get _lineHeight(){return this._metrics.lineHeight}get _linePadding(){return this._lineHeight*a}get _baselinePosition(){return this._metrics.baselinePosition}get _renderedFontSize(){return this._toRenderUnit(this._fontSize)}get _fontSize(){return this._parameters.definition.size}get _renderedHaloSize(){return this._toRenderUnit(this._haloSize)}get _haloSize(){return this._parameters.haloSize}get _backgroundHorizontalPadding(){return this._hasBackground?this._parameters.definition.background.padding[0]:0}get _backgroundVerticalPadding(){return this._hasBackground?this._parameters.definition.background.padding[1]:0}get _backgroundTopPadding(){return Math.max(0,this._backgroundVerticalPadding-this._metrics.paddingTop)}get _backgroundBottomPadding(){return Math.max(0,this._backgroundVerticalPadding-this._metrics.paddingBottom)}get _hasBackground(){return!!this._parameters.backgroundStyle}get renderPixelRatio(){if(e(this._renderPixelRatio)){const t=this._parameters.definition.pixelRatio;this._maxSize>0?this._renderPixelRatio=Math.min(t,Math.min(this._maxSize/this.displayWidth,this._maxSize/this.displayHeight)):this._renderPixelRatio=t}return this._renderPixelRatio}_getLineXOffset(t){switch(this._alignment){case r.Left:return this._backgroundHorizontalPadding;case r.Center:return(this.displayWidth-this._lineWidths[t])/2;case r.Right:return this.displayWidth-this._backgroundHorizontalPadding-this._lineWidths[t]}}render(t,e=0,n=0){t.save();const s=e/=this.renderPixelRatio,r=n/=this.renderPixelRatio,o=this._haloSize,h=this._firstLineYOffset;e+=o,n+=h+this._baselinePosition;const a=this._haloSize>0;a&&this._renderHalo(t,s,r,o,h),this._setFontProperties(t,this._renderedFontSize);for(let i=0;i<this._lines.length;++i){const s=this._lines[i],r=this._getLineXOffset(i);a&&(t.globalCompositeOperation="destination-out",t.fillStyle="rgb(0, 0, 0)",this._fillText(t,s,e+r,n),this._renderLineDecoration(t,e+r,n,this._textWidths[i])),t.globalCompositeOperation="source-over",t.fillStyle=this._parameters.textStyle,this._fillText(t,s,e+this._getLineXOffset(i),n),this._renderLineDecoration(t,e+r,n,this._textWidths[i]),n+=this._lineSpacing}if(i.TEXT_SHOW_BASELINE){t.strokeStyle=l,t.setLineDash([2,2]),t.lineWidth=1;let e=r+h;for(let i=0;i<this._lines.length;++i){const i=e+this._baselinePosition;this._drawLine(t,[s,i],[s+this.displayWidth,i]),e+=this._lineSpacing}}if(i.TEXT_SHOW_BORDER&&(t.strokeStyle=l,t.setLineDash([]),t.lineWidth=1,this._drawBox(t,[s,r],[this.displayWidth,this.displayHeight])),this._hasBackground){const e=this._parameters.definition.background.borderRadius*this.renderPixelRatio;this._roundedRect(t,s,r,e),t.globalCompositeOperation="destination-over",t.fillStyle=this._parameters.backgroundStyle,t.fill()}t.restore()}_renderLineDecoration(t,e,i,n,s=!1){if("none"===this._parameters.definition.font.decoration||0===n)return;const r=1,o=Math.max(this._parameters.definition.size/16,r);switch(this._parameters.definition.font.decoration){case"underline":i+=2*o;break;case"line-through":i-=.33*this._baselinePosition}const h=s?this._haloSize:0;t.strokeStyle=s?this._parameters.haloStyle:this._parameters.textStyle,t.lineWidth=this._toRenderUnit(o+2*h),t.beginPath(),t.moveTo(this._toRenderUnit(e-h),this._toRenderUnit(i)),t.lineTo(this._toRenderUnit(e+n+h),this._toRenderUnit(i)),t.stroke()}_roundedRect(e,i,n,s){i=this._toRenderUnit(i),n=this._toRenderUnit(n);const r=this.renderedWidth,o=this.renderedHeight;0!==s?(s=t(s,0,Math.floor(o/2)),e.beginPath(),e.moveTo(i,n+s),e.arcTo(i,n,i+s,n,s),e.lineTo(i+r-s,n),e.arcTo(i+r,n,i+r,n+s,s),e.lineTo(i+r,n+o-s),e.arcTo(i+r,n+o,i+r-s,n+o,s),e.lineTo(i+s,n+o),e.arcTo(i,n+o,i,n+o-s,s),e.closePath()):e.rect(i,n,r,o)}_renderHalo(t,e,i,n,s){const r=this.renderedWidth,a=this.renderedHeight,l=o(h,Math.max(r,d),Math.max(a,d)),_=l.getContext("2d");_.clearRect(0,0,r,a),this._setFontProperties(_,this._renderedFontSize),_.fillStyle=this._parameters.haloStyle,_.strokeStyle=this._parameters.haloStyle;const c=this._renderedHaloSize<3;_.lineJoin=c?"miter":"round",c?this._renderHaloEmulated(_,n,s):this._renderHaloNative(_,n,s);let g=s+this._baselinePosition;for(let o=0;o<this._lines.length;++o){const t=this._getLineXOffset(o);this._renderLineDecoration(_,n+t,g,this._textWidths[o],!0),g+=this._lineSpacing}t.globalAlpha=this._parameters.definition.halo.color[3],t.drawImage(l,0,0,r,a,this._toRenderUnit(e),this._toRenderUnit(i),r,a),t.globalAlpha=1}_renderHaloEmulated(t,e,i){i+=this._baselinePosition;for(let n=0;n<this._lines.length;++n){const r=this._lines[n],o=this._getLineXOffset(n);for(const[n,h]of s)this._fillText(t,r,e+o+this._haloSize*n,i+this._haloSize*h);i+=this._lineSpacing}}_renderHaloNative(t,e,i){const n=2*this._haloSize;i+=this._baselinePosition;for(let s=0;s<this._lines.length;++s){const r=this._lines[s],o=this._getLineXOffset(s),h=5,a=.1;for(let s=0;s<h;s++){const d=1-(h-1)*a+s*a;t.lineWidth=this._toRenderUnit(d*n),this._strokeText(t,r,e+o,i)}i+=this._lineSpacing}}_setFontProperties(t,e){t.font=this._parameters.fontString(e),t.textAlign="left",t.textBaseline="alphabetic"}get _displayWidth(){return this._metrics.displayWidth}_toRenderUnit(t){return t*this.renderPixelRatio}_toRoundedRenderUnit(t){return Math.round(t*this.renderPixelRatio)}_fillText(t,e,i,n){t.fillText(e,this._toRenderUnit(i),this._toRenderUnit(n))}_strokeText(t,e,i,n){t.strokeText(e,this._toRenderUnit(i),this._toRenderUnit(n))}_drawLine(t,e,i){t.beginPath(),t.moveTo(this._toRoundedRenderUnit(e[0])+.5,this._toRoundedRenderUnit(e[1])+.5),t.lineTo(this._toRoundedRenderUnit(i[0])+.5,this._toRoundedRenderUnit(i[1])+.5),t.stroke()}_drawBox(t,e,i){const n=this._toRenderUnit(e[0]),s=this._toRenderUnit(e[1]),r=this._toRenderUnit(i[0]),o=this._toRenderUnit(i[1]),h=Math.floor(n)+.5,a=Math.ceil(n+r)-.5,d=Math.floor(s)+.5,l=Math.ceil(s+o)-.5;t.beginPath(),t.moveTo(h,d),t.lineTo(a,d),t.lineTo(a,l),t.lineTo(h,l),t.lineTo(h,d),t.stroke()}}const s=[];{const t=16;for(let e=0;e<360;e+=360/t)s.push([Math.cos(Math.PI*e/180),Math.sin(Math.PI*e/180)])}var r;function o(t,e,i){return t.canvas||(t.canvas=document.createElement("canvas")),t.canvas.width=e,t.canvas.height=i,t.canvas}!function(t){t[t.Left=0]="Left",t[t.Center=1]="Center",t[t.Right=2]="Right"}(r||(r={}));const h={canvas:null},a=.2,d=512,l="rgb(255, 0, 255, 0.5)",_=(()=>{let t="";for(let e=32;e<127;e++)t+=String.fromCharCode(e);return t})();class c{constructor(t,e,i,n,s){this.paddingTop=t,this.paddingBottom=e,this.lineHeight=i,this.displayWidth=n,this.baselinePosition=s}}class g{constructor(t,e){this.actualBoundingBoxAscent=t,this.actualBoundingBoxDescent=e}}const u=new Map;export{r as TextRenderAlignment,n as TextRenderer,o as getTextHelperCanvas};