Font.js 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. import { ShapePath } from './ShapePath.js';
  2. function Font( data ) {
  3. this.type = 'Font';
  4. this.data = data;
  5. }
  6. Object.assign( Font.prototype, {
  7. isFont: true,
  8. generateShapes: function ( text, size = 100 ) {
  9. const shapes = [];
  10. const paths = createPaths( text, size, this.data );
  11. for ( let p = 0, pl = paths.length; p < pl; p ++ ) {
  12. Array.prototype.push.apply( shapes, paths[ p ].toShapes() );
  13. }
  14. return shapes;
  15. }
  16. } );
  17. function createPaths( text, size, data ) {
  18. const chars = Array.from ? Array.from( text ) : String( text ).split( '' ); // workaround for IE11, see #13988
  19. const scale = size / data.resolution;
  20. const line_height = ( data.boundingBox.yMax - data.boundingBox.yMin + data.underlineThickness ) * scale;
  21. const paths = [];
  22. let offsetX = 0, offsetY = 0;
  23. for ( let i = 0; i < chars.length; i ++ ) {
  24. const char = chars[ i ];
  25. if ( char === '\n' ) {
  26. offsetX = 0;
  27. offsetY -= line_height;
  28. } else {
  29. const ret = createPath( char, scale, offsetX, offsetY, data );
  30. offsetX += ret.offsetX;
  31. paths.push( ret.path );
  32. }
  33. }
  34. return paths;
  35. }
  36. function createPath( char, scale, offsetX, offsetY, data ) {
  37. const glyph = data.glyphs[ char ] || data.glyphs[ '?' ];
  38. if ( ! glyph ) {
  39. console.error( 'THREE.Font: character "' + char + '" does not exists in font family ' + data.familyName + '.' );
  40. return;
  41. }
  42. const path = new ShapePath();
  43. let x, y, cpx, cpy, cpx1, cpy1, cpx2, cpy2;
  44. if ( glyph.o ) {
  45. const outline = glyph._cachedOutline || ( glyph._cachedOutline = glyph.o.split( ' ' ) );
  46. for ( let i = 0, l = outline.length; i < l; ) {
  47. const action = outline[ i ++ ];
  48. switch ( action ) {
  49. case 'm': // moveTo
  50. x = outline[ i ++ ] * scale + offsetX;
  51. y = outline[ i ++ ] * scale + offsetY;
  52. path.moveTo( x, y );
  53. break;
  54. case 'l': // lineTo
  55. x = outline[ i ++ ] * scale + offsetX;
  56. y = outline[ i ++ ] * scale + offsetY;
  57. path.lineTo( x, y );
  58. break;
  59. case 'q': // quadraticCurveTo
  60. cpx = outline[ i ++ ] * scale + offsetX;
  61. cpy = outline[ i ++ ] * scale + offsetY;
  62. cpx1 = outline[ i ++ ] * scale + offsetX;
  63. cpy1 = outline[ i ++ ] * scale + offsetY;
  64. path.quadraticCurveTo( cpx1, cpy1, cpx, cpy );
  65. break;
  66. case 'b': // bezierCurveTo
  67. cpx = outline[ i ++ ] * scale + offsetX;
  68. cpy = outline[ i ++ ] * scale + offsetY;
  69. cpx1 = outline[ i ++ ] * scale + offsetX;
  70. cpy1 = outline[ i ++ ] * scale + offsetY;
  71. cpx2 = outline[ i ++ ] * scale + offsetX;
  72. cpy2 = outline[ i ++ ] * scale + offsetY;
  73. path.bezierCurveTo( cpx1, cpy1, cpx2, cpy2, cpx, cpy );
  74. break;
  75. }
  76. }
  77. }
  78. return { offsetX: glyph.ha * scale, path: path };
  79. }
  80. export { Font };