@@ -65,6 +65,7 @@ class Font {
6565 /**
6666 * Checks whether a font has glyph point data and
6767 * can thus be used for textToPoints(), WEBGL mode, etc.
68+ * @private
6869 */
6970 static hasGlyphData ( textFont ) {
7071 let { font } = textFont ;
@@ -104,6 +105,62 @@ class Font {
104105 return glyphs . map ( g => g . path . commands ) . flat ( ) ;
105106 }
106107
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+ */
107164 textToPoints ( str , x , y , width , height , options ) {
108165 // By segmenting per contour, pointAtLength becomes much faster
109166 const contourPoints = this . textToContours ( str , x , y , width , height , options ) ;
@@ -113,6 +170,71 @@ class Font {
113170 } , [ ] ) ;
114171 }
115172
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+ */
116238 textToContours ( str , x = 0 , y = 0 , width , height , options ) {
117239 ( { width, height, options } = this . _parseArgs ( width , height , options ) ) ;
118240
@@ -688,20 +810,158 @@ function parseCreateArgs(...args/*path, name, onSuccess, onError*/) {
688810function font ( p5 , fn ) {
689811
690812 /**
691- * TODO
813+ * A class to describe fonts. Create through <a href="#/p5/loadFont">`loadFont()`</a>.
692814 *
693815 * @class p5.Font
694816 */
695817 p5 . Font = Font ;
696818
697819 /**
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+ *
701851 * @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,wght@12..96,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>
704952 */
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+ */
705965 fn . loadFont = async function ( ...args /*path, name, onSuccess, onError, descriptors*/ ) {
706966
707967 let { path, name, success, error, descriptors } = parseCreateArgs ( ...args ) ;
0 commit comments