mirror of
https://github.com/wassname/CanvasTextWrapper.git
synced 2026-06-28 03:47:49 +08:00
Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f464af8c5d | |||
| 5b7a7f9cfe | |||
| 45a2b83782 | |||
| 43c8775359 | |||
| 4924f6f06a | |||
| 60c009b432 | |||
| e5ad6e9e22 | |||
| b6eb83cbbc | |||
| ba409c2f9a | |||
| 9b14e6bc20 | |||
| ab5ee97446 | |||
| 68f08dccf0 | |||
| b86396f979 | |||
| 53f765b0e8 | |||
| 4d7e9ed627 | |||
| 68a9da4826 | |||
| 9534bbbdf7 | |||
| d4566c71cf | |||
| c5464dab42 | |||
| c18627bd6a | |||
| a884a840db | |||
| c53c170d5c | |||
| 19d9b83fea | |||
| 2361b45226 | |||
| f2f142e81b |
@@ -0,0 +1 @@
|
||||
examples
|
||||
@@ -0,0 +1,3 @@
|
||||
node_modules
|
||||
examples
|
||||
bower.json
|
||||
+43
-16
@@ -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,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 (given font size is ignored)
|
||||
};
|
||||
|
||||
window.CanvasTextWrapper = function(canvas, text, opts) {
|
||||
@@ -33,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();
|
||||
@@ -49,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 = '';
|
||||
@@ -167,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.');
|
||||
}
|
||||
}
|
||||
};
|
||||
})();
|
||||
Vendored
+2
-2
@@ -1,7 +1,7 @@
|
||||
/*! 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
|
||||
*/
|
||||
!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)||18,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=this.text.trim().split(/\s+/).length,e=0;do{this.setFontSize(++e);var f=this.getWrappedText(a),g=f.length*this.lineHeight}while(c>g&&f.join(" ").split(/\s+/).length==d);this.setFontSize(--e)}var f=this.getWrappedText(a),g=f.length*this.lineHeight;this.setTextVerticalAlign(b,g);for(var h=0;h<f.length;h++)this.setTextHorizontalAlign(this.context,b,a,f[h]),b.y=parseInt(b.y)+parseInt(this.lineHeight),this.context.fillText(f[h],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.trim().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.')}}}();
|
||||
@@ -1,2 +1,69 @@
|
||||
CanvasTextWrapper
|
||||
=================
|
||||
|
||||
##Syntax
|
||||
```
|
||||
new CanvasTextWrapper(HTMLCanvasElement, String [, options]);
|
||||
```
|
||||
|
||||
```options``` - is a JavaScript object with the following available properties and values:
|
||||
|
||||
- ```font: String``` - text style that includes font size in px (REQUIRED), weight & family, similar to CSS font shorthand property
|
||||
- ```textAlign: "left" | "center" | "right"``` - horizontal alignment that applies for each line
|
||||
- ```verticalAlign: "top" | "middle" | "bottom"``` - vertical alignment that applies on a whole block of text
|
||||
- ```paddingX: Number``` - horizontal padding in pixels set equally on both, left and right sides of the element
|
||||
- ```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.
|
||||
|
||||
##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",
|
||||
sizeToFill: false
|
||||
}
|
||||
```
|
||||
|
||||
##Usage
|
||||
Use standard canvas text drawing methods such as "fillStyle" and "globalCompositeOperation" when needed before using CanvasTextWrapper like so:
|
||||
```
|
||||
var canvas = document.createElement('canvas');
|
||||
canvas.width = 300;
|
||||
canvas.height = 250;
|
||||
context = canvas.getContext("2d");
|
||||
context.fillStyle = "rgb(255, 255, 255)";
|
||||
context.fillRect(0, 0, canvas.width, canvas.height);
|
||||
|
||||
context.globalCompositeOperation = "destination-out";
|
||||
|
||||
new CanvasTextWrapper(canvas, "Hi there", {
|
||||
font: "normal 40px Open Sans, sans-serif",
|
||||
textAlign: "center",
|
||||
verticalAlign: "bottom",
|
||||
paddingY: 10,
|
||||
lineBreak: "word",
|
||||
});
|
||||
```
|
||||
|
||||
##Examples
|
||||
http://namniak.github.io/CanvasTextWrapper/
|
||||
|
||||
##Installation
|
||||
|
||||
```
|
||||
bower install canvas-text-wrapper
|
||||
|
||||
npm install canvas-text-wrapper
|
||||
```
|
||||
|
||||
+6
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "canvas-text-wrapper",
|
||||
"version": "0.1.0",
|
||||
"version": "0.2.0",
|
||||
"ignore": [
|
||||
"**/.*",
|
||||
"**/*.log",
|
||||
@@ -10,5 +10,9 @@
|
||||
"node_modules",
|
||||
"README.md"
|
||||
],
|
||||
"homepage": "https://github.com/namniak/CanvasTextWrapper.git"
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/namniak/CanvasTextWrapper.git"
|
||||
},
|
||||
"homepage": "http://namniak.github.io/CanvasTextWrapper/"
|
||||
}
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
/* http://meyerweb.com/eric/tools/css/reset/
|
||||
v2.0 | 20110126
|
||||
License: none (public domain)
|
||||
*/
|
||||
|
||||
html, body, div, span, applet, object, iframe,
|
||||
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
|
||||
a, abbr, acronym, address, big, cite, code,
|
||||
del, dfn, em, img, ins, kbd, q, s, samp,
|
||||
small, strike, strong, sub, sup, tt, var,
|
||||
b, u, i, center,
|
||||
dl, dt, dd, ol, ul, li,
|
||||
fieldset, form, label, legend,
|
||||
table, caption, tbody, tfoot, thead, tr, th, td,
|
||||
article, aside, canvas, details, embed,
|
||||
figure, figcaption, footer, header, hgroup,
|
||||
menu, nav, output, ruby, section, summary,
|
||||
time, mark, audio, video {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
font-size: 100%;
|
||||
font: inherit;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
/* HTML5 display-role reset for older browsers */
|
||||
article, aside, details, figcaption, figure,
|
||||
footer, header, hgroup, menu, nav, section {
|
||||
display: block;
|
||||
}
|
||||
body {
|
||||
line-height: 1;
|
||||
}
|
||||
ol, ul {
|
||||
list-style: none;
|
||||
}
|
||||
blockquote, q {
|
||||
quotes: none;
|
||||
}
|
||||
blockquote:before, blockquote:after,
|
||||
q:before, q:after {
|
||||
content: '';
|
||||
content: none;
|
||||
}
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
}
|
||||
@@ -1,136 +0,0 @@
|
||||
body {
|
||||
width: 960px;
|
||||
margin: auto;
|
||||
font-family: 'Open Sans', sans-serif;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
div, header, footer, article {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
header, footer, article {
|
||||
width: 930px;
|
||||
margin: auto;
|
||||
background-color: #0D9F69;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
header {
|
||||
font-size: 60px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.description {
|
||||
width: 800px;
|
||||
margin-top: 20px;
|
||||
font-size: 22px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
footer {
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
a {
|
||||
font-size: 20px;
|
||||
font-weight: normal;
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
article {
|
||||
border-top: 1px solid #fff;
|
||||
}
|
||||
|
||||
.white-block {
|
||||
display: table-cell;
|
||||
height: 30px;
|
||||
padding: 20px;
|
||||
vertical-align: middle;
|
||||
background-color: #fff;
|
||||
font-weight: 100;
|
||||
color: #0D9F69;
|
||||
line-height: 120%;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 10px 0;
|
||||
line-height: 120%;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 30px;
|
||||
}
|
||||
|
||||
h6 {
|
||||
font-weight: 700;
|
||||
text-decoration: underline;
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.syntax {
|
||||
padding: 10px 10px 0 20px;
|
||||
}
|
||||
|
||||
.syntax > li {
|
||||
list-style: none;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.values li {
|
||||
text-indent: 20px;
|
||||
list-style: inside circle;
|
||||
line-height: 120%;
|
||||
}
|
||||
|
||||
section {
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
section > div {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
width: 450px;
|
||||
margin: 15px;
|
||||
border: 1px solid #0D9F69;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
section h2 {
|
||||
color: #0D9F69;
|
||||
text-indent: 30px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
section > div div {
|
||||
width: 100%;
|
||||
height: 200px;
|
||||
background-color: #0D9F69;
|
||||
margin-top: 250px;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
canvas, img {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
span {
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
span, .emph {
|
||||
font-weight: 600;
|
||||
display: inline;
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 48 KiB |
@@ -1,125 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<link href='http://fonts.googleapis.com/css?family=Open+Sans:400,700,600' rel='stylesheet' type='text/css'>
|
||||
<link rel="stylesheet" href="css/reset.css">
|
||||
<link rel="stylesheet" href="css/styles.css">
|
||||
<script src="js/CanvasTextWrapper.js"></script>
|
||||
<script src="js/options.js"></script>
|
||||
<script src="js/examples.js"></script>
|
||||
<title>CanvasTextWrapper.js</title>
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<p>CanvasTextWrapper.js</p>
|
||||
|
||||
<p class="description">
|
||||
JavaScript canvas text wrapper that automatically splits a string into lines on specified rule with
|
||||
optional alignments and padding.
|
||||
</p>
|
||||
</header>
|
||||
<article>
|
||||
<h2>Syntax:</h2><br/>
|
||||
|
||||
<p class="white-block">new CanvasTextWrapper(HTMLCanvasElement, String [, Options]);</p><br/>
|
||||
|
||||
<div>
|
||||
<div class="emph">OPTIONS</div>
|
||||
- is a JavaScript object with the following available properties and values:
|
||||
</div>
|
||||
<ul class="syntax">
|
||||
<li>
|
||||
<div class="emph">font</div>
|
||||
(String) - text style that includes font size, family, etc. specified similarly to CSS
|
||||
font shorthand property
|
||||
</li>
|
||||
<li>
|
||||
<div class="emph">textAlign</div>
|
||||
(String) - horizontal alignment that applies for each line
|
||||
<ul class="values">
|
||||
<li>"left"</li>
|
||||
<li>"center"</li>
|
||||
<li>"right"</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<div class="emph">verticalAlign</div>
|
||||
(String) - vertical alignment that applies on a whole block of text
|
||||
<ul class="values">
|
||||
<li>"top"</li>
|
||||
<li>"middle"</li>
|
||||
<li>"bottom"</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<div class="emph">paddingX</div>
|
||||
(Number) - horizontal padding in pixels set equally on both, left and right sides of
|
||||
the element
|
||||
</li>
|
||||
<li>
|
||||
<div class="emph">paddingY</div>
|
||||
(Number) - vertical padding in pixels set equally on both, top and bottom sides of the element
|
||||
</li>
|
||||
<li>
|
||||
<div class="emph">fitParent</div>
|
||||
(Boolean) - parameter that controls which element to fit
|
||||
<ul class="values">
|
||||
<li>true - fit canvas parent's width instead of canvas own width</li>
|
||||
<li>false - fit canvas width</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<div class="emph">lineBreak</div>
|
||||
(String) - text split rule
|
||||
<ul class="values">
|
||||
<li>"auto" - text fills the element's width going to a new line on a whole word when no more space</li>
|
||||
<li>"word" - each next word will be placed on a new line</li>
|
||||
</ul>
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</article>
|
||||
<article>
|
||||
<h2>Defaults & Usage:</h2><br/>
|
||||
|
||||
<p>The default options object which values will be used if a property is not specified or no object is passed:</p>
|
||||
|
||||
<p class="white-block">
|
||||
{ font: "18px Arial, sans-serif",<br/>
|
||||
textAlign: "left",<br/>
|
||||
verticalAlign: "top",<br/>
|
||||
paddingX: 0,<br/>
|
||||
paddingY: 0,<br/>
|
||||
fitParent: false,<br/>
|
||||
lineBreak: "auto" }
|
||||
</p>
|
||||
<br/>
|
||||
|
||||
<p>
|
||||
Use standard canvas text drawing methods such as "fillStyle" and "globalCompositeOperation" when needed before
|
||||
using CanvasTextWrapper like so:
|
||||
</p>
|
||||
|
||||
<p class="white-block">
|
||||
var canvas = document.createElement('canvas');<br/>
|
||||
canvas.width = 300;<br/>
|
||||
canvas.height = 250;<br/>
|
||||
context = canvas.getContext("2d");<br/>
|
||||
context.fillStyle = "rgb(255, 255, 255)";<br/>
|
||||
context.fillRect(0, 0, canvas.width, canvas.height);<br/><br/>
|
||||
context.globalCompositeOperation = "destination-out";<br/>
|
||||
var wrapper = new CanvasTextWrapper(canvas, 'Hello'); // default options will apply<br/>
|
||||
</p>
|
||||
</article>
|
||||
<section>
|
||||
<h2>Examples:</h2>
|
||||
</section>
|
||||
<footer>
|
||||
← <a href="https://github.com/namniak/CanvasTextWrapper">View on GitHub</a>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,171 +0,0 @@
|
||||
/*! CanvasTextWrapper (https://github.com/namniak/CanvasTextWrapper)
|
||||
* Version: 0.1.0
|
||||
*
|
||||
* MIT License (http://www.opensource.org/licenses/mit-license.html)
|
||||
* Copyright (c) 2014 Vadim Namniak
|
||||
*/
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
var defaultOptions = {
|
||||
font: '18px Arial, sans-serif',
|
||||
textAlign: 'left', // each line of text is aligned left
|
||||
verticalAlign: 'top', // text lines block is aligned top
|
||||
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
|
||||
};
|
||||
|
||||
window.CanvasTextWrapper = function(canvas, text, opts) {
|
||||
if (!(this instanceof CanvasTextWrapper)) {
|
||||
throw new TypeError('CanvasTextWrapper constructor failed. Use "new" keyword when instantiating.');
|
||||
}
|
||||
|
||||
this.canvas = canvas;
|
||||
this.text = text;
|
||||
|
||||
// set options to specified or default values
|
||||
for (var property in defaultOptions) {
|
||||
this[property] = (opts && opts[property]) ? opts[property] : defaultOptions[property];
|
||||
}
|
||||
|
||||
// extract font size
|
||||
this.lineHeight = parseInt(this.font.replace(/^\D+/g, ''), 10);
|
||||
|
||||
// validate all set properties
|
||||
this.validate();
|
||||
|
||||
// basic context settings
|
||||
this.context = this.canvas.getContext('2d');
|
||||
this.context.font = this.font;
|
||||
this.context.textBaseline = 'bottom';
|
||||
|
||||
this.drawText();
|
||||
};
|
||||
|
||||
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 textPos = {
|
||||
x: 0,
|
||||
y: 0
|
||||
};
|
||||
|
||||
this.checkWordsLength(context, words, maxTextLength);
|
||||
this.breakTextIntoLines(context, lines, words, maxTextLength);
|
||||
|
||||
// height of the broken down into lines text
|
||||
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]);
|
||||
|
||||
textPos.y = parseInt(textPos.y) + parseInt(this.lineHeight);
|
||||
context.fillText(lines[i], textPos.x, textPos.y);
|
||||
}
|
||||
},
|
||||
|
||||
checkWordsLength: function(context, words, maxTextLength) {
|
||||
for (var i = 0; i < words.length; i++) {
|
||||
var testString = '';
|
||||
var tokenLen = context.measureText(words[i]).width;
|
||||
|
||||
// check if a word exceeds the element's width
|
||||
if (tokenLen > maxTextLength) {
|
||||
for (var k = 0; (context.measureText(testString + words[i][k]).width <= maxTextLength) && (k < words[i].length); k++) {
|
||||
testString += words[i][k];
|
||||
}
|
||||
|
||||
// break the word because it's too long
|
||||
var sliced = words[i].slice(0, k);
|
||||
var leftover = words[i].slice(k);
|
||||
words.splice(i, 1, sliced, leftover);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
breakTextIntoLines: function(context, lines, words, maxTextLength) {
|
||||
for (var i = 0, j = 0; i < words.length; j++) {
|
||||
lines[j] = '';
|
||||
|
||||
if (this.lineBreak === 'auto') {
|
||||
// put as many full words in a line as can fit element
|
||||
while ((context.measureText(lines[j] + words[i]).width <= maxTextLength) && (i < words.length)) {
|
||||
lines[j] += words[i] + ' ';
|
||||
i++;
|
||||
}
|
||||
lines[j] = lines[j].trim();
|
||||
} else if (this.lineBreak === 'word') {
|
||||
// put each next word in a new line
|
||||
lines[j] = words[i];
|
||||
i++;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
setTextHorizontalAlign: function(context, textPos, elementWidth, line) {
|
||||
if (this.textAlign === 'center') {
|
||||
textPos.x = (elementWidth - context.measureText(line).width) / 2;
|
||||
} else if (this.textAlign === 'right') {
|
||||
textPos.x = elementWidth - context.measureText(line).width - this.paddingX;
|
||||
} else {
|
||||
textPos.x = this.paddingX;
|
||||
}
|
||||
},
|
||||
|
||||
setTextVerticalAlign: function(textPos, textBlockHeight) {
|
||||
var elementHeight = (this.fitParent === false) ? this.canvas.height : this.canvas.parentNode.clientHeight;
|
||||
|
||||
if (this.verticalAlign === 'middle') {
|
||||
textPos.y = (elementHeight - textBlockHeight) / 2;
|
||||
} else if (this.verticalAlign === 'bottom') {
|
||||
textPos.y = elementHeight - textBlockHeight - this.paddingY;
|
||||
} else {
|
||||
textPos.y = 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 (typeof this.text !== 'string') {
|
||||
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 (this.textAlign !== 'left' && this.textAlign !== 'center' && this.textAlign !== 'right') {
|
||||
throw new TypeError('From CanvasTextWrapper(): Unsupported horizontal align value is used. Property "textAlign" can only be set to "left", "center", or "right".');
|
||||
}
|
||||
if (this.verticalAlign !== 'top' && this.verticalAlign !== 'middle' && this.verticalAlign !== 'bottom') {
|
||||
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 (typeof this.fitParent !== 'boolean') {
|
||||
throw new TypeError('From CanvasTextWrapper(): Property "fitParent" must be set to a Boolean.');
|
||||
}
|
||||
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".');
|
||||
}
|
||||
}
|
||||
};
|
||||
})();
|
||||
@@ -1,76 +0,0 @@
|
||||
document.onreadystatechange = function() {
|
||||
if (document.readyState === 'complete') {
|
||||
|
||||
(function() {
|
||||
var container = document.getElementsByTagName('section')[0];
|
||||
var w = 448;
|
||||
var h = 250;
|
||||
var aspectRatio = 0;
|
||||
var text = 'Canvas text wrapping example';
|
||||
|
||||
var img = new Image();
|
||||
img.src = 'img/bg.jpg';
|
||||
img.onload = function() {
|
||||
aspectRatio = img.naturalWidth / img.naturalHeight;
|
||||
createExamples();
|
||||
};
|
||||
|
||||
// use options.js file
|
||||
var options = optionsArr;
|
||||
|
||||
function createExamples() {
|
||||
var fragment = new DocumentFragment();
|
||||
var context;
|
||||
|
||||
for (var i = 0; i < options.length; i++) {
|
||||
var exampleItem = document.createElement('div');
|
||||
fragment.appendChild(exampleItem);
|
||||
|
||||
// draw canvas image
|
||||
var canvasImg = document.createElement('canvas');
|
||||
canvasImg.width = w;
|
||||
canvasImg.height = h;
|
||||
context = canvasImg.getContext('2d');
|
||||
context.drawImage(img, 0, 0, w, w * aspectRatio);
|
||||
exampleItem.appendChild(canvasImg);
|
||||
|
||||
// create canvas mask layer
|
||||
var canvasMask = document.createElement('canvas');
|
||||
canvasMask.width = w;
|
||||
canvasMask.height = h;
|
||||
context = canvasMask.getContext('2d');
|
||||
context.fillStyle = 'rgba(255,255,255, 1)';
|
||||
context.fillRect(0, 0, w, h);
|
||||
exampleItem.appendChild(canvasMask);
|
||||
|
||||
// create text to be cut out mask layer
|
||||
context.fillStyle = '#212121';
|
||||
context.globalCompositeOperation = 'destination-out';
|
||||
|
||||
// create wrapper
|
||||
new CanvasTextWrapper(canvasMask, ('#' + (i + 1) + ' ' + text), options[i]);
|
||||
|
||||
// create hint code block
|
||||
var hint = document.createElement('div');
|
||||
exampleItem.appendChild(hint);
|
||||
var optionsData = '';
|
||||
|
||||
// read used properties
|
||||
for (var property in options[i]) {
|
||||
var stringWrapper = (property == 'paddingX' || property == 'paddingY') ? '' : '"';
|
||||
optionsData += ' <span>' + property + '</span>: ' +
|
||||
stringWrapper + options[i][property] + stringWrapper + ',<br/>';
|
||||
}
|
||||
|
||||
// print example code
|
||||
hint.innerHTML = '<h6>CODE:</h6><p>' +
|
||||
'new CanvasTextWrapper(canvasEl, textStr, {<br/>' + optionsData + '});' +
|
||||
'</p>';
|
||||
}
|
||||
|
||||
// inject document fragment into actual DOM
|
||||
container.appendChild(fragment);
|
||||
}
|
||||
})();
|
||||
}
|
||||
};
|
||||
@@ -1,54 +0,0 @@
|
||||
(function() {
|
||||
window.optionsArr = [
|
||||
{
|
||||
font: 'bold 55px Open Sans, sans-serif',
|
||||
paddingX: 0,
|
||||
paddingY: 0,
|
||||
fitParent: false,
|
||||
lineBreak: 'auto'
|
||||
},
|
||||
{
|
||||
font: 'normal 40px Open Sans, sans-serif',
|
||||
textAlign: 'center',
|
||||
verticalAlign: 'top',
|
||||
paddingY: 10,
|
||||
lineBreak: 'word'
|
||||
},
|
||||
{
|
||||
font: 'bold 55px Open Sans, sans-serif',
|
||||
textAlign: 'right',
|
||||
verticalAlign: 'bottom',
|
||||
paddingX: 30
|
||||
},
|
||||
{
|
||||
font: 'bold 35px Open Sans, sans-serif',
|
||||
textAlign: 'center',
|
||||
verticalAlign: 'middle'
|
||||
},
|
||||
{
|
||||
font: 'bold 55px Open Sans, sans-serif',
|
||||
textAlign: 'right',
|
||||
verticalAlign: 'top',
|
||||
paddingX: 15,
|
||||
paddingY: 5
|
||||
},
|
||||
{
|
||||
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
|
||||
}
|
||||
];
|
||||
})();
|
||||
+3
-2
@@ -1,9 +1,10 @@
|
||||
{
|
||||
"name": "canvas-text-wrapper",
|
||||
"description": "Javascript canvas text wrapper that automatically breaks the text into lines on a rule of your choice with available horizontal and vertical align options.",
|
||||
"version": "0.1.0",
|
||||
"description": "JavaScript canvas text wrapper that automatically splits a string into lines on specified rule with optional alignments and padding.",
|
||||
"version": "0.2.0",
|
||||
"license": "MIT",
|
||||
"main": "CanvasTextWrapper.min.js",
|
||||
"homepage": "http://namniak.github.io/CanvasTextWrapper/",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/namniak/CanvasTextWrapper"
|
||||
|
||||
Reference in New Issue
Block a user