123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242 |
- import {
- FileLoader,
- Loader,
- ShapePath
- } from 'three';
- /**
- * A loader for loading fonts.
- *
- * You can convert fonts online using [facetype.js]{@link https://gero3.github.io/facetype.js/}.
- *
- * ```js
- * const loader = new FontLoader();
- * const font = await loader.loadAsync( 'fonts/helvetiker_regular.typeface.json' );
- * ```
- *
- * @augments Loader
- * @three_import import { FontLoader } from 'three/addons/loaders/FontLoader.js';
- */
- class FontLoader extends Loader {
- /**
- * Constructs a new font loader.
- *
- * @param {LoadingManager} [manager] - The loading manager.
- */
- constructor( manager ) {
- super( manager );
- }
- /**
- * Starts loading from the given URL and passes the loaded font
- * to the `onLoad()` callback.
- *
- * @param {string} url - The path/URL of the file to be loaded. This can also be a data URI.
- * @param {function(Font)} onLoad - Executed when the loading process has been finished.
- * @param {onProgressCallback} onProgress - Executed while the loading is in progress.
- * @param {onErrorCallback} onError - Executed when errors occur.
- */
- load( url, onLoad, onProgress, onError ) {
- const scope = this;
- const loader = new FileLoader( this.manager );
- loader.setPath( this.path );
- loader.setRequestHeader( this.requestHeader );
- loader.setWithCredentials( this.withCredentials );
- loader.load( url, function ( text ) {
- const font = scope.parse( JSON.parse( text ) );
- if ( onLoad ) onLoad( font );
- }, onProgress, onError );
- }
- /**
- * Parses the given font data and returns the resulting font.
- *
- * @param {Object} json - The raw font data as a JSON object.
- * @return {Font} The font.
- */
- parse( json ) {
- return new Font( json );
- }
- }
- /**
- * Class representing a font.
- */
- class Font {
- /**
- * Constructs a new font.
- *
- * @param {Object} data - The font data as JSON.
- */
- constructor( data ) {
- /**
- * This flag can be used for type testing.
- *
- * @type {boolean}
- * @readonly
- * @default true
- */
- this.isFont = true;
- this.type = 'Font';
- /**
- * The font data as JSON.
- *
- * @type {Object}
- */
- this.data = data;
- }
- /**
- * Generates geometry shapes from the given text and size. The result of this method
- * should be used with {@link ShapeGeometry} to generate the actual geometry data.
- *
- * @param {string} text - The text.
- * @param {number} [size=100] - The text size.
- * @return {Array<Shape>} An array of shapes representing the text.
- */
- generateShapes( text, size = 100 ) {
- const shapes = [];
- const paths = createPaths( text, size, this.data );
- for ( let p = 0, pl = paths.length; p < pl; p ++ ) {
- shapes.push( ...paths[ p ].toShapes() );
- }
- return shapes;
- }
- }
- function createPaths( text, size, data ) {
- const chars = Array.from( text );
- const scale = size / data.resolution;
- const line_height = ( data.boundingBox.yMax - data.boundingBox.yMin + data.underlineThickness ) * scale;
- const paths = [];
- let offsetX = 0, offsetY = 0;
- for ( let i = 0; i < chars.length; i ++ ) {
- const char = chars[ i ];
- if ( char === '\n' ) {
- offsetX = 0;
- offsetY -= line_height;
- } else {
- const ret = createPath( char, scale, offsetX, offsetY, data );
- offsetX += ret.offsetX;
- paths.push( ret.path );
- }
- }
- return paths;
- }
- function createPath( char, scale, offsetX, offsetY, data ) {
- const glyph = data.glyphs[ char ] || data.glyphs[ '?' ];
- if ( ! glyph ) {
- console.error( 'THREE.Font: character "' + char + '" does not exists in font family ' + data.familyName + '.' );
- return;
- }
- const path = new ShapePath();
- let x, y, cpx, cpy, cpx1, cpy1, cpx2, cpy2;
- if ( glyph.o ) {
- const outline = glyph._cachedOutline || ( glyph._cachedOutline = glyph.o.split( ' ' ) );
- for ( let i = 0, l = outline.length; i < l; ) {
- const action = outline[ i ++ ];
- switch ( action ) {
- case 'm': // moveTo
- x = outline[ i ++ ] * scale + offsetX;
- y = outline[ i ++ ] * scale + offsetY;
- path.moveTo( x, y );
- break;
- case 'l': // lineTo
- x = outline[ i ++ ] * scale + offsetX;
- y = outline[ i ++ ] * scale + offsetY;
- path.lineTo( x, y );
- break;
- case 'q': // quadraticCurveTo
- cpx = outline[ i ++ ] * scale + offsetX;
- cpy = outline[ i ++ ] * scale + offsetY;
- cpx1 = outline[ i ++ ] * scale + offsetX;
- cpy1 = outline[ i ++ ] * scale + offsetY;
- path.quadraticCurveTo( cpx1, cpy1, cpx, cpy );
- break;
- case 'b': // bezierCurveTo
- cpx = outline[ i ++ ] * scale + offsetX;
- cpy = outline[ i ++ ] * scale + offsetY;
- cpx1 = outline[ i ++ ] * scale + offsetX;
- cpy1 = outline[ i ++ ] * scale + offsetY;
- cpx2 = outline[ i ++ ] * scale + offsetX;
- cpy2 = outline[ i ++ ] * scale + offsetY;
- path.bezierCurveTo( cpx1, cpy1, cpx2, cpy2, cpx, cpy );
- break;
- }
- }
- }
- return { offsetX: glyph.ha * scale, path: path };
- }
- export { FontLoader, Font };
|