/*! * Zfont v1.2.8 * Text plugin for Zdog * 2019 James Daniel * MIT Licensed * github.com/jaames/zfont */ (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : (global = global || self, global.Zfont = factory()); }(this, (function () { 'use strict'; var Typr={};Typr.parse=function(buff){var bin=Typr._bin;var data=new Uint8Array(buff);var offset=0;var sfnt_version=bin.readFixed(data,offset);offset+=4;var numTables=bin.readUshort(data,offset);offset+=2;var searchRange=bin.readUshort(data,offset);offset+=2;var entrySelector=bin.readUshort(data,offset);offset+=2;var rangeShift=bin.readUshort(data,offset);offset+=2;var tags=["cmap","head","hhea","maxp","hmtx","name","OS/2","post","loca","glyf","kern","CFF ","GPOS","GSUB","SVG "];var obj={_data:data};var tabs={};for(var i=0;i>>i&1)!=0){ num++; } }return num};Typr._lctf.readClassDef=function(data,offset){var bin=Typr._bin;var obj=[];var format=bin.readUshort(data,offset);offset+=2;if(format==1){var startGlyph=bin.readUshort(data,offset);offset+=2;var glyphCount=bin.readUshort(data,offset);offset+=2;for(var i=0;i255){ return -1; }return Typr.CFF.glyphByUnicode(cff,Typr.CFF.tableSE[charcode])};Typr.CFF.readEncoding=function(data,offset,num){var bin=Typr._bin;var array=[".notdef"];var format=data[offset];offset++;if(format==0){var nCodes=data[offset];offset++;for(var i=0;i>4,nib1=b&15;if(nib0!=15){ nibs.push(nib0); }if(nib1!=15){ nibs.push(nib1); }if(nib1==15){ break }}var s="";var chars=[0,1,2,3,4,5,6,7,8,9,".","e","e-","reserved","-","endOfNumber"];for(var i=0;i=gl.xMax||gl.yMin>=gl.yMax){ return null; }if(gl.noc>0){gl.endPts=[];for(var i=0;i>>8;format&=15;if(format==0){ offset=Typr.kern.readFormat0(data,offset,map); }else { throw "unknown kern table format: "+format }}return map};Typr.kern.parseV1=function(data,offset,length,font){var bin=Typr._bin;var version=bin.readFixed(data,offset);offset+=4;var nTables=bin.readUint(data,offset);offset+=4;var map={glyph1:[],rval:[]};for(var i=0;i>>8;format&=15;if(format==0){ offset=Typr.kern.readFormat0(data,offset,map); }else { throw "unknown kern table format: "+format }}return map};Typr.kern.readFormat0=function(data,offset,map){var bin=Typr._bin;var pleft=-1;var nPairs=bin.readUshort(data,offset);offset+=2;var searchRange=bin.readUshort(data,offset);offset+=2;var entrySelector=bin.readUshort(data,offset);offset+=2;var rangeShift=bin.readUshort(data,offset);offset+=2;for(var j=0;j=tab.map.length){ return 0; }return tab.map[code]}else if(tab.format==4){var sind=-1;for(var i=0;icode){ return 0; }var gli=0;if(tab.idRangeOffset[sind]!=0){ gli=tab.glyphIdArray[code-tab.startCount[sind]+(tab.idRangeOffset[sind]>>1)-(tab.idRangeOffset.length-sind)]; }else { gli=code+tab.idDelta[sind]; }return gli&65535}else if(tab.format==12){if(code>tab.groups[tab.groups.length-1][1]){ return 0; }for(var i=0;i-1){ Typr.U._simpleGlyph(gl,path); }else { Typr.U._compoGlyph(gl,font,path); }}};Typr.U._simpleGlyph=function(gl,p){for(var c=0;c65535){ i++; }gls.push(Typr.U.codeToGlyph(font,cc));}var gsub=font["GSUB"];if(gsub==null){ return gls; }var llist=gsub.lookupList,flist=gsub.featureList;var wsep='\n\t" ,.:;!?() ،';var R="آأؤإاةدذرزوٱٲٳٵٶٷڈډڊڋڌڍڎڏڐڑڒړڔڕږڗژڙۀۃۄۅۆۇۈۉۊۋۍۏےۓەۮۯܐܕܖܗܘܙܞܨܪܬܯݍݙݚݛݫݬݱݳݴݸݹࡀࡆࡇࡉࡔࡧࡩࡪࢪࢫࢬࢮࢱࢲࢹૅેૉ૊૎૏ૐ૑૒૝ૡ૤૯஁ஃ஄அஉ஌எஏ஑னப஫஬";var L="ꡲ્૗";for(var ci=0;cirlim){ continue; }var good=true;for(var l=0;lrlim){ continue; }var good=true;for(var l=0;l>1;stack.length=0;haveWidth=true;}else if(v=="o3"||v=="o23"){var hasWidthArg;hasWidthArg=stack.length%2!==0;if(hasWidthArg&&!haveWidth){width=stack.shift()+font.Private.nominalWidthX;}nStems+=stack.length>>1;stack.length=0;haveWidth=true;}else if(v=="o4"){if(stack.length>1&&!haveWidth){width=stack.shift()+font.Private.nominalWidthX;haveWidth=true;}if(open){ Typr.U.P.closePath(p); }y+=stack.pop();Typr.U.P.moveTo(p,x,y);open=true;}else if(v=="o5"){while(stack.length>0){x+=stack.shift();y+=stack.shift();Typr.U.P.lineTo(p,x,y);}}else if(v=="o6"||v=="o7"){var count=stack.length;var isX=v=="o6";for(var j=0;jMath.abs(c4y-y)){x=c4x+stack.shift();}else {y=c4y+stack.shift();}Typr.U.P.curveTo(p,c1x,c1y,c2x,c2y,jpx,jpy);Typr.U.P.curveTo(p,c3x,c3y,c4x,c4y,x,y);}}else if(v=="o14"){if(stack.length>0&&!haveWidth){width=stack.shift()+font.nominalWidthX;haveWidth=true;}if(stack.length==4){var adx=stack.shift();var ady=stack.shift();var bchar=stack.shift();var achar=stack.shift();var bind=Typr.CFF.glyphBySE(font,bchar);var aind=Typr.CFF.glyphBySE(font,achar);Typr.U._drawCFF(font.CharStrings[bind],state,font,p);state.x=adx;state.y=ady;Typr.U._drawCFF(font.CharStrings[aind],state,font,p);}if(open){Typr.U.P.closePath(p);open=false;}}else if(v=="o19"||v=="o20"){var hasWidthArg;hasWidthArg=stack.length%2!==0;if(hasWidthArg&&!haveWidth){width=stack.shift()+font.Private.nominalWidthX;}nStems+=stack.length>>1;stack.length=0;haveWidth=true;i+=nStems+7>>3;}else if(v=="o21"){if(stack.length>2&&!haveWidth){width=stack.shift()+font.Private.nominalWidthX;haveWidth=true;}y+=stack.pop();x+=stack.pop();if(open){ Typr.U.P.closePath(p); }Typr.U.P.moveTo(p,x,y);open=true;}else if(v=="o22"){if(stack.length>1&&!haveWidth){width=stack.shift()+font.Private.nominalWidthX;haveWidth=true;}x+=stack.pop();if(open){ Typr.U.P.closePath(p); }Typr.U.P.moveTo(p,x,y);open=true;}else if(v=="o25"){while(stack.length>6){x+=stack.shift();y+=stack.shift();Typr.U.P.lineTo(p,x,y);}c1x=x+stack.shift();c1y=y+stack.shift();c2x=c1x+stack.shift();c2y=c1y+stack.shift();x=c2x+stack.shift();y=c2y+stack.shift();Typr.U.P.curveTo(p,c1x,c1y,c2x,c2y,x,y);}else if(v=="o26"){if(stack.length%2){x+=stack.shift();}while(stack.length>0){c1x=x;c1y=y+stack.shift();c2x=c1x+stack.shift();c2y=c1y+stack.shift();x=c2x;y=c2y+stack.shift();Typr.U.P.curveTo(p,c1x,c1y,c2x,c2y,x,y);}}else if(v=="o27"){if(stack.length%2){y+=stack.shift();}while(stack.length>0){c1x=x+stack.shift();c1y=y;c2x=c1x+stack.shift();c2y=c1y+stack.shift();x=c2x+stack.shift();y=c2y;Typr.U.P.curveTo(p,c1x,c1y,c2x,c2y,x,y);}}else if(v=="o10"||v=="o29"){var obj=v=="o10"?font.Private:font;if(stack.length==0){console.log("error: empty stack");}else {var ind=stack.pop();var subr=obj.Subrs[ind+obj.Bias];state.x=x;state.y=y;state.nStems=nStems;state.haveWidth=haveWidth;state.width=width;state.open=open;Typr.U._drawCFF(subr,state,font,p);x=state.x;y=state.y;nStems=state.nStems;haveWidth=state.haveWidth;width=state.width;open=state.open;}}else if(v=="o30"||v=="o31"){var count,count1=stack.length;var index=0;var alternate=v=="o31";count=count1&~2;index+=count1-count;while(index -1 && glyphId < advanceWidthTable.length) { advanceWidth += advanceWidthTable[glyphId]; } return advanceWidth; }, 0); }); var width = Math.max.apply(Math, lineWidths); var lineHeight = (0 - descender) + ascender; var height = lineHeight * lines.length; // Multiply by fontScale to convert from font units to pixels return { width: width * fontScale, height: height * fontScale, lineHeight: lineHeight * fontScale, lineWidths: lineWidths.map(function (width) { return width * fontScale; }), descender: descender * fontScale, ascender: ascender * fontScale, }; }; ZdogFont.prototype.getTextPath = function getTextPath (text, fontSize, x, y, z, alignX, alignY) { var this$1 = this; if ( fontSize === void 0 ) fontSize=64; if ( x === void 0 ) x=0; if ( y === void 0 ) y=0; if ( z === void 0 ) z=0; if ( alignX === void 0 ) alignX='left'; if ( alignY === void 0 ) alignY='bottom'; if (!this._hasLoaded) { return []; } var lines = Array.isArray(text) ? text : text.split(TEXT_NEWLINE_REGEXP); var measurements = this.measureText(text, fontSize); var lineWidths = measurements.lineWidths; var lineHeight = measurements.lineHeight; return lines.map(function (line, lineIndex) { var ref = this$1.getTextOrigin(Object.assign({}, measurements, {width: lineWidths[lineIndex]}), x, y, z, alignX, alignY); var _x = ref[0]; var _y = ref[1]; var _z = ref[2]; y += lineHeight; var glyphs = typr_js.U.stringToGlyphs(this$1.font, line); var path = typr_js.U.glyphsToPath(this$1.font, glyphs); return this$1._convertPathCommands(path, fontSize, _x, _y, z); }).flat(); }; ZdogFont.prototype.getTextGlyphs = function getTextGlyphs (text, fontSize, x, y, z, alignX, alignY) { var this$1 = this; if ( fontSize === void 0 ) fontSize=64; if ( x === void 0 ) x=0; if ( y === void 0 ) y=0; if ( z === void 0 ) z=0; if ( alignX === void 0 ) alignX='left'; if ( alignY === void 0 ) alignY='bottom'; if (!this._hasLoaded) { return []; } var measurements = this.measureText(text, fontSize); var advanceWidthTable = this.font.hmtx.aWidth; var fontScale = this.getFontScale(fontSize); var lineWidths = measurements.lineWidths; var lineHeight = measurements.lineHeight; var lines = Array.isArray(text) ? text : text.split(TEXT_NEWLINE_REGEXP); return lines.map(function (line, lineIndex) { var glyphs = typr_js.U.stringToGlyphs(this$1.font, line); var ref = this$1.getTextOrigin(Object.assign({}, measurements, {width: lineWidths[lineIndex]}), x, y, z, alignX, alignY); var _x = ref[0]; var _y = ref[1]; var _z = ref[2]; y += lineHeight; return glyphs.filter(function (glyph) { return glyph !== -1; }).map(function (glyphId) { var path = typr_js.U.glyphToPath(this$1.font, glyphId); var shape = { translate: {x:_x, y: _y, z:_z}, path: this$1._convertPathCommands(path, fontSize, 0, 0, 0) }; _x += advanceWidthTable[glyphId] * fontScale; return shape; }); }).flat(); }; ZdogFont.prototype.getTextOrigin = function getTextOrigin (measuement, x, y, z, alignX, alignY) { if ( x === void 0 ) x=0; if ( y === void 0 ) y=0; if ( z === void 0 ) z=0; if ( alignX === void 0 ) alignX='left'; if ( alignY === void 0 ) alignY='bottom'; var width = measuement.width; var height = measuement.height; var lineHeight = measuement.lineHeight; switch (alignX) { case 'right': x -= width; break; case 'center': x -= width / 2; break; } switch (alignY) { case 'middle': y -= (height / 2)- lineHeight; break; case 'bottom': default: y -= height - lineHeight; break; } return [x, y, z]; }; // Convert Typr.js path commands to Zdog commands // Also apply font size scaling and coordinate adjustment // https://github.com/photopea/Typr.js // https://zzz.dog/shapes#shape-path-commands ZdogFont.prototype._convertPathCommands = function _convertPathCommands (path, fontSize, x, y, z) { if ( x === void 0 ) x=0; if ( y === void 0 ) y=0; if ( z === void 0 ) z=0; var yDir = -1; var xDir = 1; var fontScale = this.getFontScale(fontSize); var commands = path.cmds; // Apply font scale to all coords var coords = path.crds.map(function (coord) { return coord * fontScale; }); // Convert coords to Zdog commands var startCoord = null; var coordOffset = 0; return commands.map(function (cmd) { var result = null; if (!startCoord) { startCoord = {x: x + coords[coordOffset] * xDir, y: y + coords[coordOffset + 1] * yDir, z: z}; } switch (cmd) { case 'M': // moveTo command result = { move: {x: x + coords[coordOffset] * xDir, y: y + coords[coordOffset + 1] * yDir, z: z} }; coordOffset += 2; return result; case 'L': // lineTo command result = { line: {x: x + coords[coordOffset] * xDir, y: y + coords[coordOffset + 1] * yDir, z: z} }; coordOffset += 2; return result; case 'C': // curveTo command result = { bezier: [ {x: x + coords[coordOffset] * xDir, y: y + coords[coordOffset + 1] * yDir, z: z}, {x: x + coords[coordOffset + 2] * xDir, y: y + coords[coordOffset + 3] * yDir, z: z}, {x: x + coords[coordOffset + 4] * xDir, y: y + coords[coordOffset + 5] * yDir, z: z} ] }; coordOffset += 6; return result; case 'Q': // arcTo command result = { arc: [ {x: x + coords[coordOffset] * xDir, y: y + coords[coordOffset + 1] * yDir, z: z}, {x: x + coords[coordOffset + 2] * xDir, y: y + coords[coordOffset + 3] * yDir, z: z} ] }; coordOffset += 4; return result; case 'Z': // close path if (startCoord) { result = { line: startCoord }; startCoord = null; } return result; // unhandled type // currently, #rrggbb and X types (used in multicolor fonts) aren't supported default: return result; } }).filter(function (cmd) { return cmd !== null; }); // filter out null commands }; ZdogFont.prototype._fetchFontResource = function _fetchFontResource (source) { return new Promise(function (resolve, reject) { var request = new XMLHttpRequest(); // Fetch as an arrayBuffer for Typr.parse request.responseType = 'arraybuffer'; request.open('GET', source, true); request.onreadystatechange = function (e) { if (request.readyState === 4) { if (request.status >= 200 && request.status < 300) { resolve(request.response); } else { reject(("HTTP error " + (request.status) + ": " + (request.statusText))); } } }; request.send(null); }); }; Zdog.Font = ZdogFont; return Zdog; } function objectWithoutProperties (obj, exclude) { var target = {}; for (var k in obj) if (Object.prototype.hasOwnProperty.call(obj, k) && exclude.indexOf(k) === -1) target[k] = obj[k]; return target; } function registerTextClass(Zdog) { // Zdog.Text class var ZdogText = /*@__PURE__*/(function (superclass) { function ZdogText(props) { // Set missing props to default values props = Zdog.extend({ font: null, value: '', fontSize: 64, textAlign: 'left', textBaseline: 'bottom', }, props); // Split props var font = props.font; var value = props.value; var fontSize = props.fontSize; var textAlign = props.textAlign; var textBaseline = props.textBaseline; var rest = objectWithoutProperties( props, ["font", "value", "fontSize", "textAlign", "textBaseline"] ); var shapeProps = rest; // Create shape object superclass.call(this, Object.assign({}, shapeProps, {closed: true, visible: false, // hide until font is loaded path: [{}]})); this._font = null; this._value = value; this._fontSize = fontSize; this._textAlign = textAlign; this._textBaseline = textBaseline; this.font = font; } if ( superclass ) ZdogText.__proto__ = superclass; ZdogText.prototype = Object.create( superclass && superclass.prototype ); ZdogText.prototype.constructor = ZdogText; var prototypeAccessors = { font: { configurable: true },value: { configurable: true },fontSize: { configurable: true },textAlign: { configurable: true },textBaseline: { configurable: true } }; ZdogText.prototype.updateText = function updateText () { var path = this.font.getTextPath(this.value, this.fontSize, 0, 0, 0, this.textAlign, this.textBaseline); if (path.length == 0) { // zdog doesn't know what to do with empty path arrays this.path = [{}]; this.visible = false; } else { this.path = path; this.visible = true; } this.updatePath(); }; prototypeAccessors.font.set = function (newFont) { var this$1 = this; this._font = newFont; this.font.waitForLoad().then(function () { this$1.updateText(); this$1.visible = true; // Find root Zdog.Illustration instance var root = this$1.addTo; while (root.addTo !== undefined) { root = root.addTo; } // Update render graph if (root && typeof root.updateRenderGraph === 'function') { root.updateRenderGraph(); } }); }; prototypeAccessors.font.get = function () { return this._font; }; prototypeAccessors.value.set = function (newValue) { this._value = newValue; this.updateText(); }; prototypeAccessors.value.get = function () { return this._value; }; prototypeAccessors.fontSize.set = function (newSize) { this._fontSize = newSize; this.updateText(); }; prototypeAccessors.fontSize.get = function () { return this._fontSize; }; prototypeAccessors.textAlign.set = function (newValue) { this._textAlign = newValue; this.updateText(); }; prototypeAccessors.textAlign.get = function () { return this._textAlign; }; prototypeAccessors.textBaseline.set = function (newValue) { this._textBaseline = newValue; this.updateText(); }; prototypeAccessors.textBaseline.get = function () { return this._textBaseline; }; Object.defineProperties( ZdogText.prototype, prototypeAccessors ); return ZdogText; }(Zdog.Shape)); ZdogText.optionKeys = ZdogText.optionKeys.concat(['font', 'fontSize', 'value', 'textAlign', 'textBaseline']); Zdog.Text = ZdogText; return Zdog; } function objectWithoutProperties$1 (obj, exclude) { var target = {}; for (var k in obj) if (Object.prototype.hasOwnProperty.call(obj, k) && exclude.indexOf(k) === -1) target[k] = obj[k]; return target; } function registerTextGroupClass(Zdog) { // Zdog.TextGroup class var ZdogTextGroup = /*@__PURE__*/(function (superclass) { function ZdogTextGroup(props) { // Set missing props to default values props = Zdog.extend({ font: null, value: '', fontSize: 64, textAlign: 'left', textBaseline: 'bottom', color: '#333', fill: false, stroke: 1, }, props); // Split props var font = props.font; var value = props.value; var fontSize = props.fontSize; var textAlign = props.textAlign; var textBaseline = props.textBaseline; var color = props.color; var fill = props.fill; var stroke = props.stroke; var rest = objectWithoutProperties$1( props, ["font", "value", "fontSize", "textAlign", "textBaseline", "color", "fill", "stroke"] ); var groupProps = rest; // Create group object superclass.call(this, Object.assign({}, groupProps, {visible: false})); this._font = null; this._value = value; this._fontSize = fontSize; this._textAlign = textAlign; this._textBaseline = textBaseline; this._color = color; this._fill = fill; this._stroke = stroke; this.font = font; } if ( superclass ) ZdogTextGroup.__proto__ = superclass; ZdogTextGroup.prototype = Object.create( superclass && superclass.prototype ); ZdogTextGroup.prototype.constructor = ZdogTextGroup; var prototypeAccessors = { font: { configurable: true },value: { configurable: true },fontSize: { configurable: true },textAlign: { configurable: true },textBaseline: { configurable: true },color: { configurable: true },fill: { configurable: true },stroke: { configurable: true } }; ZdogTextGroup.prototype.updateText = function updateText () { var this$1 = this; // Remove old children while (this.children.length > 0) { this.removeChild(this.children[0]); } // Get text paths for each glyph var glyphs = this.font.getTextGlyphs(this.value, this.fontSize, 0, 0, 0, this.textAlign, this.textBaseline); // Convert glyphs to new shapes glyphs.filter(function (shape) { return shape.path.length > 0; }).forEach(function (shape) { this$1.addChild(new Zdog.Shape({ translate: shape.translate, path: shape.path, color: this$1.color, fill: this$1.fill, stroke: this$1.stroke, closed: true, })); }); this.updateFlatGraph(); }; prototypeAccessors.font.set = function (newFont) { var this$1 = this; this._font = newFont; this._font.waitForLoad().then(function () { this$1.updateText(); this$1.visible = true; // Find root Zdog.Illustration instance var root = this$1.addTo; while (root.addTo !== undefined) { root = root.addTo; } // Update render graph if (root && typeof root.updateRenderGraph === 'function') { root.updateRenderGraph(); } }); }; prototypeAccessors.font.get = function () { return this._font; }; prototypeAccessors.value.set = function (newValue) { this._value = newValue; this.updateText(); }; prototypeAccessors.value.get = function () { return this._value; }; prototypeAccessors.fontSize.set = function (newSize) { this._fontSize = newSize; this.updateText(); }; prototypeAccessors.fontSize.get = function () { return this._fontSize; }; prototypeAccessors.textAlign.set = function (newValue) { this._textAlign = newValue; this.updateText(); }; prototypeAccessors.textAlign.get = function () { return this._textAlign; }; prototypeAccessors.textBaseline.set = function (newValue) { this._textBaseline = newValue; this.updateText(); }; prototypeAccessors.textBaseline.get = function () { return this._textBaseline; }; prototypeAccessors.color.set = function (newColor) { this._color = newColor; this.children.forEach(function (child) { return child.color = newColor; }); }; prototypeAccessors.color.get = function () { return this._color; }; prototypeAccessors.fill.set = function (newFill) { this._fill = newFill; this.children.forEach(function (child) { return child.fill = newFill; }); }; prototypeAccessors.fill.get = function () { return this._fill; }; prototypeAccessors.stroke.set = function (newStroke) { this._stroke = newStroke; this.children.forEach(function (child) { return child.stroke = newStroke; }); }; prototypeAccessors.stroke.get = function () { return this._stroke; }; Object.defineProperties( ZdogTextGroup.prototype, prototypeAccessors ); return ZdogTextGroup; }(Zdog.Group)); ZdogTextGroup.optionKeys = ZdogTextGroup.optionKeys.concat(['color', 'fill', 'stroke', 'font', 'fontSize', 'value', 'textAlign', 'textBaseline']); Zdog.TextGroup = ZdogTextGroup; return Zdog; } var index = { init: function init(Zdog) { // Global font list to keep track of all fonts Zdog.FontList = []; // Helper to wait for all fonts to load Zdog.waitForFonts = function() { return Promise.all(Zdog.FontList.map(function (font) { return font.waitForLoad(); })); }; // Register Zfont classes onto the Zdog object registerFontClass(Zdog); registerTextClass(Zdog); registerTextGroupClass(Zdog); return Zdog; }, version: "1.2.8", }; return index; }))); //# sourceMappingURL=zfont.js.map