diff --git a/README.md b/README.md index 24c2bc4..17764fb 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,8 @@ CanvasTextWrapper(HTMLCanvasElement, String [, options]); | **verticalAlign** | `"top"` `"middle"` `"bottom"` | Vertical alignment of the whole text block. | | **paddingX** | *Number* | Horizontal padding (in px) that is equally set on left and right sides. | | **paddingY** | *Number* | Vertical padding (in px) that is equally set on top and bottoms. | +| **offsetX** | *Number* | Horizontal offset (in px) that is set on left side. | +| **offsetY** | *Number* | Vertical offset (in px) that is set on top. | | **fitParent** | *Boolean* | Fit canvas' container size instead of its own size. | | **lineBreak** | `"auto"` `"word"` | `"auto"` - text goes to the next line on a whole word when there's no room `"word"` - each next word is placed on a new line | | **sizeToFill** | *Boolean* | Ignore given font size and line height and resize text to fill its padded container. | @@ -31,7 +33,7 @@ NOTE: if a single word is too long to fit the width with specified font size, it ## Default options ```javascript - { + { font: '18px Arial, sans-serif', lineHeight: 1, textAlign: 'left', @@ -70,7 +72,7 @@ CanvasTextWrapper(canvas, 'Hello', {strokeText: true}); ## Test Run ```npm t``` -NOTE: Test requires [beefy](http://didact.us/beefy/) to be installed globally +NOTE: Test requires [beefy](http://didact.us/beefy/) to be installed globally ## Examples diff --git a/canvas-text-wrapper.js b/canvas-text-wrapper.js index 0e9c399..d32a6a2 100644 --- a/canvas-text-wrapper.js +++ b/canvas-text-wrapper.js @@ -15,6 +15,8 @@ justifyLines: false, paddingX: 0, paddingY: 0, + offsetX: 0, + offsetY: 0, fitParent: false, strokeText: false, renderHDPI: true, @@ -65,8 +67,8 @@ var EL_WIDTH = (!opts.fitParent ? canvas.width : canvas.parentNode.clientWidth) / scale; var EL_HEIGHT = (!opts.fitParent ? canvas.height : canvas.parentNode.clientHeight) / scale; - var MAX_TXT_WIDTH = EL_WIDTH - (opts.paddingX * 2); - var MAX_TXT_HEIGHT = EL_HEIGHT - (opts.paddingY * 2); + var MAX_TXT_WIDTH = EL_WIDTH - (opts.paddingX * 2) - (opts.offsetX); + var MAX_TXT_HEIGHT = EL_HEIGHT - (opts.paddingY * 2) - (opts.offsetY); var fontSize = opts.font.match(/\d+(px|em|%)/g) ? +opts.font.match(/\d+(px|em|%)/g)[0].match(/\d+/g) : 18; var textBlockHeight = 0; @@ -89,7 +91,7 @@ } while (text.indexOf('\n\n') > -1); return text; } - + function setFont(fontSize) { if (!fontParts) fontParts = (!opts.sizeToFill) ? opts.font.split(/\b\d+px\b/i) : context.font.split(/\b\d+px\b/i); context.font = fontParts[0] + fontSize + 'px' + fontParts[1]; @@ -270,7 +272,7 @@ textPos.y = parseInt(textPos.y) + lineHeight; if (lines[i] !== skipLineOnMatch) { context.fillText(lines[i], textPos.x, textPos.y); - + if (opts.strokeText) { context.strokeText(lines[i], textPos.x, textPos.y); } @@ -286,21 +288,21 @@ context.textAlign = opts.textAlign; if (opts.textAlign == 'center') { - textPos.x = EL_WIDTH / 2; + textPos.x = (EL_WIDTH + opts.offsetX) / 2; } else if (opts.textAlign == 'right') { textPos.x = EL_WIDTH - opts.paddingX; } else { - textPos.x = opts.paddingX; + textPos.x = opts.paddingX + opts.offsetX; } } function setVertAlign() { if (opts.verticalAlign == 'middle') { - textPos.y = (EL_HEIGHT - textBlockHeight) / 2; + textPos.y = (EL_HEIGHT - textBlockHeight + opts.offsetY) / 2; } else if (opts.verticalAlign == 'bottom') { textPos.y = EL_HEIGHT - textBlockHeight - opts.paddingY; } else { - textPos.y = opts.paddingY; + textPos.y = opts.paddingY + opts.offsetY; } } @@ -329,6 +331,12 @@ if (isNaN(opts.paddingY)) throw new TypeError('Property "paddingY" must be a Number.'); + if (isNaN(opts.offsetX)) + throw new TypeError('Property "offsetX" must be a Number.'); + + if (isNaN(opts.offsetY)) + throw new TypeError('Property "offsetY" must be a Number.'); + if (typeof opts.fitParent !== 'boolean') throw new TypeError('Property "fitParent" must be a Boolean.'); diff --git a/canvas-text-wrapper.min.js b/canvas-text-wrapper.min.js index 2ecba73..c66d3cf 100644 --- a/canvas-text-wrapper.min.js +++ b/canvas-text-wrapper.min.js @@ -1 +1 @@ -!function(a){function b(b,c,d){"use strict";function e(a){do{a=a.replace(/\n\n/g,"\n"+M+"\n")}while(a.indexOf("\n\n")>-1);return a}function f(a){B||(B=t.sizeToFill?v.font.split(/\b\d+px\b/i):t.font.split(/\b\d+px\b/i)),v.font=B[0]+a+"px"+B[1]}function g(){isNaN(t.lineHeight)?-1!==t.lineHeight.toString().indexOf("px")?L=parseInt(t.lineHeight):-1!==t.lineHeight.toString().indexOf("%")&&(L=parseInt(t.lineHeight)/100*G):L=G*t.lineHeight}function h(){if(t.sizeToFill){var a=c.trim().split(/\s+/).length,b=0,d=!1!==t.maxFontSizeToFill;do{if(d){if(!(++b<=t.maxFontSizeToFill))break;i(b)}else i(++b)}while(HE){for(var h=0;v.measureText(b+f[h]).width<=E&&hE)break;for(;v.measureText(I[c]+a[b]).width<=E&&ba)&&(a=c,b=d);var e,f,g,h,i,j=" ";for(d=0;d1){var y={};for(var u in v)y[u]=v[u];var z=b.width,A=b.height;w=x,b.width=z*w,b.height=A*w,b.style.width=z*w*.5+"px",b.style.height=A*w*.5+"px";for(var u in y)try{v[u]=y[u]}catch(N){}v.scale(w,w)}var B,C=(t.fitParent?b.parentNode.clientWidth:b.width)/w,D=(t.fitParent?b.parentNode.clientHeight:b.height)/w,E=C-2*t.paddingX,F=D-2*t.paddingY,G=t.font.match(/\d+(px|em|%)/g)?+t.font.match(/\d+(px|em|%)/g)[0].match(/\d+/g):18,H=0,I=[],J=[],K={x:0,y:0},L=0,M="​";return c=e(c),f(G),g(),r(),h(),I}"module"in a&&"exports"in module?module.exports=b:a.CanvasTextWrapper=b}(this); \ No newline at end of file +!function(a){function b(b,c,d){"use strict";function e(a){do{a=a.replace(/\n\n/g,"\n"+M+"\n")}while(a.indexOf("\n\n")>-1);return a}function f(a){B||(B=t.sizeToFill?v.font.split(/\b\d+px\b/i):t.font.split(/\b\d+px\b/i)),v.font=B[0]+a+"px"+B[1]}function g(){isNaN(t.lineHeight)?-1!==t.lineHeight.toString().indexOf("px")?L=parseInt(t.lineHeight):-1!==t.lineHeight.toString().indexOf("%")&&(L=parseInt(t.lineHeight)/100*G):L=G*t.lineHeight}function h(){if(t.sizeToFill){var a=c.trim().split(/\s+/).length,b=0,d=!1!==t.maxFontSizeToFill;do{if(d){if(!(++b<=t.maxFontSizeToFill))break;i(b)}else i(++b)}while(HE){for(var h=0;v.measureText(b+f[h]).width<=E&&hE)break;for(;v.measureText(I[c]+a[b]).width<=E&&ba)&&(a=c,b=d);var e,f,g,h,i,j=" ";for(d=0;d1){var y={};for(var u in v)y[u]=v[u];var z=b.width,A=b.height;w=x,b.width=z*w,b.height=A*w,b.style.width=z*w*.5+"px",b.style.height=A*w*.5+"px";for(var u in y)try{v[u]=y[u]}catch(N){}v.scale(w,w)}var B,C=(t.fitParent?b.parentNode.clientWidth:b.width)/w,D=(t.fitParent?b.parentNode.clientHeight:b.height)/w,E=C-2*t.paddingX-t.offsetX,F=D-2*t.paddingY-t.offsetY,G=t.font.match(/\d+(px|em|%)/g)?+t.font.match(/\d+(px|em|%)/g)[0].match(/\d+/g):18,H=0,I=[],J=[],K={x:0,y:0},L=0,M="​";return c=e(c),f(G),g(),r(),h(),I}"module"in a&&"exports"in module?module.exports=b:a.CanvasTextWrapper=b}(this); \ No newline at end of file diff --git a/index.d.ts b/index.d.ts index bd3f6d2..47ab6d4 100644 --- a/index.d.ts +++ b/index.d.ts @@ -26,6 +26,14 @@ export interface CanvasTextWrapperOptions { * Vertical padding (in px) that is equally set on top and bottoms. */ paddingY?: number, + /** + * Horizontal offset (in px) that is set on left side. + */ + offsetX?: number, + /** + * Vertical offset (in px) that is set on top. + */ + offsetY?: number, /** * Fit canvas' container size instead of its own size. */ @@ -64,4 +72,3 @@ export interface CanvasTextWrapperOptions { */ textDecoration?: "none" | "underline" } - diff --git a/package.json b/package.json index e817ff8..c125690 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "canvas-text-wrapper", "description": "Split canvas text into lines on specified rule with optional alignment, padding, and more. Supports HDPI screens.", - "version": "0.10.2", + "version": "0.11.0", "license": "MIT", "main": "canvas-text-wrapper.js", "keywords": [ diff --git a/test/test.js b/test/test.js index 5d6b417..c063a06 100644 --- a/test/test.js +++ b/test/test.js @@ -28,4 +28,4 @@ var opts = { paddingX: 20 }; -CanvasTextWrapper(canvas, 'What an awesome library!', opts); \ No newline at end of file +CanvasTextWrapper(canvas, 'What an awesome library!', opts);