Minor changes to the new text utility code used in String input type.
- Does not force turtle to operate in radians
- Now respects turtle.isdown() and doesn't print if true
- Text.size(turtle, str, scale = 1) returns properties of text str to be printed
- Text.bbox(turtle, str, scale = 1) returns bounding box of text str to be printed
- Text.dimensions(scale = 1) returns properties of fontData for scale
- Text.bboxPrint(turtle, str, scale = 1) prints the text and returns the absolute bounding box
Log in to post a comment.
// The MIT License // as per https://turtletoy.net/turtle/0f84fd3ae4 const txt = 'This text should be centered'; //type=string const font = 1; //min=0 max=1 step=1 (EMSElfin, HersheySans1) const tilt = 0; //min=-10 max=10 step=1 // You can find the Turtle API reference here: https://turtletoy.net/syntax Canvas.setpenopacity(1); const fonts = [ {"name":"EMSElfin","unitsPerEm":1000,"ascent":800,"descent":-200,"capHeight":500,"xHeight":300,"glyphs":"IADEDgDAIQA4CYAHpuYgCDrpvAfI9gBAJgcI\/uAG4f96COH\/3ggI\/iYHCP4AQADAIgDMC+wEBuZGBQrnRgVu7ABAWgoG5loKtuq6CW7sAEAAwCMAfhhiBw78ugmy804MXOrQDOLmAEAOFYjmChQ66cQO7PwAQCAXzvXgECj29gko9tADBPcAQJIEiu6KDOrtdBMm7gIXzO38F8ztAEAAwCQABBAyCp4AFArS7LoJeuoaCb7nGglI5QBA6A1u7MoNOOsyCl7oXAhA6KQGHOlGBZjq7ASM7MgFxu7eCPrxigwQ9WoOpPdqDvz5igwO\/PAK7PwaCSz9JgcM\/SgFFPsuBFz5TAQc+ABAAMAlAAgWAgip\/R4PUOw6EUDoigxY6RoJNOrgBjTq5gXa6UwEOOuxA2zu8gPi8EYFfPLCBjbyXAhg8HoIaO0+CLDrgAd66gBA1BIS8xwRDPQEEIL2gg+e+L4PFPt8EG78NBLN\/JITL\/zwFLb5aBUE9w4VyvSMFNDz1BIS8wBAAMAmAHAcHg\/g6KYO1OpCDjLsxA7S7IQNEOv0C5jqlgry6lYJsOsaCUrtVgls7loKhO9ODN7vNgtm7yAInPCMBbjyzgTK9GoE2vjmBU\/8mAhH\/nILBP+mDuT+dhGp\/XQTMvvOEz75EBNA9xwRrPQAQLQKwvc2C0b2qAxM9QAPrPRSEjT0DhWU85wYmvISGwDxSBwC79AbLO30GlDslhnO694XUOwAQADAJwBoBpIETuSSBKrsAEAAwCgAkAsYC7EDAgiC\/8gFkvrOBIj1kgRg8CgFdOsIByjnVgmy5K4LNuMAQADAKQAYC0wEtQLCBmL\/mAhQ+5wJhve6CZTzugnk7pgIturgBmTnTATW4\/QCHuIAQADAKgC4EFoKcPSWCpTkAEAuBFTyoA++5wBAEAS+52YNJPAeD1TyAEAAwCsALBWoDM387gzN\/PQLzusAQPIDEPV6CBD1iA6s9NoRNPSqFNDzAEAAwCwAPggsBgT\/sAQE\/+wELP2kBkv9wga9AOwEsQMAQADALQAiECgFIvduBSL3\/Ahk9nILqvboDQr2AEAAwC4A5AfsBGv9sARD\/2gGQ\/+kBor97ARr\/QBAAMAvABIMkgTo\/d4ISO+WCmTnAEAAwDAAZA84CUD3GAtA92YNzvXiDpry4g5+8NAMkO0yChTsgAcU7MgFru0KBcDv7AR88sgF6PTCBmT2Vglo9wBAAMAxAAYO8Aqm\/lQLHOmuC9TqVglu7EQHzO0oBYru1QKo7gBAAMAyAHwQgAeM7CAI6u1iB6LvyAVC8GoEou\/QA2jt8gNc6iwGCuf8CAbmkAvi5ioNgOlmDVDs7gwk8FQLTPU4CZj5Yget\/CwG5P6aEMn9AEAAwDMA3A\/ACNT5IAhE+KoFYvguBD75kgOW+xAEqf3mBWL\/egii\/5ALqf0MDZL6SA1A92wMlPMYC5bxOAl+8IAHnPDCBgDx5gX68VwIou9sDNTqHg\/m55YKBOjCBr7nAEAAwDQAIhDcD9j6UgNL\/cAIwO82C4LnAEAwDOrtMAy2+U4Mwf8wDNADAEAAwDUAHg+8B0\/8YgdQ+ywGUPvOBE\/8zgSm\/iwGngAaCb0ATgym\/oQN0vvoDSD5qAyq9rQKDPQ4CbLzYgdw9CwGavVGBar27AT+90YFJPBuBUTuCgWA6ZgI+OnQDIDpAEAAwDYA2hEgCEP\/egjw+zIKXPlODLz4pg66+kYPS\/1CDmL\/qAx+ANgJfgBiB0f+RgU4+uwEEPVKBiTwGgmq7K4LmOroDVzqBBDy6hYSUOwAQADANwAiEMgFWgFODKLvJA7O62QPXOpeEJ7pGAsW6iwGeupSA9rpAEDgBvrxRg928wBAAMA4ADoRugli\/4QNKP7EDuz8Hg\/S+0AQFPtAEHr5\/hCk99wPsvMGDgDxqAyE7xgLZu\/8CGbv5AfM7eQHOOu6CRzpzAsc6egNFuoAD87rHg8I7iQOIO+KDMDv3gjA7+AGPPEoBQz0zgTI9uwE1PmqBS\/8CAdH\/roJYv8AQADAOQAcEWoEDvywBA78bgUI\/rwHBP8YC8n96A32+kYPZPbiDn7wTgzO6xgLXOp+CbzpJgd66sgFUOwKBWzujAUA8eAGfPLeCNby8Ar68U4MnPBmDa7tAEAAwDoAnAluBULwKAUY8uAGGPImB2DwbgVC8ABAqgVr\/W4FQ\/8mB0P\/Ygdr\/aoFa\/0AQADAOwD2CSwG4vDmBZrygAea8uQH4vAsBuLwAECEnB8AZJz4Af6d+AE9nh8AhJwfAABAwgYj\/0YFI\/+MBWv9RAdr\/WIH\/ACMBdADAEAAwDwALBXUEgj+LgTa+JIThO8AQADAPQACFygFkvq+D9j6bhSS+gBAChR286AP7vP2CbLzqgV28wBAAMA+ACYWCgVa8U4MUvQWEij2aBWG96APOPoaCez8qgUo\/gBAAMA\/AB4P4Aaq9oAHLO28BwLvGglI704MDu3KDV7oKg1s5HIL2OH8CMDgLAYe4goFNuOSBE7kagSm5vIDIujOBFjpSgZ86IYG4uYAQADAQAD0GmgVhv6CD4L\/lgpn\/koGXPluBTbyegjO64oMQOjgEEbn8BRe6PwX8upUGkTuuBo88dgY6PTkFiL3bhRE+FYTaPdSEoj1UhK48pgSfvC8EQLvXhCK7sQOou+sDRjyDA3Q8wwN7PVIDWj3Bg4c+AAPpPcEEAr2cBJU8gBAAMBBAD4XmgFyA7AEUgMmB\/IDkgRSA1oKzuuKDEzm0AxI5bgQ4vBuFDL7DhXJ\/eYFyf3wFKn95BYQBOwTsARaGdADAEAAwEIALhOMBTsBGAsj\/wAPbvwEEFb6vg9E+GoORvYqDRD1VAuO9GIHTPVyC3D0oA++8bwRiu5SEjjr+BHm57gQSOXoDfritArY4cIGHuJ6AXji5gV44rwHvQAAQADAQwBOGzAbdPq6GEv9ShVD\/9oRov\/KDSP\/nAnN\/AgHtvnsBBD1zgT87+AG+OlaCsrlQg4w5DQScuMIFvTjGBqI5pAaEuTcGYjmNhoc6QBAAMBEABoYFwK64aQGfuGoDB7iWBES5IwU5ucmFhTsxhZg8IYVjvRwEoD4xA4U+zYL7PwEBsn9nAlr\/QIIZOeAB5zhAEAAwEUAzhN0E2f+VhP4AXQTfgBKBr0ALgQ7AcIGvQCGBsL3lgqG9+IOwvegD4j1Hg9c+eIO4Pd+CWj3hgaG98IGSu1oBk7kLgQS5AgHlORIDZTkkhOU5HQTCufOE7rhAEAAwEYAVhOkBtgBnAn8AJYK\/AAaCd0AegiA+JoQwvfgENT5mhCq9poQwvd6CID44AZw5eAGJOZ2AgbmkAvo5bYSyuW2Erjj1BKk6BATgOkAQADARwDIFLYSGONwEsTmmBKs5S4T6OXaEUjlIhAS5NAMuOP2Ce7kJgcE6G4FLO1GBVTyjAWG9+QHFPvwCm78AA9Q+1gRvPiYEhD11BIm7owUbO5CDibuAEAAwEgAohcKBd0AXAii\/+AGPwBoBuz1zgTu5PQCSOXOBAzlSgaU5ABA8BTYAewTFwKaEHYCcBI3AjIUxu7IFMLo6hWQ46IXkOMKFFTjAEBWExz4pAbg9wBAAMBJAFQLbgVeAPwIQ\/+uCyP\/3ggE\/wgHuPJoBmrmeggG5n4JTOY+CAbm1QIo5wBAAMBKAJoQbgUE\/9ADhv65AeH\/\/AA3ArUCRgUsBgQGFAoKBQwNNwKIDob+iA50+kgNMPOWCirlgAck5kIOTuQAQADASwD6GW4FFAN+CfgBvAd2AiYHcPSGBsDvLAYM5XoIsuT0AnDlAEBaGSTmqhSs5eQWBuY0EjjrhA0A8VYJ6PSeB2r1tApw9KwNUvS+D2r1WBHg9\/ISkvoIFgT\/YBi9ALgaPwAqHKb+cByp\/bIb0vuQGtj6eBmW+wBAAMBMAAQQQBBn\/mQPMwO+DzsBtAq9AMgFvQAzAzsB5gW9AOYFou\/IBZ7pBAb64kwE+uLkB9LiAEAAwE0A8COaAYL\/gAfk\/qoFBP8CCHrqwAii4CIQRPjGFiDvNhra6XAcjuVkHn7hoB7k3woejuUEH8zt4B\/s9dogBP9EJSj+ph2i\/wBAAMBOAAgWcgN6AZwJfgDgBr0Ahgay8wQGSO8EBo7lzAvi8NQS0vsuE4rusBPm58gUtOJcF\/riUhJ44gBAAMBPAFoZOhGs5UYP0OTYCYjmaAZ66s4EJPAoBab1ngfU+TAMDvzgENL7hhVi+D4XpvV+GFTyYBhs7gIX+OloFUbndBPK5VgRrOUAQADAUABSEigFXgC6CcH\/YgcfAOQH8upiB0Do4AYq5W4FNuMXAjbj8Apy4yQOlOSaEEbn2hF66rwRzO3gEJzwyg0w81oK7vPkB+7zAEAAwFEA+hnsE+j9PhfU+YQXgPhgGAT3uhju86IX5O6oFjLs7BPa6XASvOkiEMLo9gl66oYGqO5GBZry7ASk90oG0vtcCAj+cgvh\/0YPHwCUEWL\/sBOp\/ZoQ\/PkYGhAEyhySBCgeUgNkHhcCCh69AAYdwf\/QG6L\/shteAABAAMBSAJwYqgVqBJYKUgM+CPID5AdM9WIHbO4+CAzllQIk5hgL0OReEO7k1BJq5qoUHOnwFBTsbhTk7jQSPPFGD7jyqAyU8wII0POIDpTzXhDK9BYS\/vfOE838ShXYAVwXjAW0GaQGSBzmBaYdsASmHdUCLh1aAbIbAACQGn4ANhpaAQBAAMBTAJoQeggy+yAIXPnmBWL4sQM++dUC0vtyAwj+KAVeAAIIegGQC+H\/JA7N\/OIOGvqmDqT3MAzW8iAIjOzCBljpwgYG5noIcuOcCZbicgta4ioNNuOgD47lmhD040IOfOgAQADAVADqFRgL+AHgEFoBQg6aAe4M4uaGFabmpBUE6IYVpuYmFhLkhhWm5nIDguexA5TkkgO+5zMDNOoAQADAVQCoFrUCeOLkB7rhKAU84iwGiu5iB0T4GgnS+xIMzfziDg78WBFW+pIT7PVQFNzxMhQY4xYS+uKAFrTiAEAAwFYAzBVyA+jlSgZI5bAEjuV6CCTw0gr8+fQLpv5mDXT6ag5E+JoQ3u\/aEc7rVhOg54YVNuMuE9LiaBVU42AYNuMAQADAVwDmHvQCauYsBgbmeghI5W4FJOZiB+TuAggw87oJOPr2CUv9cgsc+O4MyvTEDqrsHg966gQQ\/uheEGTnHBGS6xATMPOoFh8A\/Be8+HgZVPJ4GSTwchrq7bIbOOvuG2TnLh3S4tYa+uKAIBjjAEAAwFgAwBdXAhwBCAe9AM4E3QD+EJDtUhKY6iAXkOMeGbjjUBQ24wBAtQIw5PwIGONKBpDjgAcc6XgK3u8GDkD3uBDs\/HYRBP8yFLkBzBV2AhoYNwJaGRwBlhkE\/5wYyf2EF+j9AEAAwFkAIBdSA9LiCAf24QoFeOJ6CJjq9gnq7e4MGPJODFcCWgp2ApgItQJODFcCHg92AgBA0Az68TQSFursE+LmPhc44aoUouB4Gdjh3Bke4gBAAMBaADIU1QJc6lIDrOVSA4jmVAsG5jIUrOUuE6zl4BCk6DAMvvEaCQDxTgy+8WQP3PEwDNzxRAcs\/ewEOwG2EoL\/1BJL\/bYSWgEAQADAWwBODGwMNwK8B5UCvAdQ+0oGMPPIBarsyAX041QL1uMAQADAXACsDe4MS\/1cCLLzCAfk7moE4OgAQADAXQDYCbEDTARKBi4EwgaxA+AG4vBEBwzl8gMq5QBAAMBeAAAP0ANG9t4IBuZUCyztZg1M9QBAAMBfAC4TsQOeALYSvQAAQADAYAA+CDMD\/OBcCO7kAEAAwGEAHg\/sBFTyTATe724FCO7kB27sGAss7dAM3u9IDTDzZg1E+NAMOPpaCvD7vAdL\/W4Fqf2SA478cgPU+WoEHPgmB2j3lgpo95ALpPcMDT75hA3Y+qwNS\/2sDQAAyg38AB4POwHcDzsBuBA7AbwRvQAAQADAYgBwErkBXOCeB+TfzgQ+4CwGXgC6CXoBZg29AHwQyf2UEdj6OhGk9wQQTPXKDdDzMgqO9CAIRvbCBmL45gWS+mgGegGSBPgBsQN2AgBAAMBjAGQPSA3Q80IOJu7oDULwrguo7n4JRO6kBsDv7ASU82oEQPduBTj6Agjs\/DYLS\/0qDU\/86A1u+wBAAMBkALwRNBIfAEYPXgCsDd0ARg8\/AEYPqvbEDnzyrA0e8VQL4vBcCL7xSgbu884EQPeSBJL6RgUM\/SYHxf78CMX+kAvN\/AwNuvpCDqT3AA+U89wPxt9UCyDgAEAAwGUAhA3uDEf+cgteAMAIOwHmBWL\/sASS+goFEPXgBkLwPghm7xQKou9yCwDxKg1M9TgJiPUoBab1AEAAwGYAVAtMBD4IrgvgBiAIYgcIBz75wgZg8LQKQvDMC8DvuglC8EwEYPDQA0LwCAdg8EQHXujkBxLkOAm64cwLhOCIDlzg4BD24doRVOP4EU7kAEAAwGcAfBC0Cob30Aym9QYOfPKIDvrxdhHi8CQO+vFODITv9gnM7XoIru1GBcDvEAR28+wERvakBqT3XAjg97oJpPc2C0D3rguW+64LYv9CDrkB3A\/QA5oQYgd8ELoJhA2oDBoJiA6wBCQOegH0C+H\/mAh+ABAEFwI7AdADYv9EB0f+Vgln\/q4LYv8AQADAaAB2EXIDFwL8CH4ASgZaAUYF0uzOBKjfqgVi384E5N92AuTfAECqBbLz5Afi8PAKZu8MDd7vag6+8R4PavVkD574gg+9ACoNWgE0Ej8AAEAAwGkAFAoUAwj+MwMI\/n4JS\/2GBor9CAcC70wEAu8AQCgF0OQoBUzmwgaI5sIG0OQoBdDkAEAAwGoAWgoXApgIfgB6CGL\/FArh\/2wMNwLoDW4FKg16CLoJ\/AgEBiAIwvdcCALvyAXe79UCfvAAQIYG0ORuBY7lCAeI5t4IjuWGBtDkAEAAwGsA+BFSAxwB3ggAACwGfgBuBRDrjAUy3SAIktzVAm7dAEBSEiztiA7w7NwP6u0MDZzwSgZM9TIK9PIGDlb6XhBi\/xATkgMOFS4EIBdSA0IYmgHeF4L\/qBbF\/swV5P5oFaL\/AEAAwGwAwAiSAwoF8gMKBd4IFANKBi4EbgUm7uYFWuICCLrhjAW04lIDtOIAQADAbQDoHM4EmgEmB70AMgo\/AAgHvQDgBoj1BAaK7rwHCO4UAwLvLAaK7kQHBPd+CZrySA3A7x4PhO8iEOLwmhDs9ZoQ\/PnaEY70bhRC8CAXCO48GcztNhpg8JAapvVUGqb+ohei\/6YdR\/4AQADAbgDsE5ID+AHACDsBhgZ6AWgGtvkIB5TzRAeq7CwG9usUAzLsAEAIB1L00gr87+gNbO4EEN7vdhE28toREPX4EbT7XhAO\/DIUUPsAQADAbwD+EMwLkO1+CQ7tSgYm7uwEuvAKBVL0aAaq9pwJRPjKDeb2gg\/Q86APJPAkDibuMAwm7gBAAMBwAHQTKAWsDVYJDA3SCooMmAgMDQIIagQsBhz4BAaW8VwIaO3uDBDruBBu7DQSYPCUEY70vg+G9zAMvPh+Cf73CAfO9QQGGPKMBVDsjAVe6CYHvuf0AhzpAEAAwHEA1BKUEYDpQBDc8YgOjvQwDGT2\/Ajm9iwGTPXOBJryCgWo7iAIMuw2C87rQg7M7b4Pou\/cDzT0vg\/2+kIOeAoeD4AHNBKSBJIT+AEAQADAcgAiEM4E\/ACeBx8A2AmC\/+AGXgAsBiD5LAa48qoF0uwUA0rtqgXw7KQGdvPACITvEgzS7GoOMuygD0rtXhCo7gQQYPBGDx7xJA4e8QBAAMBzAEgNCgX8ABAEov+1AqL\/mgE7ATcCEATQA8gFwgYsBn4JsAQYC3YCVAuG\/lYJIPmGBhLzyAVs7oAHEOsUClzq9Avy6u4MMuwkDtTqkAvk7gBAAMB0AKwNkAvN\/O4MlvtqDk\/8pg4I\/ugNHwBUC1oBGgn8ACYHhv7gBpj5aAbq7XIDbO4UCpDtaAbq7SwGauYAQADAdQDOEzMD9utEB\/br5gVQ7G4FcPRuBT75hgZu+54Hzfx6COz8FArY+pALIPn0CwT3xA648kAQwO+4ENLs4BCk91gRZ\/6gDwT\/dhFn\/lAUCP4AQADAdgDyEnYCbuyMBXTrkgT265YKCP5qDqr23A\/68TQSFOwEEDLs8BQy7ABAAMB3AHIauQEy7LAEsOuGBvLqLgTO6wIIevl6CAj+nAm2+VoKCvbuDN7vZg2K7gYO3PG4EDj62hEI\/nASYv90EwT\/8BTU+QIXlPPAF5bxfhiQ7cYWjOycGJDtEhtK7e4b0uwAQADAeAB0E1cCbO52AibuLAaQ7bAE6u2uC9j63A\/dAPgRFAPOE3IDDhW1AmgVuQGkFZ4A8BQj\/84Tgv8AQLkBsQMXArEDhgZyA0wEcgOWCp74+BEy7NwPdOsKFKrsAEAAwHkA2hE3ArwHHAFoBuT+aAaK\/VwILP3wCgT\/Kg0XAioNLAY2C7oJCgUqDa38Rg+m9ZQRYPAAQGwMKP6SBB7x5gXi8BcCePEAQADAegCaEPID+vHyA8ztEARI72QPkO1sDLjyfgn4+KQGnvh+Cfj4Kg2e+H4JIPnOBBcC3A\/VAnwQXgC+D\/QCBBCMBQBAAMB7AEgN7gxyA3gKEAQCCBQDCAfB\/0QHHPjIBej0kgSy8xQDMPOVArLzkgSy82IHuPLeCGbvwAi86boJuOOWCvbhbAxg4QYOnOEAQADAfADeCCwGpv4sBhjyyAXC6IwF5ucAQADAfQCoDGoELgQKBUwEwgaxA94IegHeCAz9VglA9xQK6PTMCwz0Kg2y8zIKUvSYCLjyAgh+8HoIHOmeB9DkhgbS4qoFHuLyA7rhtQJ44gBAAMB+ABoYagQi94YGyvTACLLzrguO9OIOCvY0EgT3jBQK9qgWcPQAQADA"}, {"name":"HersheySans1","unitsPerEm":1000,"ascent":800,"descent":-200,"capHeight":500,"xHeight":300,"glyphs":"IADEDgDAIQBODE4MJOZODGj3AEBODIr9GAvF\/k4MAACEDcX+TgyK\/QBAAMAiALATmAgk5pgIxu4AQHASJOZwEsbuAEAAwCMA3Bk6ETjhmAiYCABAnBg44QQQmAgAQJgIPPHcGTzxAEBiB574nBie+ABAAMAkAJwYhA044YQN7AQAQHASOOFwEuwEAECcGNrpJhZk53ASJOaEDSTm2Alk52IH2uliB1DsmAjG7tgJ\/O9ODDzxsBOy8yYW6PRcFyj2nBie+JwYT\/wmFsX+cBIAAIQNAADYCcX+YgdP\/ABAAMAlAIgdiB0k5mIHAAAAQIQNJOYEEKToBBAQ68QOkO1ODMbu2AnG7mIHUOxiB9rpmAhk5xgLJOaEDSTmBBBk57ATpOhcF6ToEhtk54gdJOYAQJwYaPcmFp748BQU+\/AUiv1cFwAA3BkAAEgcxf6IHU\/8iB3U+RIbaPecGGj3AEAAwCYA\/h\/+Hzzx\/h\/878gexu6IHcbuSBz87xIbfPKcGJ74JhZP\/LATxf46EQAATgwAANgJxf6YCIr9YgcU+2IHnviYCCj22Ano9HAS\/O+wE8bu8BRQ7PAU2umwE2TnOhEk5sQOZOeEDdrphA1Q7MQO\/O86EbLzXBdP\/NwZxf5IHAAAyB4AAP4fxf7+H4r9AEAAwCcATgzYCaTomAhk59gJJOYYC2TnGAva6dgJUOyYCJDtAEAAwCgAOhE6ETjhxA64404MZOfYCVDsmAh88pgIaPfYCYr9Tgx2AsQOLAY6EZgIAEAAwCkAOhFiBzjh2Am4404MZOfEDlDsBBB88gQQaPfEDor9Tgx2AtgJLAZiB5gIAEAAwCoAsBOEDZDthA1P\/ABAYgc88bATnvgAQLATPPFiB574AEAAwCsA\/h+wE9rpsBMAAABAmAjo9Mge6PQAQADALADYCdgJFPuYCE\/8YgcU+5gI1PnYCRT72AmK\/WIHAAAAQADALQD+H5gI6PTIHuj0AEAAwC4A2AmYCNT5YgcU+5gIT\/zYCRT7mAjU+QBAAMAvABIbSBw44SwGmAgAQADAMACcGMQOJOYYC2TnmAgQ62IHPPFiB+j0mAgU+xgLxf7EDgAAOhEAAPAUxf5cFxT7nBjo9JwYPPFcFxDr8BRk5zoRJObEDiTmAEAAwDEAnBgYCxDrhA3a6ToRJOY6EQAAAEAAwDIAnBiYCFDsmAgQ69gJpOgYC2TnhA0k5nASJObwFGTnJhak6FwXEOtcF5DtJhb877ATsvNiBwAAnBgAAABAAMAzAJwY2Akk5lwXJOYEEPzvsBP87yYWPPFcF3zynBgo9pwYnvhcF0\/88BTF\/joRAACEDQAA2AnF\/pgIiv1iBxT7AEAAwDQAnBiwEyTmYgdo99wZaPcAQLATJOawEwAAAEAAwDUAnBgmFiTm2Akk5pgIPPHYCfzvhA3G7joRxu7wFPzvXBd88pwYKPacGJ74XBdP\/PAUxf46EQAAhA0AANgJxf6YCIr9YgcU+wBAAMA2AJwYXBfa6SYWZOdwEiTmBBAk5k4MZOfYCRDrmAg88ZgIaPfYCU\/8TgzF\/gQQAAA6EQAA8BTF\/lwXT\/ycGJ74nBho91wXsvPwFDzxOhH87wQQ\/O9ODDzx2Amy85gIaPcAQADANwCcGJwYJOZODAAAAEBiByTmnBgk5gBAAMA4AJwYhA0k5tgJZOeYCNrpmAhQ7NgJxu5ODPzvOhE88fAUfPJcF+j0nBho95wYFPtcF4r9JhbF\/nASAACEDQAA2AnF\/pgIiv1iBxT7Ygdo95gI6PQYC3zyxA488bAT\/O8mFsbuXBdQ7FwX2ukmFmTncBIk5oQNJOYAQADAOQCcGFwXxu4mFnzysBPo9AQQKPbEDij2GAvo9JgIfPJiB8buYgeQ7ZgI2ukYC2TnxA4k5gQQJOawE2TnJhba6VwXxu5cF+j0JhYU+7ATxf4EEAAAhA0AANgJxf6YCE\/8AEAAwDoA2AmYCDzxYgd88pgIsvPYCXzymAg88QBAmAjU+WIHFPuYCE\/82AkU+5gI1PkAQADAOwDYCZgIPPFiB3zymAiy89gJfPKYCDzxAEDYCRT7mAhP\/GIHFPuYCNT52AkU+9gJiv1iBwAAAEAAwDwAiB1IHNrpmAjo9EgcAAAAQADAPQD+H5gIPPHIHjzxAECYCJ74yB6e+ABAAMA+AIgdmAja6Ugc6PSYCAAAAEAAwD8AJhZiB1DsYgcQ65gIpOjYCWTnTgwk5joRJOawE2Tn8BSk6CYWEOsmFpDt8BT877ATPPHEDrLzxA5o9wBAxA6K\/YQNxf7EDgAABBDF\/sQOiv0AQADAQAA0IdwZ\/O+cGJDtJhZQ7HASUOwEEJDtxA7G7oQNfPKEDSj2xA6e+DoR1PnwFNT5XBee+JwYKPYAQHASUOwEEMbuxA588sQOKPYEEJ74OhHU+QBA3BlQ7JwYKPacGJ74EhvU+Ygd1Pn+H2j3NCGy8zQhPPH+H5DtyB4Q60gcpOjcGWTnJhYk5nASJObEDmTnTgyk6NgJEOuYCJDtYgc88WIH6PSYCJ742AkU+04Miv3EDsX+cBIAACYWAADcGcX+SByK\/YgdT\/wAQBIbUOzcGSj23Bme+BIb1PkAQADAQQAmFsQOJObsBAAAAEDEDiTmnBgAAABAmAho9\/AUaPcAQADAQgDcGZgIJOaYCAAAAECYCCTmsBMk5lwXZOecGKTo3BkQ69wZkO2cGPzvXBc88bATfPIAQJgIfPKwE3zyXBey85wY6PTcGWj33BkU+5wYiv1cF8X+sBMAAJgIAAAAQADAQwDcGdwZUOycGNrpJhZk57ATJObEDiTmTgxk59gJ2umYCFDsYgf872IHKPaYCNT52AlP\/E4Mxf7EDgAAsBMAACYWxf6cGE\/83BnU+QBAAMBEANwZmAgk5pgIAAAAQJgIJOY6ESTm8BRk51wX2umcGFDs3Bn879wZKPacGNT5XBdP\/PAUxf46EQAAmAgAAABAAMBFAFwXmAgk5pgIAAAAQJgIJOacGCTmAECYCHzycBJ88gBAmAgAAJwYAAAAQADARgAmFpgIJOaYCAAAAECYCCTmnBgk5gBAmAh88nASfPIAQADARwDcGdwZUOycGNrpJhZk57ATJObEDiTmTgxk59gJ2umYCFDsYgf872IHKPaYCNT52AlP\/E4Mxf7EDgAAsBMAACYWxf6cGE\/83BnU+dwZKPYAQLATKPbcGSj2AEAAwEgAEhuYCCTmmAgAAABA3Bkk5twZAAAAQJgIfPLcGXzyAEAAwEkA2AmYCCTmmAgAAABAAMBKALATcBIk5nAS1Pk6EYr9BBDF\/oQNAAAYCwAAmAjF\/mIHiv0sBtT5LAZo9wBAAMBLANwZmAgk5pgIAAAAQNwZJOaYCGj3AEDEDjzx3BkAAABAAMBMAPAUmAgk5pgIAAAAQJgIAABcFwAAAEAAwE0AiB2YCCTmmAgAAABAmAgk5nASAAAAQEgcJOZwEgAAAEBIHCTmSBwAAABAAMBOABIbmAgk5pgIAAAAQJgIJObcGQAAAEDcGSTm3BkAAABAAMBPABIbxA4k5k4MZOfYCdrpmAhQ7GIH\/O9iByj2mAjU+dgJT\/xODMX+xA4AALATAAAmFsX+nBhP\/NwZ1PkSGyj2Ehv879wZUOycGNrpJhZk57ATJObEDiTmAEAAwFAA3BmYCCTmmAgAAABAmAgk5rATJOZcF2TnnBik6NwZEOvcGcbunBg88VwXfPKwE7LzmAiy8wBAAMBRABIbxA4k5k4MZOfYCdrpmAhQ7GIH\/O9iByj2mAjU+dgJT\/xODMX+xA4AALATAAAmFsX+nBhP\/NwZ1PkSGyj2Ehv879wZUOycGNrpJhZk57ATJObEDiTmAEBwEhT73Bl2AgBAAMBSANwZmAgk5pgIAAAAQJgIJOawEyTmXBdk55wYpOjcGRDr3BmQ7ZwY\/O9cFzzxsBN88pgIfPIAQDoRfPLcGQAAAEAAwFMAnBicGNrpJhZk53ASJOaEDSTm2Alk52IH2uliB1DsmAjG7tgJ\/O9ODDzxsBOy8yYW6PRcFyj2nBie+JwYT\/wmFsX+cBIAAIQNAADYCcX+YgdP\/ABAAMBUALAThA0k5oQNAAAAQOwEJOYmFiTmAEAAwFUAEhuYCCTmmAie+NgJT\/xODMX+BBAAAHASAAAmFsX+nBhP\/NwZnvjcGSTmAEAAwFYAJhbsBCTmxA4AAABAnBgk5sQOAAAAQADAVwCIHSwGJOZODAAAAEBwEiTmTgwAAABAcBIk5pwYAAAAQMgeJOacGAAAAEAAwFgAnBhiByTmnBgAAABAnBgk5mIHAAAAQADAWQAmFuwEJObEDnzyxA4AAABAnBgk5sQOfPIAQADAWgCcGJwYJOZiBwAAAEBiByTmnBgk5gBAYgcAAJwYAAAAQADAWwA6EZgIOOGYCJgIAEDYCTjh2AmYCABAmAg44ToROOEAQJgImAg6EZgIAEAAwFwAOhGxAyTm8BSxAwBAAMBdADoRxA444cQOmAgAQAQQOOEEEJgIAEBiBzjhBBA44QBAYgeYCAQQmAgAQADAXgCwE4QNuOOxA+j0AECEDbjjXBfo9ABAAMBfACYWsQOYCNwZmAgAQADAYADYCdgJUOxiB8buYgc88ZgIfPLYCTzxmAj872IHPPEAQADAYQBcFyYWxu4mFgAAAEAmFnzysBP87zoRxu6EDcbuGAv875gIfPJiByj2Ygee+JgIT\/wYC8X+hA0AADoRAACwE8X+JhZP\/ABAAMBiAFwXmAgk5pgIAAAAQJgIfPIYC\/zvhA3G7joRxu6wE\/zvJhZ88lwXKPZcF574JhZP\/LATxf46EQAAhA0AABgLxf6YCE\/8AEAAwGMAJhYmFnzysBP87zoRxu6EDcbuGAv875gIfPJiByj2Ygee+JgIT\/wYC8X+hA0AADoRAACwE8X+JhZP\/ABAAMBkAFwXJhYk5iYWAAAAQCYWfPKwE\/zvOhHG7oQNxu4YC\/zvmAh88mIHKPZiB574mAhP\/BgLxf6EDQAAOhEAALATxf4mFk\/8AEAAwGUAJhZiByj2JhYo9iYWsvPwFDzxsBP87zoRxu6EDcbuGAv875gIfPJiByj2Ygee+JgIT\/wYC8X+hA0AADoRAACwE8X+JhZP\/ABAAMBmAMQOBBAk5oQNJOYYC2Tn2AkQ69gJAAAAQCwGxu7EDsbuAEAAwGcAXBcmFsbuJhZ2AvAULAawE2IHOhGYCIQNmAgYC2IHAEAmFnzysBP87zoRxu6EDcbuGAv875gIfPJiByj2Ygee+JgIT\/wYC8X+hA0AADoRAACwE8X+JhZP\/ABAAMBoAFwXmAgk5pgIAAAAQJgIsvNODPzvxA7G7nASxu7wFPzvJhay8yYWAAAAQADAaQDYCWIHJOaYCGTn2Akk5pgI7uRiByTmAECYCMbumAgAAABAAMBqAE4M2Akk5hgLZOdODCTmGAvu5NgJJOYAQBgLxu4YC7ED2AliB2IHmAjsBJgIAEAAwGsA8BSYCCTmmAgAAABA8BTG7pgIFPsAQIQNKPYmFgAAAEAAwGwA2AmYCCTmmAgAAABAAMBtAOokmAjG7pgIAAAAQJgIsvNODPzvxA7G7nASxu7wFPzvJhay8yYWAAAAQCYWsvPcGfzvSBzG7v4fxu50IvzvtCOy87QjAAAAQADAbgBcF5gIxu6YCAAAAECYCLLzTgz878QOxu5wEsbu8BT87yYWsvMmFgAAAEAAwG8AXBeEDcbuGAv875gIfPJiByj2Ygee+JgIT\/wYC8X+hA0AADoRAACwE8X+JhZP\/FwXnvhcFyj2JhZ88rAT\/O86EcbuhA3G7gBAAMBwAFwXmAjG7pgImAgAQJgIfPIYC\/zvhA3G7joRxu6wE\/zvJhZ88lwXKPZcF574JhZP\/LATxf46EQAAhA0AABgLxf6YCE\/8AEAAwHEAXBcmFsbuJhaYCABAJhZ88rAT\/O86EcbuhA3G7hgL\/O+YCHzyYgco9mIHnviYCE\/8GAvF\/oQNAAA6EQAAsBPF\/iYWT\/wAQADAcgAEEJgIxu6YCAAAAECYCCj22Al88k4M\/O\/EDsbucBLG7gBAAMBzAPAU8BR88rAT\/O8EEMbuTgzG7pgI\/O9iB3zymAjo9BgLKPY6EWj3sBOe+PAUFPvwFE\/8sBPF\/gQQAABODAAAmAjF\/mIHT\/wAQADAdADEDtgJJObYCRT7GAvF\/oQNAAAEEAAAAEAsBsbuxA7G7gBAAMB1AFwXmAjG7pgIFPvYCcX+TgwAAAQQAABwEsX+JhYU+wBAJhbG7iYWAAAAQADAdgCwEywGxu6EDQAAAEDwFMbuhA0AAABAAMB3ABIbYgfG7k4MAAAAQDoRxu5ODAAAAEA6EcbuJhYAAABAEhvG7iYWAAAAQADAeADwFGIHxu7wFAAAAEDwFMbuYgcAAABAAMB5ALATLAbG7oQNAAAAQPAUxu6EDQAAGAvsBJgIYgcsBpgI7ASYCABAAMB6APAU8BTG7mIHAAAAQGIHxu7wFMbuAEBiBwAA8BQAAABAAMB7ADoRxA444U4MeOIYC7jj2Akk5tgJpOgYCxDrTgxQ7IQNxu6EDTzxGAuy8wBATgx44hgL7uQYC2TnTgza6YQNEOvEDpDtxA7874QNfPKYCOj0hA1o98QO1PnEDk\/8hA3F\/k4MAAAYC3YCGAvsBE4MYgcAQBgLKPaEDZ74hA0U+04Miv0YC8X+2Ak7AdgJsQMYCywGTgxiB8QOmAgAQADAfADYCZgIOOGYCJgIAEAAwH0AOhHYCTjhTgx44oQNuOPEDiTmxA6k6IQNEOtODFDsGAvG7hgLPPGEDbLzAEBODHjihA3u5IQNZOdODNrpGAsQ69gJkO3YCfzvGAt88gQQ6PQYC2j32AnU+dgJT\/wYC8X+TgwAAIQNdgKEDewETgxiBwBAhA0o9hgLnvgYCxT7TgyK\/YQNxf7EDjsBxA6xA4QNLAZODGIH2AmYCABAAMB+AIgdYgee+GIHKPaYCHzyGAs88YQNPPEEEHzy8BQo9lwXaPfcGWj3SBwo9ogdsvMAQGIHKPaYCLLzGAt88oQNfPIEELLz8BRo91wXnvjcGZ74SBxo94gdsvOIHTzxAEAAwA=="} ]; // Global code will be evaluated once. const turtle = new Turtle(); const text = new Text(fonts[font]); turtle.left(tilt); // The walk function will be called until it returns false. function walk(i) { const scale = .3 * (i+1); const size = text.size(turtle, txt, scale); const dimensions = text.dimensions(scale); const textStartPosition = [size.width / -2, 48 * i - 85]; //references to bounding box values to translate them to coordinates for box [[0,0],[1,0],[1,1],[0,1]] //read the bbox values and assing them .map(ref => [size.bbox[ref[0]][0], size.bbox[ref[1]][1]]) //center the box for transformation .map(pt => [pt[0] - size.width / 2, pt[1] + size.height / 2]) //add some padding to the box based on the dimensions of character 'x' .map(pt => [pt[0] + Math.sign(pt[0]) * dimensions.width, pt[1] + Math.sign(pt[1]) * dimensions.height]) //resetting the box to be translated to text position .map(pt => [pt[0] + size.width / 2, pt[1] - size.height / 2]) // translate it to the actual position .map(pt => [pt[0] + textStartPosition[0], pt[1] + textStartPosition[1]]) //draw lines .forEach((e,i,a) => { turtle.jump(e); turtle.goto(a[(i+1)%a.length]); }); //print text turtle.jump(textStartPosition); //another way to get the bounding box with absolute values // (instead of relative values used above) is to print with bboxPrint() const bbox = text.bboxPrint(turtle, txt, scale); // bbox will now contain the topleft point and bottomright point of the // rectangle that is the circumference of the printed text return i < 3; } //////////////////////////////////////////////////////////////// // Text utility code. Created by Reinder Nijhoff 2024 // https://turtletoy.net/turtle/0f84fd3ae4 // Modifications by Jurgen Westerhof 2024: https://turtletoy.net/turtle/9aef87b45e // - Does not force turtle to operate in radians // - Now respects turtle.isdown() and doesn't print if true // - Text.size(turtle, str, scale = 1) returns properties of text str to be printed // - Text.bbox(turtle, str, scale = 1) returns bounding box of text str to be printed // - Text.dimensions(scale = 1) returns properties of fontData for scale // - Text.bboxPrint(turtle, str, scale = 1) prints the text and returns the absolute bounding box //////////////////////////////////////////////////////////////// function Text(fontData) { const decode = (data) => { const b = atob(data), a = new Int16Array(b.length / 2), g = {}; for (let i = 0; i < b.length; i+=2) { a[i / 2 | 0] = b.charCodeAt(i) | (b.charCodeAt(i + 1) << 8); } for (let i = 0;i < a.length; i++) { let u = String.fromCharCode(a[i++]), x = a[i++], d = [], p = []; for (;a[i] !== -16384; i++) a[i] === 16384 ? (d.push(p), p = []) : p.push(a[i]); g[u] = { x, d }; } return g; } const rotAdd = (a, b, h) => [Math.cos(h)*a[0] - Math.sin(h)*a[1] + b[0], Math.cos(h)*a[1] + Math.sin(h)*a[0] + b[1]]; const data = Object.fromEntries(Object.entries(fontData).map(([key, value]) => [key, key === 'glyphs' ? decode(value) : value])); class RangeFinderTurtle extends Turtle { constructor(x, y) {super(x, y);this.reset();} goto(x, y) {super.goto(x, y);const [a, b] = this.pos();this.rangeX = [Math.min(a, this.rangeX? this.rangeX[0]: a), Math.max(a, this.rangeX? this.rangeX[1]: a)];this.rangeY = [Math.min(b, this.rangeY? this.rangeY[0]: b), Math.max(b, this.rangeY? this.rangeY[1]: b)];} reset() {const [a, b] = this.pos();this.rangeX = [a, a];this.rangeY = [b, b];} bbox() { return [[this.rangeX[0], this.rangeY[0]], [this.rangeX[1], this.rangeY[1]]]; } } class Text { print (t, str, scale = 1) { const isDown = t && t.isdown(); let pos = t ? [t.x(), t.y()] : [0,0], h = t ? t.h() * 2*Math.PI/t.fullCircle() : 0, o = pos, s = scale / data.unitsPerEm; str.split('').map(c => { if (c == '\n') { pos = o = rotAdd([0, 10 * scale], o, h); return; } const glyph = (data.glyphs[c] || data.glyphs[' ']), d = glyph.d; d.forEach( (p, k) => { t && t.up(); for (let i=0; i<p.length; i+=2) { t && t.goto(rotAdd([p[i]*s, p[i+1]*s], pos, h)); t && (!isDown || t.down()); } }); pos = rotAdd([glyph.x*s, 0], pos, h); }); if(isDown) t.down(); return rotAdd([0, 10*scale], pos, h); } bboxPrint(t, str, scale = 1) { const rft = new RangeFinderTurtle(t.pos()); rft.degrees(t.fullCircle()); rft.seth(t.h()); rft.up(); this.print(rft, str, scale); this.print(t, str, scale); return rft.bbox(); } size(t, str, scale = 1) { const rft = new RangeFinderTurtle(); rft.up(); this.print(rft, str, scale); return { width: rft.rangeX[1] - rft.rangeX[0], height: rft.rangeY[1] - rft.rangeY[0], bbox: t.h() === 0? rft.bbox(): this.bbox(t, str, scale) } } bbox(t, str, scale = 1) { const rft = new RangeFinderTurtle(); rft.degrees(t.fullCircle()); rft.seth(t.h()); rft.up(); this.print(rft, str, scale); return rft.bbox(); } dimensions(scale = 1, standardCharacter = 'x') { const t = new Turtle(); const x = this.size(t, standardCharacter, scale); const allLower = this.size(t, 'abcdefghijklmnopqrstuvwxyz', scale); const allUpper = this.size(t, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', scale); // property names from: https://www.onlineprinters.co.uk/magazine/font-sizes/ return { height: x.height, width: x.width, ascenders: Math.abs(allLower.bbox[0][1]) - x.height, descenders: Math.abs(allLower.bbox[1][1]), capitalHeight: Math.abs(allUpper.bbox[0][1]), capitalDescenders: Math.abs(allUpper.bbox[1][1]) }; } } return new Text(); }