text-metrics
Version:
An efficient text measurement set for the browser.
3 lines (2 loc) • 8.78 kB
JavaScript
function e(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),r.push.apply(r,n)}return r}function t(t){for(var r=1;r<arguments.length;r++){var n=null!=arguments[r]?arguments[r]:{};r%2?e(Object(n),!0).forEach(function(e){var r,s,i;r=t,i=n[e],(s=function(e){var t=function(e,t){if("object"!=typeof e||null===e)return e;var r=e[Symbol.toPrimitive];if(void 0!==r){var n=r.call(e,"string");if("object"!=typeof n)return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(e)}(e);return"symbol"==typeof t?t:String(t)}(s=e))in r?Object.defineProperty(r,s,{value:i,enumerable:!0,configurable:!0,writable:!0}):r[s]=i}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(n)):e(Object(n)).forEach(function(e){Object.defineProperty(t,e,Object.getOwnPropertyDescriptor(n,e))})}return t}const r=new Set(["—"]),n=new Set([""]),s=new Set([" "," "," "," "," "," "," "," "," "," "," "," "," "," ","\t","","\u2028","\u2029"]),i=new Set(["֊","‐","‒","–","־","་","፡","៘","៚","‧","|","᛫","᛬","᛭","⁖","⁘","⁙","⁚","⁛","⁝","⁞","⸙","⸪","⸫","⸬","⸭","⸰","တ0","တ1","တ2","္F","ွ0","႑F","ቇ0"]),o=new Set(["´","´"]),a=new Set(["\n"]);function l(e,t){t||(t={});const r=Number.parseInt(x(t,"base-font-size",16),10),n=Number.parseFloat(e),s=e.replace(n,"");switch(s){case"rem":case"em":return n*r;case"pt":return n*(96/72);case"px":return n}throw new Error("The unit "+s+" is not supported")}function c(e,t){const r=new Set(["inherit","initial","unset","normal"]);let n=0;e&&!r.has(e)&&(n=l(e));let s=0;return t&&!r.has(t)&&(s=l(t)),e=>(e.trim().replace(/\s+/gi," ").split(" ").length-1)*n+e.length*s}function u(e,t){const r=[],n=x(t,"font-weight",e.getPropertyValue("font-weight"))||"400";["normal","bold","bolder","lighter","100","200","300","400","500","600","700","800","900"].includes(n.toString())&&r.push(n);const s=x(t,"font-style",e.getPropertyValue("font-style"));["normal","italic","oblique"].includes(s)&&r.push(s);const i=x(t,"font-variant",e.getPropertyValue("font-variant"));["normal","small-caps"].includes(i)&&r.push(i);const o=l(x(t,"font-size",e.getPropertyValue("font-size"))||"16px");r.push(o+"px");const a=x(t,"font-family",e.getPropertyValue("font-family"))||"Helvetica, Arial, sans-serif";return r.push(a),r.join(" ")}function p(e){return e&&"function"==typeof e.getPropertyValue}function h(e){return f(e)&&e.style&&"undefined"!=typeof window&&"function"==typeof window.getComputedStyle}function f(e){return"object"==typeof HTMLElement?e instanceof HTMLElement:Boolean(e&&"object"==typeof e&&null!==e&&1===e.nodeType&&"string"==typeof e.nodeName)}function d(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}function g(e,r){const n=t({},r),{style:s}=n;return r||(r={}),p(s)?s:h(e)?window.getComputedStyle(e,x(r,"pseudoElt",null)):{getPropertyValue:e=>x(r,e)}}function y(e,t){switch(t){case"pre":case"pre-wrap":return e;case"pre-line":return(e||"").replace(/\s+/gm," ").trim();default:return(e||"").replace(/[\r\n]/gm," ").replace(/\s+/gm," ").trim()}}function w(e,t){switch(t.getPropertyValue("text-transform")){case"uppercase":return e.toUpperCase();case"lowercase":return e.toLowerCase();default:return e}}function m(e){return e=(e||"").replace(/<wbr>/gi,"").replace(/<br\s*\/?>/gi,"\n").replace(/­/gi,"").replace(/—/gi,"—"),/&#(\d+)(;?)|&#[xX]([a-fA-F\d]+)(;?)|&([\da-zA-Z]+);/g.test(e)&&console&&console.error("text-metrics: Found encoded htmlenties. You may want to use https://mths.be/he to decode your text first."),e}function b(e){return e&&(e.textContent||e.textContent)||""}function x(e,t,r){return e&&void 0!==e[t]&&e[t]||r}function S(e){const t={};for(const r of Object.keys(e||{}))t[r.replace(/([A-Z])/g,e=>"-"+e.toLowerCase())]=e[r];return t}function v(e){try{const t=document.createElement("canvas").getContext("2d"),r=window.devicePixelRatio||1,n=t.webkitBackingStorePixelRatio||t.mozBackingStorePixelRatio||t.msBackingStorePixelRatio||t.oBackingStorePixelRatio||t.backingStorePixelRatio||1;return t.font=e,t.setTransform(r/n,0,0,r/n,0,0),t}catch(e){throw new Error("Canvas support required"+e.message)}}function P(e){return(r.has(e)?"B2":s.has(e)&&"BAI")||n.has(e)&&"SHY"||i.has(e)&&"BA"||o.has(e)&&"BB"||a.has(e)&&"BK"}function B({ctx:e,text:t,max:r,wordSpacing:n,letterSpacing:s}){const i=c(n,s),o=[],a=[],l=[];let u="",p="";if(!t)return[];for(const e of t){const t=P(e);""===p&&"BAI"===t||(t?(l.push({chr:e,type:t}),a.push(p),p=""):p+=e)}p&&a.push(p);for(const[t,n]of a.entries()){if(0===t){u=n;continue}const s=l[t-1],a="SHY"===s.type?"":s.chr;if("BK"===s.type){o.push(u),u=n;continue}const c=e.measureText(u+a+n).width+i(u+a+n);if(Math.round(c)<=r)u+=a+n;else switch(s.type){case"SHY":o.push(u+"-"),u=n;break;case"BA":o.push(u+a),u=n;break;case"BAI":o.push(u),u=n;break;case"BB":o.push(u),u=a+n;break;case"B2":Number.parseInt(e.measureText(u+a).width+i(u+a),10)<=r?(o.push(u+a),u=n):Number.parseInt(e.measureText(a+n).width+i(a+n),10)<=r?(o.push(u),u=a+n):(o.push(u,a),u=n);break;default:throw new Error("Undefoined break")}}return[...u].length>0&&o.push(u),o}function j({ctx:e,text:t,max:r,wordSpacing:n,letterSpacing:i}){const o=c(n,i),a=[];let l="",u=0;if(!t)return[];for(const n of t){const i=P(n);if("BK"===i){a.push(l),l="";continue}const c=l.length;if(s.has(n)&&(0===c||s.has(l[c-1])))continue;let p=e.measureText(l+n).width+o(l+n),h=Math.ceil(p);if("SHY"===i){const r=t[u+1]||"";p=e.measureText(l+n+r).width+o(l+n+r),h=Math.ceil(p)}if(h>r&&[...l].length>0)switch(i){case"SHY":a.push(l+"-"),l="";break;case"BA":a.push(l+n),l="";break;case"BAI":a.push(l),l="";break;default:a.push(l),l=n}else""!==n&&(l+=n);u++}return[...l].length>0&&a.push(l),a}var k={__proto__:null,addWordAndLetterSpacing:c,getFont:u,isCSSStyleDeclaration:p,canGetComputedStyle:h,isElement:f,isObject:d,getStyle:g,normalizeWhitespace:y,getStyledText:w,prepareText:m,getText:b,prop:x,normalizeOptions:S,getContext2d:v,computeLinesDefault:B,computeLinesBreakAll:j};class O{constructor(e,t={}){!f(e)&&d(e)?(this.el=void 0,this.overwrites=S(e)):(this.el=e,this.overwrites=S(t)),this.style=g(this.el,this.overwrites),this.font=x(t,"font",null)||u(this.style,this.overwrites)}padding(){return this.el?Number.parseInt(this.style.paddingLeft||0,10)+Number.parseInt(this.style.paddingRight||0,10):0}parseArgs(e,r={},n={}){"object"==typeof e&&e&&(n=r,r=e||{},e=void 0);const s=t(t({},this.overwrites),S(n)),i=x(s,"white-space")||this.style.getPropertyValue("white-space");return r||(r={}),n||(r={}),{text:e=!e&&this.el?y(b(this.el),i):m(y(e,i)),options:r,overwrites:n,styles:s}}width(){const{text:e,options:t,overwrites:r,styles:n}=this.parseArgs(...[].slice.call(arguments));if(!e)return 0;const s=u(this.style,n),i=x(n,"letter-spacing")||this.style.getPropertyValue("letter-spacing"),o=c(x(n,"word-spacing")||this.style.getPropertyValue("word-spacing"),i),a=v(s),l=w(e,this.style);return t.multiline?this.lines(l,t,r).reduce((e,t)=>{const r=a.measureText(t).width+o(t);return Math.max(e,r)},0):a.measureText(l).width+o(l)}height(){const{text:e,options:t,styles:r}=this.parseArgs(...[].slice.call(arguments)),n=Number.parseFloat(x(r,"line-height")||this.style.getPropertyValue("line-height"));return Math.ceil(this.lines(e,t,r).length*n||0)}lines(){const{text:e,options:t,overwrites:r,styles:n}=this.parseArgs(...[].slice.call(arguments)),s=u(this.style,n);let i=Number.parseInt(x(t,"width")||x(r,"width"),10)||x(this.el,"offsetWidth",0)||Number.parseInt(x(n,"width",0),10)||Number.parseInt(this.style.width,10);i-=this.padding();const o=x(n,"word-break")||this.style.getPropertyValue("word-break"),a=x(n,"letter-spacing")||this.style.getPropertyValue("letter-spacing"),l=x(n,"word-spacing")||this.style.getPropertyValue("word-spacing"),c=v(s),p=w(e,this.style);return"break-all"===o?j({ctx:c,text:p,max:i,wordSpacing:l,letterSpacing:a}):B({ctx:c,text:p,max:i,wordSpacing:l,letterSpacing:a})}maxFontSize(){const{text:e,options:r,overwrites:n,styles:s}=this.parseArgs(...[].slice.call(arguments)),i=n=>Math.ceil(this.width(e,r,t(t({},s),{},{"font-size":n+"px"})));let o=Number.parseInt(x(r,"width")||x(n,"width"),10)||x(this.el,"offsetWidth",0)||Number.parseInt(x(s,"width",0),10)||Number.parseInt(this.style.width,10);o-=this.padding();let a=Math.floor(o/2),l=i(a);if(a=Math.floor(a/l*o),l=i(a),Math.ceil(l)===o)return a?a+"px":void 0;const c=l>o&&a>0;for(;l>o&&a>0;)a-=1,l=i(a);if(!c)for(;l<o;){if(l=i(a+1),l>o)return a?a+"px":void 0;a+=1}return a?a+"px":void 0}}const A=(e,t)=>new O(e,t),T=t({},k);export{A as init,T as utils};
//# sourceMappingURL=text-metrics.mjs.map