I found that to get the base64 data from a HTML canvas, you had to do canvas.toDataURL();. The problem with this, is that when it gives you the base64, it is scaled to the generic 300 x 150 canvas size, but the actual canvas is 600 x 100. Is there a way to strech the image to be 600 x 100, or to export it in the base64 as such? Thanks in advance!
I had the width and height defined in CSS not HTML, so the document wasn't registering the widths and heights.
Here is the updated code below:
<body>
<script>
var granmoe = 0;
var hai = 5;
var runnin = 0;
while(runnin != hai){
var can = document.createElement("canvas");
can.id = "canvasite"
can.style = "width: 150px; height: 100px; display:none;"
document.body.appendChild(can);
c = document.getElementById('canvasite'),
ctx = c.getContext('2d');
var x = 0
if(runnin == 0){
var endheight = c.height/2
}
var y = endheight;
var widd = 0
while(widd != c.width){
ctx.fillStyle = "rgba("+0+","+255+","+0+","+(255/255)+")";
ctx.fillRect( x, y, 1, 1 );
var ychan = Math.floor((Math.random() * 6) + 1);
if(ychan == 1){
var y=y+2
}else if(ychan == 2){
var y=y+1
}else if(ychan == 3){
var y=y-1
}else if(ychan == 4){
var y=y-2
}else{
var y=y
}
var hig = y
while(hig != c.height){
ctx.fillStyle = "rgba("+0+","+255+","+0+","+(255/255)+")";
ctx.fillRect( x, hig, 1, 1 );
var hig = hig+1
}
var widd = widd+1
var x=x+1
}
{
var endheight = y
var runnin = runnin+1
document.getElementById('canvasite').setAttribute('id','nAn')
var imgm = document.createElement("img");
imgm.src = c.toDataURL();
imgm.id = "imageitem"
imgm.style = "display:none;"
document.body.appendChild(imgm)
var xid = granmoe*(300*(1/hai));
if(granmoe == 0){
var cansfoo = document.createElement("canvas")
cansfoo.id = "fullimage";
cansfoo.style = 'width: '+(hai*150)+'px; height: 100px; display:none;'
document.body.appendChild(cansfoo);
}
var ci=document.getElementById("fullimage");
var ctxi=ci.getContext("2d");
var imd=document.getElementById("imageitem");
ctxi.drawImage(imd,xid,0,(300*(1/hai)),180);
//end
var granmoe=granmoe+1
document.getElementById("imageitem").setAttribute('id','non');
}
}
var base64 = ci.toDataURL();
var bass = document.createElement("img");
bass.src = base64
bass.id = "resiz"
bass.style = "display:none;"
document.body.appendChild(bass);
{
var resize = document.createElement("canvas")
resize.id = "resize";
resize.width = (hai*150);
resize.height = 100;
resize.style = 'display:none;'
document.body.appendChild(resize);
var re=document.getElementById("resize");
var res=re.getContext("2d");
var imag=document.getElementById("resiz");
res.drawImage(imag,0,50,(hai*150),50);
document.write(resize.toDataURL());
}
</script>
</body>
Related
I have two div of same dimension which overlap each other using z-index.
Ist div contain image and 2nd div contain a canvas
I am trying to draw image on canvas same place as Ist div. I am using hammerjs library to zoomin/out , reposition and rotate image. I found these code somewhere else
function getMeta(url){
img = new Image();
var remoteImage = {}
img.src = url;
remoteImage.width = img.naturalWidth
remoteImage.height = img.naturalHeight
remoteImage.src = url;
return remoteImage
}
var urlImage = getMeta('https://www.penghu-nsa.gov.tw/FileDownload/Album/Big/20161012162551758864338.jpg')
var text = document.querySelector("#text");
var oImg=document.querySelector("#img_scan");
oImg.style['transition-duration'] = '100ms';
var timeInMs = 0;
var preAngle = 0;
var rotateAngle = 0;
var preRotation = 0;
var originalSize = {
width : oImg.offsetWidth,
height : oImg.offsetHeight,
}
var current = {
x : 0,
y : 0,
z : 1,
angle : 0,
width: originalSize.width,
height: originalSize.height,
}
var last = {
x : 0,
y : 0,
z : 1,
}
var oImgRec = oImg.getBoundingClientRect();
var cx = oImgRec.left + oImgRec.width * 0.5;
var cy = oImgRec.top + oImgRec.height * 0.5;
var imageCenter = {
x:cx,
y:cy
}
var pinchImageCenter = {}
var deltaIssue = { x: 0, y: 0 };
var pinchStart = { x: undefined, y: undefined, isPanend:false}
var panendDeltaFix = {x:0,y:0,isPanend:false}
var pinchZoomOrigin = undefined;
var lastEvent = ''
var hammer = new Hammer(oImg);
hammer.get('pinch').set({enable: true});
hammer.get('pan').set({direction: Hammer.DIRECTION_ALL}).recognizeWith(hammer.get('pinch'));
hammer.on("pinchstart", function(e) {
last.x = current.x;
last.y = current.y;
pinchStart.x = e.center.x;
pinchStart.y = e.center.y;
pinchImageCenter = {
x: imageCenter.x + last.x,
y: imageCenter.y + last.y
}
lastEvent = 'pinchstart';
});
hammer.on("pinchmove", function(e) {
if(preAngle == 0){
preAngle = Math.round(e.rotation);
preRotation = Math.round(e.rotation);
}else{
if(Math.abs(Math.round(e.rotation)-preRotation)>=300){
if(e.rotation > 0){
preAngle+=360;
}else if(e.rotation < 0){
preAngle-=360;
}
}
current.angle = rotateAngle + (Math.round(e.rotation)-preAngle);
preRotation = Math.round(e.rotation);
}
var newScale = (last.z * e.scale) >= 0.1 ? (last.z * e.scale) : 0.1;
var d = scaleCal(e.center, pinchImageCenter, last.z, newScale)
current.x = d.x + last.x;
current.y = d.y + last.y;
current.z = d.z + last.z;
update();
lastEvent = 'pinchmove';
});
hammer.on("pinchend", function(e) {
last.x = current.x;
last.y = current.y;
last.z = current.z;
rotateAngle = current.angle;
preAngle = 0;
lastEvent = 'pinchend';
});
hammer.on("panmove", function(e) {
var panDelta = {
x:e.deltaX,
y:e.deltaY
}
if (lastEvent !== 'panmove') {
deltaIssue = {
x: panDelta.x,
y: panDelta.y
}
}
current.x = (last.x+panDelta.x-deltaIssue.x);
current.y = (last.y+panDelta.y-deltaIssue.y);
lastEvent = 'panmove'
update();
});
hammer.on("panend", function(e) {
last.x = current.x;
last.y = current.y;
lastEvent = 'panend';
});
hammer.on('tap', function(e) {
if((Date.now()-timeInMs)<300){
if(last.z > 1){
last.z = 1;
current.z = 1;
update();
}else if(last.z <= 1){
last.z = 2;
current.z = 2;
update();
}
}
timeInMs = Date.now();
lastEvent = 'tap';
});
function scaleCal(eCenter, originCenter, currentScale, newScale) {
var zoomDistance = newScale - currentScale;
var x = (originCenter.x - eCenter.x)*(zoomDistance)/currentScale;
var y = (originCenter.y - eCenter.y)*(zoomDistance)/currentScale;
var output = {
x: x,
y: y,
z: zoomDistance
}
return output
}
function update() {
current.height = originalSize.height * current.z;
current.width = originalSize.width * current.z;
if(current.z < 0.1){
current.z = 0.1;
}
oImg.style.transform = " translate3d(" + current.x + "px, " + current.y + "px, 0)rotate("+current.angle+"deg)scale("+current.z+")"
}
So by above code user can zoomin/zoom out , rotate image . After they set image in their desired position i am putting that image on canvas so i can use dataurl method to save image later.
I tried below code to draw image on canvas same place as div ,same dimension and with same angle but sadly image is not getting exactly same positioned as div
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
$("#btn").click(copyoncanvas);
function copyoncanvas(){
var bound=objimg.getBoundingClientRect();
var objimg=new Image();
objimg.src="https://www.penghu-nsa.gov.tw/FileDownload/Album/Big/20161012162551758864338.jpg";
ctx.drawImage(objimg,bound.left,bound.top,current.width,current.height);
drawRotated(current.angle,bound.left,bound.top);
}
function drawRotated(degrees,l,t){
const objimg=document.getElementById("img_scan");
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.save();
var x=canvas.width/2;
var y=canvas.height/2;
ctx.translate(x,y);
ctx.rotate(degrees * Math.PI/180);
ctx.drawImage(objimg,-l,-t,current.width,current.height);
ctx.restore();
}
I think my problem is with drawrotated function because it work fine without using it but i want to rotate image on canvas too
HTML
<div id="container">
<div class="box"><canvas id="canvas"></canvas></div>
<div id="imgcont">
<img src="https://www.penghu-nsa.gov.tw/FileDownload/Album/Big/20161012162551758864338.jpg" id="img_scan" class="img-custom-img2"/>
</div>
</div>
<button id="btn">Copy on canvas</button>
CSS
#container{
position:relative;margin: 0px;
padding:0px;background:#ff0;
top:0px; overflow:hidden;
width:300px;
border:1px solid #000; height:250}
#img_scan,.box{
width:100%; height:100%;
position: absolute;
top: 0;
left: 0; margin:0; padding:0px
}
.box{z-index:98;height:250}
#canvas{width:100%;margin:0;
padding:0;
width:300;height:250}
#img_scan{width:300px;height:250px}
#imgcont{width:100%;height:250px;z-index:99}
I have implemented Signature pad canvas for my website. I want to make an imprint when saving signature after user signed. The problem I'm facing is to make that imprint size fit into canvas width. Canvas size is depends on users signature scale.
This is how it saved
If you could see I have trimmed out after signature drawn on the canvas space. And I'm using another function to print value on the top of the signature canvas after download it as an image. I want to adjust that text width as per canvas width to fit into the whole text value inside the canvas area.
var signaturePad = new SignaturePad(document.getElementById('signature-pad'), {
backgroundColor: 'rgba(255, 255, 255)',
penColor: 'rgb(0, 0, 0)'
});
var saveButton = document.getElementById('save');
var cancelButton = document.getElementById('clear');
function dataURLToBlob(dataURL) {
// Code taken from https://github.com/ebidel/filer.js
var parts = dataURL.split(';base64,');
var contentType = parts[0].split(":")[1];
var raw = window.atob(parts[1]);
var rawLength = raw.length;
var uInt8Array = new Uint8Array(rawLength);
for (var i = 0; i < rawLength; ++i) {
uInt8Array[i] = raw.charCodeAt(i);
}
return new Blob([uInt8Array], {
type: contentType
});
}
SignaturePad.prototype.removeBlanks = function() {
var cif = "0000885458";
var shortName = "/MR Jhon Doe";
var ref = "0854220190000001585/";
var imprintValue1 = "";
var imprintValue = "";
var imgWidth = this._ctx.canvas.width;
var imgHeight = this._ctx.canvas.height;
var imageData = this._ctx.getImageData(0, 0, imgWidth, imgHeight),
data = imageData.data,
getAlpha = function(x, y) {
return {
red: data[(imgWidth * y + x) * 4],
green: data[(imgWidth * y + x) * 4 + 1],
blue: data[(imgWidth * y + x) * 4 + 2]
};
},
isWhite = function(rgb) {
return rgb.red == 255 && rgb.green == 255 && rgb.blue == 255;
},
scanY = function(fromTop) {
var offset = fromTop ? 1 : -1;
// loop through each row
for (var y = fromTop ? 0 : imgHeight - 1; fromTop ? (y < imgHeight) : (y > -1); y += offset) {
// loop through each column
for (var x = 0; x < imgWidth; x++) {
if (!isWhite(getAlpha(x, y))) {
return y;
}
}
}
return null; // all image is white
},
scanX = function(fromLeft) {
var offset = fromLeft ? 1 : -1;
// loop through each column
for (var x = fromLeft ? 0 : imgWidth - 1; fromLeft ? (x < imgWidth) : (x > -1); x += offset) {
// loop through each row
for (var y = 0; y < imgHeight; y++) {
if (!isWhite(getAlpha(x, y))) {
return x;
}
}
}
return null; // all image is white
};
var cropTop = scanY(false),
cropBottom = scanY(true),
cropLeft = scanX(true),
cropRight = scanX(false);
cropTop += 30;
cropRight += 20;
var relevantData = this._ctx.getImageData(cropLeft - 10, cropTop - 20, cropRight - cropLeft, cropBottom - cropTop);
this._ctx.canvas.width = cropRight - cropLeft;
this._ctx.canvas.height = cropBottom - cropTop;
if (cif && shortName && ref) {
imprintValue1 = cif.concat("" + shortName);
imprintValue = ref.concat(imprintValue1);
}
this._ctx.clearRect(0, 0, cropRight - cropLeft, cropBottom - cropTop);
this._ctx.putImageData(relevantData, 0, 0);
var canvas_width = this._ctx.canvas.width;
var fontBase = canvas_width, // selected default width for canvas
fontSize = 70;
var ratio = fontSize / fontBase; // calc ratio
var size = canvas_width * ratio; // get font size based on current width
this._ctx.font = size;
// draw the imprintValue
this._ctx.fillStyle = "#e42f2f";
this._ctx.fillText(imprintValue, 0, 15);
};
saveButton.addEventListener('click', function(event) {
signaturePad.removeBlanks();
var dataURL = signaturePad.toDataURL('image/png');
download(dataURL, "signature.png");
});
function download(dataURL, filename) {
if (navigator.userAgent.indexOf("Safari") > -1 && navigator.userAgent.indexOf("Chrome") === -1) {
window.open(dataURL);
} else {
var blob = dataURLToBlob(dataURL);
var url = window.URL.createObjectURL(blob);
var a = document.createElement("a");
a.style = "display: none";
a.href = url;
a.download = filename;
document.body.appendChild(a);
a.click();
window.URL.revokeObjectURL(url);
}
}
cancelButton.addEventListener('click', function(event) {
signaturePad.clear();
});
.wrapper {
position: relative;
width: 400px;
height: 200px;
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
user-select: none;
}
img {
position: absolute;
left: 0;
top: 0;
}
.signature-pad {
position: absolute;
left: 0;
top: 0;
width: 400px;
height: 200px;
}
<script src="https://cdn.jsdelivr.net/npm/signature_pad#3.0.0-beta.3/dist/signature_pad.umd.min.js"></script>
<h1>
Put Signature
</h1>
<div class="wrapper">
<canvas id="signature-pad" class="signature-pad" width=400 height=200></canvas>
</div>
<div>
<button id="save">Save</button>
<button id="clear">Clear</button>
</div>
I've been creating a Flappy Bird game with JavaScript and for some reason, it's stopped displaying in the browser. I've checked the canvas displays by changing the background colour, but the actual JavaScript doesn't. I'm new to JavaScript, so I'm not sure where I'm going wrong. Thank you in advance.
Here is the html file:
<!DOCTYPE html>
<html>
<head>
<title>Flappy Bird using JS</title>
</head>
<body>
<canvas id="canvas" width="288" height="512"></canvas>
<script src="flappyBird.js"></script>
</body>
</html>
And here is the JS:
var cvs = document.getElementById("canvas");
var ctx = cvs.getContext("2d");
// load images
var bird = new Image();
var bg = new Image();
var fg = new Image();
var pipeNorth = new Image();
var pipeSouth = new Image();
bird.src = "images/bird.png";
bg.src = "images/bg.png";
fg.src = "images/fg.png";
pipeNorth.src = "images/pipeNorth.png";
pipeSouth.src = "images/pipeSouth.png";
// some variables
var gap = 85;
var constant = pipeNorth.height+gap;
var bX = 10;
var bY = 150;
var gravity = 1.5;
// on key down
document.addEventListener("keydown",moveUp);
function moveUp(){
bY -= 25;
}
// pipe coordinates
var pipe = [];
pipe[0] = {
x : cvs.width;
y : 0;
}
// draw images
function draw(){
ctx.drawImage(bg,0,0);
for(var i = 0; i < pipe.length; i++){
ctx.drawImage(pipeNorth,pipe[i].x,pipe[i].y);
ctx.drawImage(pipeSouth,pipe[i].x,pipe[i].y+constant);
pipe[i].x--;
if(pipe[i].x == 125){
pipe.push({
x : cvs.width,
y : Math.floor(Math.random()*pipeNorth.height) - pipeNorth.height
});
}
// detect collision
if(bX + bird.width >= pipe[i].x && bX <= pipe[i].x + pipeNorth.width &&
(bY <= pipe[i].y + pipeNorth.height || bY+bird.height >= pipe[i].y+constant)
|| bY + bird.height >= cvs.height - fg.height){
location.reload();
}
if(pipe[i].x == 5){
score++;
}
}
ctx.drawImage(fg,0,cvs.height - fg.height);
ctx.drawImage(bird,bX,bY);
bY += gravity;
ctx.fillStyle = "#000";
ctx.font = "20px Verdana";
ctx.fillText("Score: "+score,10,cvs.height-20);
requestAnimationFrame(draw);
}
draw();
I am using Teechart library to display y axes in the time intervals of 1 second. Chart1.axes.left.increment = 1; helps me to increment the yaxis in the interval of 1. What i need is to lay out dotted lines in between these Solid lines. I want to manually add the line series for dotted lines in time interval of 0.20 seconds. How can I use line series to add dotted lines here.
function draw_TeeChart() {
var w = window.innerWidth, h = window.innerHeight;
// Initialize Teechart[![enter image description here][1]][1]
Chart1 = new Tee.Chart("canvas");
document.getElementById("canvas").style.position = "relative";
document.getElementById("canvas").width= Math.round(0.82*w);document.getElementById("canvas").height= Math.round(0.89*h); //Chart1.bounds.x = Math.round(0.01*w);
Chart1.bounds.x = 14;Chart1.bounds.y= 10;
Chart1.bounds.width = Math.round(chartW*w);Chart1.bounds.height= Math.round(0.88*h);
Chart1.legend.visible = false; Chart1.panel.transparent = true;
Chart1.title.visible = false;Chart1.axes.bottom.title.text = " ";
Chart1.axes.left.increment = 1;
Chart1.axes.bottom.increment=1;
Chart1.axes.bottom.innerTicks.visible = true;
Chart1.axes.bottom.ticks.length = 9;
Chart1.axes.bottom.ticks.stroke.fill = "blue";
Chart1.axes.bottom.minorTicks.visible = true;
Chart1.axes.bottom.minorTicks.length = 4;
Chart1.axes.bottom.minorTicks.count = 4;
Chart1.axes.bottom.minorTicks.stroke.fill = "green";
// var dottedLines = Chart1.axes.bottom.increment=.2;
// var increment = 0.20;
// var dottedLines = Chart1.axes.bottom.grid.format.stroke.dash = [5,3];
// var solidLines = Chart1.axes.bottom.increment=1;
// for(increment =0.20;increment<100;increment =increment+0.20){
// if (increment % 1 == 0) {
// Chart1.axes.bottom.increment=1;
// }
// else {
// Chart1.axes.bottom.increment=0.20;
// Chart1.axes.bottom.grid.format.stroke.dash = [5,3];
// }
// }
Chart1.walls.back.format.fill = wallColorCode;
Chart1.walls.back.format.shadow.visible = false;
document.body.style.cursor = "pointer";
document.getElementById("EventCount").value = event_time.length.toFixed(0);
}
Image1:
Image2:
Here an example showing how you could extend the bottom axis adding a new innerGrid property and using it at drawLabel override.
var Chart1;
function draw() {
Chart1 = new Tee.Chart("canvas1");
var line1 = Chart1.addSeries(new Tee.Line());
line1.data.values = [10, 20, 30, 20, 50];
Chart1.legend.visible = false;
Chart1.axes.bottom.setMinMax(0, 5);
Chart1.axes.bottom.increment = 1;
Chart1.axes.bottom.innerTicks.visible = true;
Chart1.axes.bottom.ticks.length = 9;
Chart1.axes.bottom.ticks.stroke.fill = "blue";
Chart1.axes.bottom.minorTicks.visible = true;
Chart1.axes.bottom.minorTicks.length = 4;
Chart1.axes.bottom.minorTicks.count = 4;
Chart1.axes.bottom.minorTicks.stroke.fill = "green";
Chart1.axes.bottom.innerGrid = [];
Chart1.axes.bottom.innerGrid.increment = 0.20;
Chart1.axes.bottom.innerGrid.format = new Tee.Format(Chart1);
Chart1.axes.bottom.innerGrid.format.stroke.fill = Chart1.axes.bottom.grid.format.stroke.fill;
Chart1.axes.bottom.innerGrid.format.stroke.dash = [5, 3];
Chart1.axes.bottom.oldDrawLabel = Chart1.axes.bottom.drawLabel;
Chart1.axes.bottom.drawLabel = function(value, r) {
this.oldDrawLabel(value, r);
var c = this.chart.ctx,
rect = this.chart.chartRect,
f = this.innerGrid.format,
tmpX;
var tmpValue = value + this.innerGrid.increment;
while (tmpValue < value + this.increment) {
tmpX = Chart1.axes.bottom.calc(tmpValue);
if ((tmpX > rect.x) && (tmpX < rect.x + rect.width)) {
c.beginPath();
c.moveTo(tmpX, rect.y);
c.lineTo(tmpX, rect.y + rect.height);
f.stroke.prepare();
c.stroke();
}
tmpValue += this.innerGrid.increment;
}
//draw innerGrid between the axis minimum and the first label. Happens when scrolled
if (value - this.increment <= this.minimum) {
tmpValue = value - this.innerGrid.increment;
while (tmpValue > value - this.increment) {
tmpX = Chart1.axes.bottom.calc(tmpValue);
if ((tmpX > rect.x) && (tmpX < rect.x + rect.width)) {
c.beginPath();
c.moveTo(tmpX, rect.y);
c.lineTo(tmpX, rect.y + rect.height);
f.stroke.prepare();
c.stroke();
}
tmpValue -= this.innerGrid.increment;
}
}
};
Chart1.draw();
}
<!DOCTYPE html>
<html lang="en">
<head>
<script src="http://www.steema.com/files/public/teechart/html5/latest/src/teechart.js" type="text/javascript"></script>
</head>
<body onload="draw()">
<canvas id="canvas1" width="500" height="300">
This browser does not seem to support HTML5 Canvas.
</canvas>
</body>
</html>
I have this little script.
How can I center the text vertically? In another words, I need to bring out a variable from the function "wrapText" in order to use it to calculate the position of the text. Thanks a lot!
<canvas id="myCanvas" width="900" height="600" style="display:none;"></canvas>
<img id="canvasImg">
<script>
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
var imageObj = new Image();
imageObj.onload = function()
{
context.drawImage(imageObj, 0, 0);
}
imageObj.src = "img/imagea.jpg";
var myForm = document.getElementById('myForm');
myForm.addEventListener('submit', function(e)
{
var text = document.getElementById('area1').value;
if(text.lenght == 0)
{
alert("you forgot to put something");
}
function wrapText(context, text, x, y, maxWidth, lineHeight) {
var convtext = text.replace(/\n/g, ' |br| ');
var words = convtext.split(' ');
var line = '';
for(var n = 0; n < words.length; n++) {
var newline = false;
if (words[n].indexOf("|br|") > -1) newline = true;
var metrics = maxWidth;
var testWidth = maxWidth;
var testLine = line + words[n] + ' ';
if (context.measureText) {
metrics = context.measureText(testLine);
testWidth = metrics.width;
}
if ((testWidth > maxWidth && n > 0) || newline) {
context.fillText(line, x, y);
if (!newline) line = words[n] + ' ';
if (newline) line = "";
y += lineHeight;
} else {
line = testLine;
}
}
context.fillText(line, x, y);
}
var maxWidth = 500;
var lineHeight = 40;
var x = 100;
var y = 100;
context.font = "30pt HelveticaNeue-Light";
wrapText(context, text, x, y, maxWidth, lineHeight);
context.fillStyle = "#009bdc";
context.fillText("try", 100, 500);
var dataURL = canvas.toDataURL();
document.getElementById('canvasImg').src = dataURL;
e.preventDefault();
});
</script>
Here's how:
Modify wrapText to return the ending height value (so you can calculate the paragraph height).
Modify wrapText to optionally not draw (==optionally, not do fillText)
Run wrapText once in the no-draw mode to get the height of the wrapped paragraph.
Calculate a starting y that will produce a vertically centered paragraph: var centeringY = maxHeight/2 - paragraphHeight/2
Run wrapText again in the yes-draw mode using centeringY.
Example code and a Demo:
A paragraph of wrapped text that's vertically centered...
var canvas=document.getElementById("canvas");
var context=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
var maxWidth = 150;
var lineHeight = 20;
var x = 100;
var y = 100;
var text='It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness.';
context.font='12px verdana';
var height=wrapTextVCentered(context,text,x,y,maxWidth,lineHeight,true);
var y=(canvas.height-height)/2;
wrapTextVCentered(context,text,x,y,maxWidth,lineHeight,false);
context.strokeStyle='green';
context.strokeRect(x,y,maxWidth,height);
function wrapTextVCentered(context,text,x,y,maxWidth,lineHeight,measureOnly){
var height=0;
var convtext = text.replace(/\n/g, ' |br| ');
var words = convtext.split(' ');
var line = '';
context.textBaseline='top';
for(var n = 0; n < words.length; n++){
var newline = false;
if (words[n].indexOf("|br|") > -1) newline = true;
var metrics = maxWidth;
var testWidth = maxWidth;
var testLine = line + words[n] + ' ';
if (context.measureText){
metrics = context.measureText(testLine);
testWidth = metrics.width;
}
if ((testWidth > maxWidth && n > 0) || newline){
if(!measureOnly){ context.fillText(line, x, y); }
if (!newline) line = words[n] + ' ';
if (newline) line = "";
y += lineHeight;
height += lineHeight;
} else {
line = testLine;
}
}
if(!measureOnly){ context.fillText(line, x, y); }
height += lineHeight;
return(height);
}
body{ background-color: ivory; }
#canvas{border:1px solid red; margin:0 auto; }
<h4>Vertically centered paragraph on canvas</h4>
<canvas id="canvas" width=350 height=350></canvas>