2

Is there a way to resize the height of a canvas according to text line count? The text will reside at bottom of canvas. An image will also be drawn into canvas at top-left most position of canvas, at same time of text, so the text will always start at a fixed location on canvas just under the image. I just want for the canvas to resize vertically according to text line-count, not while I am typing, only after I click a button after the text has been typed in a textarea.

I'm using this for text:

...

var str = $('#TEXTAREA').val();

var splittext = $.map(str.split(" "), function (t) { // Split words > than 40 chars
return t.match(/[\s\S]{1,40}/g) || [];
}).join(" ");

qrc.font = 'normal normal 14px monospace';
qrc.textAlign = 'center';
qrc.fillStyle = '#000';

wrapText(qrc, splittext, x, y, maxWidth, lineHeight);

function wrapText(context, text, x, y, maxWidth, fontSize, fontFace){
var words = text.split(' ');
var line = '';
var lineHeight = fontSize;

context.font=fontSize+" "+fontFace;

for(var n = 0; n < words.length; n++){
var testLine = line + words[n] + ' ';
var metrics = context.measureText(testLine);
var testWidth = metrics.width;      

if(testWidth > maxWidth) {
context.fillText(line, x, y);
line = words[n] + ' ';
 y += lineHeight;
if(++lineCount>6){return(y);} // Change to "Add 14px to canvas height at each line count" ?   
}
else {
line = testLine;
}
}
context.fillText(line, x, y);
return(y);
}

Currently, this code doesn't print text beyond 6 lines of text. I don't know where in the code to modify / add (see comments in code). Any hints?

UPDATE w/ FIDDLE

Here's a fiddle to experiment with. Please use that fiddle in your answer. Read TODO comment in fiddle. I'm stumped, but we're nearly thar! Thx for input. http://jsfiddle.net/uL84x7vw/12/

UPDATE w/ FIDDLE

This fiddle is same as previous but moves the image placeholder code to bottom of fiddle code so it doesn't get cleared. It's looking better but all lines of text except last line of text are still being wiped out. Obviously some code missing. Thx for input. http://jsfiddle.net/uL84x7vw/15/

koolness
  • 166
  • 19

3 Answers3

0

If you're using jquery:

var canvas = $('#yourCanvas');
canvas.height(canvas.height()+14);

If you're not (and you are using height="" attribute):

var canvas = document.getElementById('yourCanvas');
canvas.height = canvas.height+14;

If you're using css to style the height:

var canvas = document.getElementById('yourCanvas');
canvas.style.height = (parseInt(canvas.style.height.substring(0,canvas.style.height.length-2))+14)+"px";    
Jason
  • 734
  • 1
  • 7
  • 17
  • Where in my code can I implement your code? Also, no need for a canvas redraw? Thx for input. – koolness Sep 03 '14 at 00:15
  • Should be able to do it before your return(y), where your comment is - this is assuming you only need to add height after 6 lines. According to http://stackoverflow.com/questions/4938346/canvas-width-and-height-in-html5 it will clear the canvas (and require a redraw) though you should also manually clear the canvas for those browsers which do not. – Jason Sep 03 '14 at 00:26
  • A redraw means to repeat my function with the new params? I tried that but it's multiplying the height every time I apply it. I'll have a fiddle available tomorrow for testing. Thx for input. – koolness Sep 03 '14 at 03:00
  • You could save/restore what's currently on your canvas http://stackoverflow.com/questions/4858187/save-restore-background-area-of-html5-canvas, but yes a jsfiddle would be good. Good luck! – Jason Sep 03 '14 at 03:33
  • See Update with latest Fiddle. Thx for input. – koolness Sep 03 '14 at 18:20
0

As I understand you want your text dynamically appear and be resized in canvas. Use onchange event to track the number of lines of your text and dynamically manipulate canvas. Each time you write character it will be already on canvas. Use canvas.width = canvas.width + 14;

PashaB
  • 109
  • 4
  • Like I mentioned above, there is no dynamically applied text to canvas while typing (we don't see the canvas). Only after a button click the canvas will print the text. Thx for input. – koolness Sep 03 '14 at 00:18
  • See Update with latest Fiddle. Thx for input. – koolness Sep 03 '14 at 18:19
0

UPDATE - FINAL

DEMO

Finally got it working! The text displays under the image placeholder and resizes (vertically) the canvas at each addition or deletion of line of text. The split function splits long words exceeding canvas width (or whatever width prescribed). Using monospace font for fixed-width character display, but you can try other types of fonts. Copying a canvas to image and back saved the day! :

function showCanvas(){

var elem = document.getElementById('myCanvas');

var wd = 200;
var ht = 110;

ctx = elem.getContext('2d');
ctx.canvas.width = wd;
ctx.canvas.height = ht;
ctx.fillStyle = '#FFF'; // Text area BG color.
ctx.fillRect(0,0,wd,ht);

var str = $('#textArea').val();
var maxWidth = 190;
var lineHeight = 14;
var x = 100; // Since text alignment is centered.
var y = 104;  // Start position of text (under image placeholder).
var lineCount = 1;

var splittext = $.map(str.split(" "), function (t) {
return t.match(/[\s\S]{1,20}/g) || [];
}).join(" ");

ctx.font = 'normal normal 14px monospace'; // Monospace fonts have same widths.
ctx.textAlign = 'center'; // Choose text alignment, change var x accordingly.
ctx.fillStyle = '#000';

wrapText(ctx, splittext, x, y, maxWidth, lineHeight);

function wrapText(context, text, x, y, maxWidth, fontSize){
var words = text.split(' ');
var line = '';
var lineHeight = fontSize;

context.font=fontSize+" ";

for(var n = 0; n < words.length; n++){
var testLine = line + words[n] + ' ';
var metrics = context.measureText(testLine);
var testWidth = metrics.width;      

if(testWidth > maxWidth) {
context.fillText(line, x, y);
line = words[n] + ' ';
y += lineHeight;
if(++lineCount>1){ // If more than one line of text.

// Start - Canvas copy:

/* Only use drawImage for copying Canvas contents since getImageData()
is pixel data extraction requiring more processing time and cpu overhead. */

var backCanvas = document.createElement('canvas');
backCanvas.width = elem.width;
backCanvas.height = elem.height;
var backCtx = backCanvas.getContext('2d');
backCtx.drawImage(elem, 0,0);

// End - Canvas copy.

elem.height = elem.height+(lineHeight); // Canvas resizes vertically.
ctx.font = 'normal normal 14px monospace';
ctx.textAlign = 'center'; // Choose text alignment, change var x accordingly.
ctx.fillStyle = '#000'; 

ctx.drawImage(backCanvas, 0,0); // Paste canvas copy into source canvas.   
}   
}
else {
line = testLine;
}
}
context.fillText(line, x, y);
return(y);    
}

// Create image placeholder.

ctx.fillStyle = 'red'; 
ctx.fillRect(0,0,200,90);

}

Feel free to comment on streamlining code where applicable. Thx for input.

Community
  • 1
  • 1
koolness
  • 166
  • 19