-
-
Notifications
You must be signed in to change notification settings - Fork 195
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: ex.FontSource resource type (#2934)
## Changes: - Added `ex.FontSource` resource type ```typescript const fontSource = new ex.FontSource('/my-font.ttf', 'My Font') loader.addResource(fontSource) game.start(loader).then(() => { const font = fontSource.toFont() // returns ex.Font }) ``` Font options can be defined either at the source or at the `toFont()` call. If defined in both, `toFont(options)` will override the options in the `FontSource`. ```typescript const fontSource = new ex.FontSource('/my-font.ttf', 'My Font', { filtering: ex.ImageFiltering.Pixel, size: 16, // set a default size }) const font = fontSource.toFont({ // override just the size size: 20, }) ``` - adds `"dom.iterable"` to `lib` in tsconfig.json as it was needed to get the correct types for `document.fonts`
- Loading branch information
1 parent
9d21bae
commit a981c5d
Showing
8 changed files
with
185 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
import { Font } from '../Graphics/Font'; | ||
import { FontOptions } from '../Graphics/FontCommon'; | ||
import { GraphicOptions, RasterOptions } from '../Graphics'; | ||
import { Loadable } from '../Interfaces/Loadable'; | ||
import { Resource } from './Resource'; | ||
|
||
|
||
export interface FontSourceOptions | ||
extends Omit<FontOptions, 'family'>, | ||
GraphicOptions, | ||
RasterOptions { | ||
/** | ||
* Whether or not to cache-bust requests | ||
*/ | ||
bustCache?: boolean | ||
} | ||
|
||
export class FontSource implements Loadable<FontFace> { | ||
private _resource: Resource<Blob>; | ||
private _isLoaded = false; | ||
private _options: FontSourceOptions; | ||
|
||
data!: FontFace; | ||
|
||
|
||
constructor( | ||
/** | ||
* Path to the font resource relative from the HTML document hosting the game, or absolute | ||
*/ | ||
public readonly path: string, | ||
/** | ||
* The font family name | ||
*/ | ||
public readonly family: string, | ||
{ bustCache, ...options }: FontSourceOptions = {} | ||
) { | ||
this._resource = new Resource(path, 'blob', bustCache); | ||
this._options = options; | ||
} | ||
|
||
async load(): Promise<FontFace> { | ||
if (this.isLoaded()) { | ||
return this.data; | ||
} | ||
|
||
try { | ||
const blob = await this._resource.load(); | ||
const url = URL.createObjectURL(blob); | ||
|
||
if (!this.data) { | ||
this.data = new FontFace(this.family, `url(${url})`); | ||
document.fonts.add(this.data); | ||
} | ||
|
||
await this.data.load(); | ||
this._isLoaded = true; | ||
} catch (error) { | ||
throw `Error loading FontSource from path '${this.path}' with error [${ | ||
(error as Error).message | ||
}]`; | ||
} | ||
return this.data; | ||
} | ||
|
||
isLoaded(): boolean { | ||
return this._isLoaded; | ||
} | ||
|
||
/** | ||
* Build a font from this FontSource. | ||
* @param options {FontOptions} Override the font options | ||
*/ | ||
toFont(options?: FontOptions): Font { | ||
return new Font({ family: this.family, ...this._options, ...options }); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
export * from './Resource'; | ||
export * from './Sound/Index'; | ||
export * from './Gif'; | ||
export * from './Font'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -20,6 +20,7 @@ | |
"downlevelIteration": true, | ||
"lib": [ | ||
"dom", | ||
"dom.iterable", | ||
"es5", | ||
"es2018" | ||
], | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
import * as ex from '@excalibur'; | ||
|
||
describe('A FontSource', () => { | ||
it('exists', () => { | ||
expect(ex.FontSource).toBeDefined(); | ||
}); | ||
|
||
it('can be constructed', () => { | ||
const fontSource = new ex.FontSource('src/spec/fonts/Gorgeous Pixel.ttf', 'Gorgeous Pixel'); | ||
expect(fontSource).toBeDefined(); | ||
}); | ||
|
||
it('can load fonts', async () => { | ||
const fontSource = new ex.FontSource('src/spec/fonts/Gorgeous Pixel.ttf', 'Gorgeous Pixel'); | ||
|
||
await fontSource.load(); | ||
|
||
expect(fontSource.data).not.toBeUndefined(); | ||
}); | ||
|
||
it('adds a FontFace to document.fonts', async () => { | ||
const fontSource = new ex.FontSource('src/spec/fonts/Gorgeous Pixel.ttf', 'Gorgeous Pixel'); | ||
|
||
await fontSource.load(); | ||
|
||
expect(document.fonts.has(fontSource.data)).toBeTrue(); | ||
}); | ||
|
||
it('can convert to a Font', async () => { | ||
const fontSource = new ex.FontSource('src/spec/fonts/Gorgeous Pixel.ttf', 'Gorgeous Pixel'); | ||
|
||
await fontSource.load(); | ||
const font = fontSource.toFont(); | ||
|
||
expect(font).toBeInstanceOf(ex.Font); | ||
}); | ||
|
||
it('will use options from FontSource', async () => { | ||
const fontSource = new ex.FontSource('src/spec/fonts/Gorgeous Pixel.ttf', 'Gorgeous Pixel', { | ||
size: 50 | ||
}); | ||
|
||
await fontSource.load(); | ||
const font = fontSource.toFont(); | ||
|
||
expect(font.size).toBe(50); | ||
}); | ||
|
||
it('will override options when converting to a Font', async () => { | ||
const fontSource = new ex.FontSource('src/spec/fonts/Gorgeous Pixel.ttf', 'Gorgeous Pixel', { | ||
size: 50, | ||
opacity: 0.5 | ||
}); | ||
|
||
await fontSource.load(); | ||
const font = fontSource.toFont({ | ||
size: 100 | ||
}); | ||
|
||
expect(font.size).toBe(100); | ||
expect(font.opacity).toBe(0.5); | ||
}); | ||
|
||
it('will resolve the font if already loaded', async () => { | ||
const fontSource = new ex.FontSource('src/spec/fonts/Gorgeous Pixel.ttf', 'Gorgeous Pixel'); | ||
|
||
const font = await fontSource.load(); | ||
|
||
expect(fontSource.isLoaded()).toBe(true); | ||
const alreadyLoadedFont = await fontSource.load(); | ||
|
||
expect(font).toBe(alreadyLoadedFont); | ||
}); | ||
|
||
it('will return error if font doesn\'t exist', async () => { | ||
const fontSource = new ex.FontSource('42.ttf', '42'); | ||
|
||
await expectAsync(fontSource.load()).toBeRejectedWith( | ||
'Error loading FontSource from path \'42.ttf\' with error [Not Found]' | ||
); | ||
}); | ||
}); |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters