@@ -65,6 +65,7 @@ class Font {
65
65
/**
66
66
* Checks whether a font has glyph point data and
67
67
* can thus be used for textToPoints(), WEBGL mode, etc.
68
+ * @private
68
69
*/
69
70
static hasGlyphData ( textFont ) {
70
71
let { font } = textFont ;
@@ -104,6 +105,62 @@ class Font {
104
105
return glyphs . map ( g => g . path . commands ) . flat ( ) ;
105
106
}
106
107
108
+ /**
109
+ * Returns an array of points outlining a string of text written using the
110
+ * font.
111
+ *
112
+ * Each point object in the array has three properties that describe the
113
+ * point's location and orientation, called its path angle. For example,
114
+ * `{ x: 10, y: 20, alpha: 450 }`.
115
+ *
116
+ * The first parameter, `str`, is a string of text. The second and third
117
+ * parameters, `x` and `y`, are the text's position. By default, they set the
118
+ * coordinates of the bounding box's bottom-left corner. See
119
+ * <a href="#/p5/textAlign">textAlign()</a> for more ways to align text.
120
+ *
121
+ * The fourth parameter, `options`, is also optional. `font.textToPoints()`
122
+ * expects an object with the following properties:
123
+ *
124
+ * `sampleFactor` is the ratio of the text's path length to the number of
125
+ * samples. It defaults to 0.1. Higher values produce more points along the
126
+ * path and are more precise.
127
+ *
128
+ * `simplifyThreshold` removes collinear points if it's set to a number other
129
+ * than 0. The value represents the threshold angle to use when determining
130
+ * whether two edges are collinear.
131
+ *
132
+ * @param {String } str string of text.
133
+ * @param {Number } x x-coordinate of the text.
134
+ * @param {Number } y y-coordinate of the text.
135
+ * @param {Object } [options] object with sampleFactor and simplifyThreshold
136
+ * properties.
137
+ * @return {Array<Object> } array of point objects, each with `x`, `y`, and `alpha` (path angle) properties.
138
+ *
139
+ * @example
140
+ * <div>
141
+ * <code>
142
+ * let font;
143
+ *
144
+ * async function setup() {
145
+ * createCanvas(100, 100);
146
+ * font = await loadFont('assets/inconsolata.otf');
147
+ *
148
+ * background(200);
149
+ * textSize(35);
150
+ *
151
+ * // Get the point array.
152
+ * let points = font.textToPoints('p5*js', 6, 60, { sampleFactor: 0.5 });
153
+ *
154
+ * // Draw a dot at each point.
155
+ * for (let p of points) {
156
+ * point(p.x, p.y);
157
+ * }
158
+ *
159
+ * describe('A set of black dots outlining the text "p5*js" on a gray background.');
160
+ * }
161
+ * </code>
162
+ * </div>
163
+ */
107
164
textToPoints ( str , x , y , width , height , options ) {
108
165
// By segmenting per contour, pointAtLength becomes much faster
109
166
const contourPoints = this . textToContours ( str , x , y , width , height , options ) ;
@@ -113,6 +170,71 @@ class Font {
113
170
} , [ ] ) ;
114
171
}
115
172
173
+ /**
174
+ * Returns an array of arrays of points outlining a string of text written using the
175
+ * font. Each array represents a contour, so the letter O will have two outer arrays:
176
+ * one for the outer edge of the shape, and one for the inner edge of the hole.
177
+ *
178
+ * Each point object in a contour array has three properties that describe the
179
+ * point's location and orientation, called its path angle. For example,
180
+ * `{ x: 10, y: 20, alpha: 450 }`.
181
+ *
182
+ * The first parameter, `str`, is a string of text. The second and third
183
+ * parameters, `x` and `y`, are the text's position. By default, they set the
184
+ * coordinates of the bounding box's bottom-left corner. See
185
+ * <a href="#/p5/textAlign">textAlign()</a> for more ways to align text.
186
+ *
187
+ * The fourth parameter, `options`, is also optional. `font.textToPoints()`
188
+ * expects an object with the following properties:
189
+ *
190
+ * `sampleFactor` is the ratio of the text's path length to the number of
191
+ * samples. It defaults to 0.1. Higher values produce more points along the
192
+ * path and are more precise.
193
+ *
194
+ * `simplifyThreshold` removes collinear points if it's set to a number other
195
+ * than 0. The value represents the threshold angle to use when determining
196
+ * whether two edges are collinear.
197
+ *
198
+ * @param {String } str string of text.
199
+ * @param {Number } x x-coordinate of the text.
200
+ * @param {Number } y y-coordinate of the text.
201
+ * @param {Object } [options] object with sampleFactor and simplifyThreshold
202
+ * properties.
203
+ * @return {Array<Array<Object>> } array of point objects, each with `x`, `y`, and `alpha` (path angle) properties.
204
+ *
205
+ * @example
206
+ * <div>
207
+ * <code>
208
+ * let font;
209
+ *
210
+ * async function setup() {
211
+ * createCanvas(100, 100);
212
+ * font = await loadFont('/assets/inconsolata.otf');
213
+ * }
214
+ *
215
+ * function draw() {
216
+ * background(200);
217
+ * textAlign(CENTER, CENTER);
218
+ * textSize(30);
219
+ *
220
+ * // Get the point array.
221
+ * let contours = font.textToContours('p5*js', width/2, height/2, { sampleFactor: 0.5 });
222
+ *
223
+ * beginShape();
224
+ * for (const pts of contours) {
225
+ * beginContour();
226
+ * for (const pt of pts) {
227
+ * vertex(pt.x + 5*sin(pt.y*0.1 + millis()*0.01), pt.y);
228
+ * }
229
+ * endContour(CLOSE);
230
+ * }
231
+ * endShape();
232
+ *
233
+ * describe('The text p5*js wobbling over time');
234
+ * }
235
+ * </code>
236
+ * </div>
237
+ */
116
238
textToContours ( str , x = 0 , y = 0 , width , height , options ) {
117
239
( { width, height, options } = this . _parseArgs ( width , height , options ) ) ;
118
240
@@ -688,20 +810,158 @@ function parseCreateArgs(...args/*path, name, onSuccess, onError*/) {
688
810
function font ( p5 , fn ) {
689
811
690
812
/**
691
- * TODO
813
+ * A class to describe fonts. Create through <a href="#/p5/loadFont">`loadFont()`</a>.
692
814
*
693
815
* @class p5.Font
694
816
*/
695
817
p5 . Font = Font ;
696
818
697
819
/**
698
- * Load a font and returns a p5.Font instance. The font can be specified by its path or a url.
699
- * Optional arguments include the font name, descriptors for the FontFace object,
700
- * and callbacks for success and error.
820
+ * Loads a font and creates a <a href="#/p5.Font">p5.Font</a> object.
821
+ * `loadFont()` can load fonts in either .otf or .ttf format. Loaded fonts can
822
+ * be used to style text on the canvas and in HTML elements.
823
+ *
824
+ * The first parameter, `path`, is the path to a font file.
825
+ * Paths to local files should be relative. For example,
826
+ * `'assets/inconsolata.otf'`. The Inconsolata font used in the following
827
+ * examples can be downloaded for free
828
+ * <a href="https://www.fontsquirrel.com/fonts/inconsolata" target="_blank">here</a>.
829
+ * Paths to remote files should be URLs. For example,
830
+ * `'https://example.com/inconsolata.otf'`. URLs may be blocked due to browser
831
+ * security.
832
+ *
833
+ * In 2D mode, `path` can take on a few other forms. It could be a path to a CSS file,
834
+ * such as one from <a href="https://fonts.google.com/">Google Fonts.</a> It could also
835
+ * be a string with a <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face">CSS `@font-face` declaration.</a> It can also be an object containing key-value pairs with
836
+ * properties that you would find in an `@font-face` block.
837
+ *
838
+ * The second parameter, `successCallback`, is optional. If a function is
839
+ * passed, it will be called once the font has loaded. The callback function
840
+ * may use the new <a href="#/p5.Font">p5.Font</a> object if needed.
841
+ *
842
+ * The third parameter, `failureCallback`, is also optional. If a function is
843
+ * passed, it will be called if the font fails to load. The callback function
844
+ * may use the error
845
+ * <a href="https://developer.mozilla.org/en-US/docs/Web/API/Event" target="_blank">Event</a>
846
+ * object if needed.
847
+ *
848
+ * Fonts can take time to load. `await` the result of `loadFont()` in
849
+ * <a href="#/p5/setup">setup()</a> before using the result.
850
+ *
701
851
* @method loadFont
702
- * @param {...any } args - path, name, onSuccess, onError, descriptors
703
- * @returns a Promise that resolves with a p5.Font instance
852
+ * @for p5
853
+ * @param {String|Object } path path of the font to be loaded, a CSS `@font-face` string, or an object with font face properties.
854
+ * @param {String } [name] An alias that can be used for this font in `textFont()`. Defaults to the name in the font's metadata.
855
+ * @param {Function } [successCallback] function called with the
856
+ * <a href="#/p5.Font">p5.Font</a> object after it
857
+ * loads.
858
+ * @param {Function } [failureCallback] function called with the error
859
+ * <a href="https://developer.mozilla.org/en-US/docs/Web/API/Event" target="_blank">Event</a>
860
+ * object if the font fails to load.
861
+ * @return {Promise<p5.Font> } <a href="#/p5.Font">p5.Font</a> object.
862
+ * @example
863
+ * <div>
864
+ * <code>
865
+ * let font;
866
+ *
867
+ * async function setup() {
868
+ * createCanvas(100, 100);
869
+ * font = await loadFont('assets/inconsolata.otf');
870
+ * fill('deeppink');
871
+ * textFont(font);
872
+ * textSize(36);
873
+ * text('p5*js', 10, 50);
874
+ *
875
+ * describe('The text "p5*js" written in pink on a white background.');
876
+ * }
877
+ * </code>
878
+ * </div>
879
+ *
880
+ * @example
881
+ * <div>
882
+ * <code>
883
+ * function setup() {
884
+ * createCanvas(100, 100);
885
+ * loadFont('assets/inconsolata.otf', font => {
886
+ * fill('deeppink');
887
+ * textFont(font);
888
+ * textSize(36);
889
+ * text('p5*js', 10, 50);
890
+ *
891
+ * describe('The text "p5*js" written in pink on a white background.');
892
+ * });
893
+ * }
894
+ * </code>
895
+ * </div>
896
+ *
897
+ * @example
898
+ * <div>
899
+ * <code>
900
+ * function setup() {
901
+ * createCanvas(100, 100);
902
+ * loadFont('assets/inconsolata.otf', success, failure);
903
+ * }
904
+ *
905
+ * function success(font) {
906
+ * fill('deeppink');
907
+ * textFont(font);
908
+ * textSize(36);
909
+ * text('p5*js', 10, 50);
910
+ *
911
+ * describe('The text "p5*js" written in pink on a white background.');
912
+ * }
913
+ *
914
+ * function failure(event) {
915
+ * console.error('Oops!', event);
916
+ * }
917
+ * </code>
918
+ * </div>
919
+ *
920
+ * @example
921
+ * <div>
922
+ * <code>
923
+ * async function setup() {
924
+ * createCanvas(100, 100);
925
+ * await loadFont('assets/inconsolata.otf');
926
+ * let p = createP('p5*js');
927
+ * p.style('color', 'deeppink');
928
+ * p.style('font-family', 'Inconsolata');
929
+ * p.style('font-size', '36px');
930
+ * p.position(10, 50);
931
+ *
932
+ * describe('The text "p5*js" written in pink on a white background.');
933
+ * }
934
+ * </code>
935
+ * </div>
936
+ *
937
+ * @example
938
+ * <div class="norender">
939
+ * <code>
940
+ * // Some other forms of loading fonts:
941
+ * loadFont("https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,[email protected] ,200..800&display=swap");
942
+ * loadFont(`@font-face { font-family: "Bricolage Grotesque", serif; font-optical-sizing: auto; font-weight: 400; font-style: normal; font-variation-settings: "wdth" 100; }`);
943
+ * loadFont({
944
+ * fontFamily: '"Bricolage Grotesque", serif',
945
+ * fontOpticalSizing: 'auto',
946
+ * fontWeight: 400,
947
+ * fontStyle: 'normal',
948
+ * fontVariationSettings: '"wdth" 100',
949
+ * });
950
+ * </code>
951
+ * </div>
704
952
*/
953
+ /**
954
+ * @method loadFont
955
+ * @for p5
956
+ * @param {String } path path of the font to be loaded.
957
+ * @param {Function } [successCallback] function called with the
958
+ * <a href="#/p5.Font">p5.Font</a> object after it
959
+ * loads.
960
+ * @param {Function } [failureCallback] function called with the error
961
+ * <a href="https://developer.mozilla.org/en-US/docs/Web/API/Event" target="_blank">Event</a>
962
+ * object if the font fails to load.
963
+ * @returns {Promise<p5.Font> } The font.
964
+ */
705
965
fn . loadFont = async function ( ...args /*path, name, onSuccess, onError, descriptors*/ ) {
706
966
707
967
let { path, name, success, error, descriptors } = parseCreateArgs ( ...args ) ;
0 commit comments