mirror of
https://github.com/wassname/CanvasTextWrapper.git
synced 2026-06-27 19:45:29 +08:00
Added sizeToFill option for resizing text to fill its container
This commit is contained in:
+42
-14
@@ -15,7 +15,8 @@
|
||||
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 height (given font size is ignored)
|
||||
};
|
||||
|
||||
window.CanvasTextWrapper = function(canvas, text, opts) {
|
||||
@@ -49,24 +50,30 @@
|
||||
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
|
||||
var elementHeight = ((this.fitParent === false) ? this.canvas.height : this.canvas.parentNode.clientHeight) - (this.paddingX * 2);
|
||||
var fontSize = 0;
|
||||
do {
|
||||
this.setFontSize(++fontSize);
|
||||
var lines = this.getWrappedText(elementWidth);
|
||||
var textBlockHeight = lines.length * this.lineHeight;
|
||||
} while (textBlockHeight < elementHeight);
|
||||
|
||||
// height of the broken down into lines text
|
||||
var textBlockHeight = lines.length * this.lineHeight;
|
||||
// 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;
|
||||
} else {
|
||||
var lines = this.getWrappedText(elementWidth);
|
||||
var textBlockHeight = lines.length * this.lineHeight;
|
||||
}
|
||||
|
||||
// set vertical align for the whole text block
|
||||
this.setTextVerticalAlign(textPos, textBlockHeight);
|
||||
@@ -79,6 +86,24 @@
|
||||
}
|
||||
},
|
||||
|
||||
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.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 = '';
|
||||
@@ -167,6 +192,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.');
|
||||
}
|
||||
}
|
||||
};
|
||||
})();
|
||||
})();
|
||||
|
||||
Vendored
+1
-1
@@ -4,4 +4,4 @@
|
||||
* MIT License (http://www.opensource.org/licenses/mit-license.html)
|
||||
* Copyright (c) 2014 Vadim Namniak
|
||||
*/
|
||||
!function(){"use strict";var a={font:"18px Arial, sans-serif",textAlign:"left",verticalAlign:"top",paddingX:0,paddingY:0,fitParent:!1,lineBreak:"auto"};window.CanvasTextWrapper=function(b,c,d){if(!(this instanceof CanvasTextWrapper))throw new TypeError('CanvasTextWrapper constructor failed. Use "new" keyword when instantiating.');this.canvas=b,this.text=c;for(var e in a)this[e]=d&&d[e]?d[e]:a[e];this.lineHeight=parseInt(this.font.replace(/^\D+/g,""),10),this.validate(),this.context=this.canvas.getContext("2d"),this.context.font=this.font,this.context.textBaseline="bottom",this.drawText()},CanvasTextWrapper.prototype={drawText:function(){var a=this.canvas,b=a.getContext("2d"),c=this.fitParent===!1?a.width:a.parentNode.clientWidth,d=c-2*this.paddingX,e=this.text.split(/\s+/),f=[],g={x:0,y:0};this.checkWordsLength(b,e,d),this.breakTextIntoLines(b,f,e,d);var h=f.length*this.lineHeight;this.setTextVerticalAlign(g,h);for(var i=0;i<f.length;i++)this.setTextHorizontalAlign(b,g,c,f[i]),g.y=parseInt(g.y)+parseInt(this.lineHeight),b.fillText(f[i],g.x,g.y)},checkWordsLength:function(a,b,c){for(var d=0;d<b.length;d++){var e="",f=a.measureText(b[d]).width;if(f>c){for(var g=0;a.measureText(e+b[d][g]).width<=c&&g<b[d].length;g++)e+=b[d][g];var h=b[d].slice(0,g),i=b[d].slice(g);b.splice(d,1,h,i)}}},breakTextIntoLines:function(a,b,c,d){for(var e=0,f=0;e<c.length;f++)if(b[f]="","auto"===this.lineBreak){for(;a.measureText(b[f]+c[e]).width<=d&&e<c.length;)b[f]+=c[e]+" ",e++;b[f]=b[f].trim()}else"word"===this.lineBreak&&(b[f]=c[e],e++)},setTextHorizontalAlign:function(a,b,c,d){b.x="center"===this.textAlign?(c-a.measureText(d).width)/2:"right"===this.textAlign?c-a.measureText(d).width-this.paddingX:this.paddingX},setTextVerticalAlign:function(a,b){var c=this.fitParent===!1?this.canvas.height:this.canvas.parentNode.clientHeight;a.y="middle"===this.verticalAlign?(c-b)/2:"bottom"===this.verticalAlign?c-b-this.paddingY:this.paddingY},validate:function(){if(!(this.canvas instanceof HTMLCanvasElement))throw new TypeError("From CanvasTextWrapper(): Element passed as the first parameter is not an instance of HTMLCanvasElement.");if("string"!=typeof this.text)throw new TypeError("From CanvasTextWrapper(): The second, dedicated for the text, parameter must be a string.");if(isNaN(this.lineHeight))throw new TypeError('From CanvasTextWrapper(): Cannot parse font size as an Integer. Check "font" property\'s value.');if("left"!==this.textAlign&&"center"!==this.textAlign&&"right"!==this.textAlign)throw new TypeError('From CanvasTextWrapper(): Unsupported horizontal align value is used. Property "textAlign" can only be set to "left", "center", or "right".');if("top"!==this.verticalAlign&&"middle"!==this.verticalAlign&&"bottom"!==this.verticalAlign)throw new TypeError('From CanvasTextWrapper(): Unsupported vertical align value is used. Property "verticalAlign" can only be set to "top", "middle", or "bottom".');if(isNaN(this.paddingX))throw new TypeError('From CanvasTextWrapper(): Unsupported horizontal padding value is used. Property "paddingX" must be set to a number');if(isNaN(this.paddingY))throw new TypeError('From CanvasTextWrapper(): Unsupported vertical padding value is used. Property "paddingY" must be set to a number.');if("boolean"!=typeof this.fitParent)throw new TypeError('From CanvasTextWrapper(): Property "fitParent" must be set to a Boolean.');if("auto"!==this.lineBreak&&"word"!==this.lineBreak)throw new TypeError('From CanvasTextWrapper(): Unsupported line break value is used. Property "lineBreak" can only be set to "auto", or "word".')}}}();
|
||||
!function(){"use strict";var a={font:"18px Arial, sans-serif",textAlign:"left",verticalAlign:"top",paddingX:0,paddingY:0,fitParent:!1,lineBreak:"auto",sizeToFill:!1};window.CanvasTextWrapper=function(b,c,d){if(!(this instanceof CanvasTextWrapper))throw new TypeError('CanvasTextWrapper constructor failed. Use "new" keyword when instantiating.');this.canvas=b,this.text=c;for(var e in a)this[e]=d&&d[e]?d[e]:a[e];this.lineHeight=parseInt(this.font.replace(/^\D+/g,""),10),this.validate(),this.context=this.canvas.getContext("2d"),this.context.font=this.font,this.context.textBaseline="bottom",this.drawText()},CanvasTextWrapper.prototype={drawText:function(){var a=this.fitParent===!1?this.canvas.width:this.canvas.parentNode.clientWidth,b={x:0,y:0};if(this.sizeToFill){var c=(this.fitParent===!1?this.canvas.height:this.canvas.parentNode.clientHeight)-2*this.paddingX,d=0;do{this.setFontSize(++d);var e=this.getWrappedText(a),f=e.length*this.lineHeight}while(c>f);this.setFontSize(--d);var e=this.getWrappedText(a),f=e.length*this.lineHeight}else var e=this.getWrappedText(a),f=e.length*this.lineHeight;this.setTextVerticalAlign(b,f);for(var g=0;g<e.length;g++)this.setTextHorizontalAlign(context,b,a,e[g]),b.y=parseInt(b.y)+parseInt(this.lineHeight),context.fillText(e[g],b.x,b.y)},setFontSize:function(a){var b=this.context.font.split(/\b\d+px\b/i);this.context.font=b[0]+a+"px"+b[1],this.lineHeight=a},getWrappedText:function(a){var b=a-2*this.paddingX,c=this.text.split(/\s+/),d=[];return this.checkWordsLength(this.context,c,b),this.breakTextIntoLines(this.context,d,c,b),d},checkWordsLength:function(a,b,c){for(var d=0;d<b.length;d++){var e="",f=a.measureText(b[d]).width;if(f>c){for(var g=0;a.measureText(e+b[d][g]).width<=c&&g<b[d].length;g++)e+=b[d][g];var h=b[d].slice(0,g),i=b[d].slice(g);b.splice(d,1,h,i)}}},breakTextIntoLines:function(a,b,c,d){for(var e=0,f=0;e<c.length;f++)if(b[f]="","auto"===this.lineBreak){for(;a.measureText(b[f]+c[e]).width<=d&&e<c.length;)b[f]+=c[e]+" ",e++;b[f]=b[f].trim()}else"word"===this.lineBreak&&(b[f]=c[e],e++)},setTextHorizontalAlign:function(a,b,c,d){b.x="center"===this.textAlign?(c-a.measureText(d).width)/2:"right"===this.textAlign?c-a.measureText(d).width-this.paddingX:this.paddingX},setTextVerticalAlign:function(a,b){var c=this.fitParent===!1?this.canvas.height:this.canvas.parentNode.clientHeight;a.y="middle"===this.verticalAlign?(c-b)/2:"bottom"===this.verticalAlign?c-b-this.paddingY:this.paddingY},validate:function(){if(!(this.canvas instanceof HTMLCanvasElement))throw new TypeError("From CanvasTextWrapper(): Element passed as the first parameter is not an instance of HTMLCanvasElement.");if("string"!=typeof this.text)throw new TypeError("From CanvasTextWrapper(): The second, dedicated for the text, parameter must be a string.");if(isNaN(this.lineHeight))throw new TypeError('From CanvasTextWrapper(): Cannot parse font size as an Integer. Check "font" property\'s value.');if("left"!==this.textAlign&&"center"!==this.textAlign&&"right"!==this.textAlign)throw new TypeError('From CanvasTextWrapper(): Unsupported horizontal align value is used. Property "textAlign" can only be set to "left", "center", or "right".');if("top"!==this.verticalAlign&&"middle"!==this.verticalAlign&&"bottom"!==this.verticalAlign)throw new TypeError('From CanvasTextWrapper(): Unsupported vertical align value is used. Property "verticalAlign" can only be set to "top", "middle", or "bottom".');if(isNaN(this.paddingX))throw new TypeError('From CanvasTextWrapper(): Unsupported horizontal padding value is used. Property "paddingX" must be set to a number');if(isNaN(this.paddingY))throw new TypeError('From CanvasTextWrapper(): Unsupported vertical padding value is used. Property "paddingY" must be set to a number.');if("boolean"!=typeof this.fitParent)throw new TypeError('From CanvasTextWrapper(): Property "fitParent" must be set to a Boolean.');if("auto"!==this.lineBreak&&"word"!==this.lineBreak)throw new TypeError('From CanvasTextWrapper(): Unsupported line break value is used. Property "lineBreak" can only be set to "auto", or "word".');if("boolean"!=typeof this.sizeToFill)throw new TypeError('From CanvasTextWrapper(): Property "sizeToFill" must be set to a Boolean.')}}}();
|
||||
@@ -15,6 +15,7 @@ new CanvasTextWrapper(HTMLCanvasElement, String [, options]);
|
||||
- ```paddingY: Number``` - vertical padding in pixels set equally on both, top and bottom sides of the element
|
||||
- ```fitParent: Boolean``` - parameter that controls which element to fit where ```true``` means fit canvas parent's width instead of canvas own width
|
||||
- ```lineBreak: "auto" | "word"``` - text split rule. When using ```"auto"```, text fills the element's width going to a new line on a whole word when no more space. If ```"word"``` is set as value, each next word will be placed on a new line.
|
||||
- ```sizeToFill: Boolean``` - ignore given font size and resize text to fill its padded 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.
|
||||
|
||||
@@ -30,7 +31,8 @@ The default options object which values will be used if a property is not specif
|
||||
paddingX: 0,
|
||||
paddingY: 0,
|
||||
fitParent: false,
|
||||
lineBreak: "auto"
|
||||
lineBreak: "auto",
|
||||
sizeToFill: false
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
Reference in New Issue
Block a user