1
- /**
1
+ /**
2
2
* API:
3
3
* loadFont("https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,[email protected] ,200..800&display=swap")
4
4
* loadFont("{ font-family: "Bricolage Grotesque", serif; font-optical-sizing: auto; font-weight: <weight> font-style: normal; font-variation-settings: "wdth" 100; });
5
- * loadFont({
6
- * fontFamily: '"Bricolage Grotesque", serif';
5
+ * loadFont({
6
+ * fontFamily: '"Bricolage Grotesque", serif';
7
7
* fontOpticalSizing: 'auto';
8
8
* fontWeight: '<weight>';
9
9
* fontStyle: 'normal';
10
- * fontVariationSettings: '"wdth" 100';
10
+ * fontVariationSettings: '"wdth" 100';
11
11
* });
12
12
* loadFont("https://fonts.gstatic.com/s/bricolagegrotesque/v1/pxiAZBhjZQIdd8jGnEotWQ.woff2");
13
13
* loadFont("./path/to/localFont.ttf");
14
14
* loadFont("system-font-name");
15
- *
16
- *
15
+ *
16
+ *
17
17
* NEXT:
18
18
* extract axes from font file
19
- *
20
- * TEST:
19
+ *
20
+ * TEST:
21
21
* const font = new FontFace("Inter", "url(./fonts/inter-latin-variable-full-font.woff2)", {
22
22
style: "oblique 0deg 10deg",
23
23
weight: "100 900",
@@ -53,6 +53,16 @@ function font(p5, fn) {
53
53
this . face = fontFace ;
54
54
}
55
55
56
+ verticalAlign ( size ) {
57
+ const { sCapHeight } = this . data ?. [ 'OS/2' ] || { } ;
58
+ const { unitsPerEm = 1000 } = this . data ?. head || { } ;
59
+ const { ascender = 0 , descender = 0 } = this . data ?. hhea || { } ;
60
+ const current = ascender / 2 ;
61
+ const target = ( sCapHeight || ( ascender + descender ) ) / 2 ;
62
+ const offset = target - current ;
63
+ return offset * size / unitsPerEm ;
64
+ }
65
+
56
66
variations ( ) {
57
67
let vars = { } ;
58
68
if ( this . data ) {
@@ -254,20 +264,63 @@ function font(p5, fn) {
254
264
return lines . map ( coordify ) ;
255
265
}
256
266
257
- _lineToGlyphs ( line , scale ) {
267
+ _lineToGlyphs ( line , scale = 1 ) {
258
268
259
269
if ( ! this . data ) {
260
270
throw Error ( 'No font data available for "' + this . name
261
271
+ '"\nTry downloading a local copy of the font file' ) ;
262
272
}
263
273
let glyphShapes = Typr . U . shape ( this . data , line . text ) ;
274
+ line . glyphShapes = glyphShapes ;
264
275
line . glyphs = this . _shapeToPaths ( glyphShapes , line , scale ) ;
265
276
266
277
return line ;
267
278
}
268
279
269
- _shapeToPaths ( glyphs , line , scale ) {
280
+ _positionGlyphs ( text ) {
281
+ const glyphShapes = Typr . U . shape ( this . data , text ) ;
282
+ const positionedGlyphs = [ ] ;
283
+ let x = 0 ;
284
+ for ( const glyph of glyphShapes ) {
285
+ positionedGlyphs . push ( { x, index : glyph . g , shape : glyph } ) ;
286
+ x += glyph . ax ;
287
+ }
288
+ return positionedGlyphs ;
289
+ }
290
+
291
+ _singleShapeToPath ( shape , { scale = 1 , x = 0 , y = 0 , lineX = 0 , lineY = 0 } = { } ) {
270
292
let font = this . data ;
293
+ let crdIdx = 0 ;
294
+ let { g, ax, ay, dx, dy } = shape ;
295
+ let { crds, cmds } = Typr . U . glyphToPath ( font , g ) ;
296
+
297
+ // can get simple points for each glyph here, but we don't need them ?
298
+ let glyph = { /*g: line.text[i], points: [],*/ path : { commands : [ ] } } ;
299
+
300
+ for ( let j = 0 ; j < cmds . length ; j ++ ) {
301
+ let type = cmds [ j ] , command = [ type ] ;
302
+ if ( type in pathArgCounts ) {
303
+ let argCount = pathArgCounts [ type ] ;
304
+ for ( let k = 0 ; k < argCount ; k += 2 ) {
305
+ let gx = crds [ k + crdIdx ] + x + dx ;
306
+ let gy = crds [ k + crdIdx + 1 ] + y + dy ;
307
+ let fx = lineX + gx * scale ;
308
+ let fy = lineY + gy * - scale ;
309
+ command . push ( fx ) ;
310
+ command . push ( fy ) ;
311
+ /*if (k === argCount - 2) {
312
+ glyph.points.push({ x: fx, y: fy });
313
+ }*/
314
+ }
315
+ crdIdx += argCount ;
316
+ }
317
+ glyph . path . commands . push ( command ) ;
318
+ }
319
+
320
+ return { glyph, ax, ay } ;
321
+ }
322
+
323
+ _shapeToPaths ( glyphs , line , scale = 1 ) {
271
324
let x = 0 , y = 0 , paths = [ ] ;
272
325
273
326
if ( glyphs . length !== line . text . length ) {
@@ -277,32 +330,14 @@ function font(p5, fn) {
277
330
// iterate over the glyphs, converting each to a glyph object
278
331
// with a path property containing an array of commands
279
332
for ( let i = 0 ; i < glyphs . length ; i ++ ) {
280
- let crdIdx = 0 ;
281
- let { g, ax, ay, dx, dy } = glyphs [ i ] ;
282
- let { crds, cmds } = Typr . U . glyphToPath ( font , g ) ;
283
-
284
- // can get simple points for each glyph here, but we don't need them ?
285
- let glyph = { g : line . text [ i ] , /*points: [],*/ path : { commands : [ ] } } ;
286
-
287
- for ( let j = 0 ; j < cmds . length ; j ++ ) {
288
- let type = cmds [ j ] , command = [ type ] ;
289
- if ( type in pathArgCounts ) {
290
- let argCount = pathArgCounts [ type ] ;
291
- for ( let k = 0 ; k < argCount ; k += 2 ) {
292
- let gx = crds [ k + crdIdx ] + x + dx ;
293
- let gy = crds [ k + crdIdx + 1 ] + y + dy ;
294
- let fx = line . x + gx * scale ;
295
- let fy = line . y + gy * - scale ;
296
- command . push ( fx ) ;
297
- command . push ( fy ) ;
298
- /*if (k === argCount - 2) {
299
- glyph.points.push({ x: fx, y: fy });
300
- }*/
301
- }
302
- crdIdx += argCount ;
303
- }
304
- glyph . path . commands . push ( command ) ;
305
- }
333
+ const { glyph, ax, ay } = this . _singleShapeToPath ( glyphs [ i ] , {
334
+ scale,
335
+ x,
336
+ y,
337
+ lineX : line . x ,
338
+ lineY : line . y ,
339
+ } ) ;
340
+
306
341
paths . push ( glyph ) ;
307
342
x += ax ; y += ay ;
308
343
}
@@ -411,7 +446,7 @@ function font(p5, fn) {
411
446
412
447
/**
413
448
* Load a font and returns a p5.Font instance. The font can be specified by its path or a url.
414
- * Optional arguments include the font name, descriptors for the FontFace object,
449
+ * Optional arguments include the font name, descriptors for the FontFace object,
415
450
* and callbacks for success and error.
416
451
* @param {...any } args - path, name, onSuccess, onError, descriptors
417
452
* @returns a Promise that resolves with a p5.Font instance
@@ -430,7 +465,7 @@ function font(p5, fn) {
430
465
431
466
// parse the font data
432
467
let fonts = Typr . parse ( result ) ;
433
-
468
+
434
469
if ( fonts . length !== 1 || fonts [ 0 ] . cmap === undefined ) {
435
470
throw Error ( 23 ) ;
436
471
}
@@ -1059,4 +1094,4 @@ export default font;
1059
1094
1060
1095
if ( typeof p5 !== 'undefined' ) {
1061
1096
font ( p5 , p5 . prototype ) ;
1062
- }
1097
+ }
0 commit comments