From cb7cb65b9ef5cfe38f9c22c4b3c9d25a4df46bee Mon Sep 17 00:00:00 2001 From: Vadim Namniak Date: Wed, 8 Oct 2014 22:48:48 -0400 Subject: [PATCH] added sizeToFill option + ui updates --- css/styles.css | 9 +++++++ index.html | 41 +++++++++++++++++----------- js/CanvasTextWrapper.js | 60 ++++++++++++++++++++++++++++++----------- js/examples.js | 4 +-- js/options.js | 36 +++++++------------------ 5 files changed, 90 insertions(+), 60 deletions(-) diff --git a/css/styles.css b/css/styles.css index 89a3bae..8b7719b 100644 --- a/css/styles.css +++ b/css/styles.css @@ -3,6 +3,7 @@ body { margin: auto; font-family: 'Open Sans', sans-serif; color: #fff; + line-height: 140%; } div, header, footer, article { @@ -128,9 +129,17 @@ img { span { margin-left: 20px; + margin-right: 5px; } span, .emph { font-weight: 600; display: inline; } + +strong { + background: #fff; + color: #0D9F69; + font-weight: bold; + padding: 0 5px; +} diff --git a/index.html b/index.html index aaabdf3..9ba7298 100644 --- a/index.html +++ b/index.html @@ -76,27 +76,38 @@
  • "auto" - text fills the element's width going to a new line on a whole word when no more space
  • "word" - each next word will be placed on a new line
  • -

    - NOTE: if a single word is too long to fit the width with specified font size, it will be broken into as - many lines as required on any letter without specific word breaking rule. -

    - +
  • +
    sizeToFill
    + (Boolean) - auto font size to fill text container + +
  • +

    + NOTE: if a single word is too long to fit the width with specified font size, it will be broken into as + many lines as required on any letter without specific word breaking rule unless sizeToFill option is used. +

    +

    Defaults


    The default options object which values will be used if a property is not specified or no object is passed:

    -

    - { font: "18px Arial, sans-serif",
    -    textAlign: "left",
    -    verticalAlign: "top",
    -    paddingX: 0,
    -    paddingY: 0,
    -    fitParent: false,
    -    lineBreak: "auto" } -

    -
    +
    +    { 
    +        font: "18px Arial, sans-serif",     
    +        textAlign: "left",  
    +        verticalAlign: "top",   
    +        paddingX: 0,
    +        paddingY: 0,
    +        fitParent: false,
    +        lineBreak: "auto",
    +       sizeToFill: false
    +    }
    +    
    +

    Usage


    diff --git a/js/CanvasTextWrapper.js b/js/CanvasTextWrapper.js index a974aa6..97b04f3 100644 --- a/js/CanvasTextWrapper.js +++ b/js/CanvasTextWrapper.js @@ -1,5 +1,5 @@ /*! CanvasTextWrapper (https://github.com/namniak/CanvasTextWrapper) - * Version: 0.1.0 + * Version: 0.2.0 * * MIT License (http://www.opensource.org/licenses/mit-license.html) * Copyright (c) 2014 Vadim Namniak @@ -15,10 +15,12 @@ paddingX: 0, // zero px left & right text padding relative to canvas or parent paddingY: 0, // zero px top & bottom text padding relative to canvas or parent fitParent: false, // text is tested to fit canvas width - lineBreak: 'auto' // text fills the element's (canvas or parent) width going to a new line on a whole word + lineBreak: 'auto', // text fills the element's (canvas or parent) width going to a new line on a whole word + sizeToFill: false // text is resized to fill the container (given font size is ignored) }; window.CanvasTextWrapper = function(canvas, text, opts) { + if (!(this instanceof CanvasTextWrapper)) { throw new TypeError('CanvasTextWrapper constructor failed. Use "new" keyword when instantiating.'); } @@ -32,7 +34,7 @@ } // extract font size - this.lineHeight = parseInt(this.font.replace(/^\D+/g, ''), 10); + this.lineHeight = parseInt(this.font.replace(/^\D+/g, ''), 10) || 18; // validate all set properties this.validate(); @@ -48,36 +50,59 @@ CanvasTextWrapper.prototype = { drawText: function() { - var canvas = this.canvas; - var context = canvas.getContext('2d'); - - var elementWidth = (this.fitParent === false) ? canvas.width : canvas.parentNode.clientWidth; - var maxTextLength = elementWidth - (this.paddingX * 2); - - var words = this.text.split(/\s+/); - var lines = []; + var elementWidth = (this.fitParent === false) ? this.canvas.width : this.canvas.parentNode.clientWidth; var textPos = { x: 0, y: 0 }; - this.checkWordsLength(context, words, maxTextLength); - this.breakTextIntoLines(context, lines, words, maxTextLength); + if (this.sizeToFill) { + // starting at 1px increase font size by 1px until text block exceeds the height of its padded container or until words break + var elementHeight = ((this.fitParent === false) ? this.canvas.height : this.canvas.parentNode.clientHeight) - (this.paddingX * 2); + var numWords = this.text.trim().split(/\s+/).length; + var fontSize = 0; + do { + this.setFontSize(++fontSize); + var lines = this.getWrappedText(elementWidth); + var textBlockHeight = lines.length * this.lineHeight; + } while (textBlockHeight < elementHeight && lines.join(' ').split(/\s+/).length == numWords); - // height of the broken down into lines text + // use previous font size, not the one that broke the while condition + this.setFontSize(--fontSize); + } + + var lines = this.getWrappedText(elementWidth); var textBlockHeight = lines.length * this.lineHeight; // set vertical align for the whole text block this.setTextVerticalAlign(textPos, textBlockHeight); for (var i = 0; i < lines.length; i++) { - this.setTextHorizontalAlign(context, textPos, elementWidth, lines[i]); + this.setTextHorizontalAlign(this.context, textPos, elementWidth, lines[i]); textPos.y = parseInt(textPos.y) + parseInt(this.lineHeight); - context.fillText(lines[i], textPos.x, textPos.y); + this.context.fillText(lines[i], textPos.x, textPos.y); } }, + setFontSize: function(size) { + var fontParts = this.context.font.split(/\b\d+px\b/i); + this.context.font = fontParts[0] + size + 'px' + fontParts[1]; + this.lineHeight = size; + }, + + getWrappedText: function(elementWidth) { + var maxTextLength = elementWidth - (this.paddingX * 2); + + var words = this.text.trim().split(/\s+/); + var lines = []; + + this.checkWordsLength(this.context, words, maxTextLength); + this.breakTextIntoLines(this.context, lines, words, maxTextLength); + + return lines; + }, + checkWordsLength: function(context, words, maxTextLength) { for (var i = 0; i < words.length; i++) { var testString = ''; @@ -166,6 +191,9 @@ if (this.lineBreak !== 'auto' && this.lineBreak !== 'word') { throw new TypeError('From CanvasTextWrapper(): Unsupported line break value is used. Property "lineBreak" can only be set to "auto", or "word".'); } + if (typeof this.sizeToFill !== 'boolean') { + throw new TypeError('From CanvasTextWrapper(): Property "sizeToFill" must be set to a Boolean.'); + } } }; })(); \ No newline at end of file diff --git a/js/examples.js b/js/examples.js index 9610094..ccd8f75 100644 --- a/js/examples.js +++ b/js/examples.js @@ -57,8 +57,8 @@ document.onreadystatechange = function() { // read used properties for (var property in options[i]) { - var stringWrapper = (property == 'paddingX' || property == 'paddingY') ? '' : '"'; - optionsData += ' ' + property + ': ' + + var stringWrapper = (property == 'paddingX' || property == 'paddingY' || property == 'sizeToFill') ? '' : '"'; + optionsData += ' ' + property + ': ' + stringWrapper + options[i][property] + stringWrapper + ',
    '; } diff --git a/js/options.js b/js/options.js index 77f6e69..aa4f77e 100644 --- a/js/options.js +++ b/js/options.js @@ -1,16 +1,11 @@ (function() { window.optionsArr = [ { - font: 'bold 55px Open Sans, sans-serif', - paddingX: 0, - paddingY: 0, - fitParent: false, - lineBreak: 'auto' + font: 'bold 55px Open Sans, sans-serif' }, { - font: 'normal 40px Open Sans, sans-serif', + font: 'normal 40px Impact, Charcoal, sans-serif', textAlign: 'center', - verticalAlign: 'top', paddingY: 10, lineBreak: 'word' }, @@ -21,34 +16,21 @@ paddingX: 30 }, { - font: 'bold 35px Open Sans, sans-serif', + font: 'bold 35px Verdana, Geneva, sans-serif', textAlign: 'center', verticalAlign: 'middle' }, { - font: 'bold 55px Open Sans, sans-serif', + font: 'bold 50px Tahoma, Geneva, sans-serif', textAlign: 'right', - verticalAlign: 'top', - paddingX: 15, - paddingY: 5 + paddingX: 25, + paddingY: 25 }, { - font: 'bold 45px Open Sans, sans-serif', textAlign: 'center', verticalAlign: 'middle', - lineBreak: 'word' - }, - { - font: 'bold 25px Open Sans, sans-serif', - verticalAlign: 'bottom', - paddingX: 10, - paddingY: 60 - }, - { - font: '50px Open Sans, sans-serif', - textAlign: 'right', - verticalAlign: 'middle', - paddingX: 15 + //lineBreak: 'word', + sizeToFill: true } ]; -})(); +})(); \ No newline at end of file