diff --git a/src/typography/attributes.js b/src/typography/attributes.js index b11311b1eb..8d7995c5f8 100644 --- a/src/typography/attributes.js +++ b/src/typography/attributes.js @@ -16,6 +16,8 @@ define(function (require) { p5.prototype._textFont = 'sans-serif'; p5.prototype._textSize = 12; p5.prototype._textStyle = constants.NORMAL; + p5.prototype._textAscent = null; + p5.prototype._textDescent = null; /** * Sets the current alignment for drawing text. The parameters LEFT, CENTER, @@ -46,27 +48,6 @@ define(function (require) { } }; - /** - * Calculates and returns the height of any character or text string. - * - * @method textHeight - * @param {String} s the String of characters to measure - * @example - *
- * - * background(0); - * fill(255); - * textSize(14); - * s = "String."; - * text(s, 10, 23); - * console.log(textHeight(s)); - * - *
- */ - p5.prototype.textHeight = function(s) { - return this.drawingContext.measureText(s).height; - }; - /** * Sets the spacing between lines of text in units of pixels. This * setting will be used in all subsequent calls to the text() function. @@ -173,15 +154,126 @@ define(function (require) { return this.drawingContext.measureText(s).width; }; + /** + * Returns ascent of the current font at its current size. + * @example + *
+ * + * var base = height * 0.75; + * var scalar = 0.8; // Different for each font + * + * textSize(32); // Set initial text size + * var a = textAscent() * scalar; // Calc ascent + * line(0, base-a, width, base-a); + * text("dp", 0, base); // Draw text on baseline + * + * textSize(64); // Increase text size + * a = textAscent() * scalar; // Recalc ascent + * line(40, base-a, width, base-a); + * text("dp", 40, base); // Draw text on baseline + * + *
+ */ + p5.prototype.textAscent = function() { + if (this._textAscent == null) { this._updateTextMetrics(); } + return this._textAscent; + }; + + /** + * Returns descent of the current font at its current size. + * @example + *
+ * + * var base = height * 0.75; + * var scalar = 0.8; // Different for each font + * + * textSize(32); // Set initial text size + * var a = textDescent() * scalar; // Calc ascent + * line(0, base+a, width, base+a); + * text("dp", 0, base); // Draw text on baseline + * + * textSize(64); // Increase text size + * a = textDescent() * scalar; // Recalc ascent + * line(40, base+a, width, base+a); + * text("dp", 40, base); // Draw text on baseline + * + *
+ */ + p5.prototype.textDescent = function() { + if (this._textDescent == null) { this._updateTextMetrics(); } + return this._textDescent; + }; + /** * Helper fxn to apply text properties. - * */ p5.prototype._applyTextProperties = function () { + this._setProperty('_textAscent', null); + this._setProperty('_textDescent', null); + var str = this._textStyle + ' ' + this._textSize + 'px ' + this._textFont; this.drawingContext.font = str; }; + /** + * Helper fxn to measure ascent and descent. + * Adapted from http://stackoverflow.com/a/25355178 + */ + p5.prototype._updateTextMetrics = function () { + + var text = document.createElement('span'); + text.style.fontFamily = this._textFont; + text.style.fontSize = this._textSize + 'px'; + text.innerHTML = 'ABCjgq|'; + + var block = document.createElement('div'); + block.style.display = 'inline-block'; + block.style.width = '1px'; + block.style.height = '0px'; + + var container = document.createElement('div'); + container.appendChild(text); + container.appendChild(block); + + container.style.height = '0px'; + container.style.overflow = 'hidden'; + document.body.appendChild(container); + + block.style.verticalAlign = 'baseline'; + var blockOffset = this._calculateOffset(block); + var textOffset = this._calculateOffset(text); + var ascent = blockOffset[1] - textOffset[1]; + + block.style.verticalAlign = 'bottom'; + blockOffset = this._calculateOffset(block); + textOffset = this._calculateOffset(text); + var height = blockOffset[1] - textOffset[1]; + var descent = height - ascent; + + document.body.removeChild(container); + + this._setProperty('_textAscent', ascent); + this._setProperty('_textDescent', descent); + }; + + /** + * Helper fxn to measure ascent and descent. + * Adapted from http://stackoverflow.com/a/25355178 + */ + p5.prototype._calculateOffset = function (object) { + var currentLeft = 0, currentTop = 0; + if( object.offsetParent ) { + do { + currentLeft += object.offsetLeft; + currentTop += object.offsetTop; + } while( object = object.offsetParent ); + } else { + currentLeft += object.offsetLeft; + currentTop += object.offsetTop; + } + return [currentLeft,currentTop]; + }; + return p5; });