How I can take value from a button and insert into a canvas to fill, for example if I press button T the box where is canvas will fill pattern with letter T entire box, I have an example but I don't want to copy the code I want to understand how it was made because I want to make something more advanced but I need to understand this first, here is the link example of feature.
For this I'm using 3 canvases. Two canvases are hidden but you don't need to attach them to the DOM. The logic is like this:
You have a first canvas (canvas1) where you draw the text from the <textarea>
You create a pattern using the canvas1: ctx2.fillStyle = ctx2.createPattern(canvas1,"repeat-x"); and you use it to fill a second canvas canvas2. This second canvas is twice as wide as the main canvas.
You use the canvas2 as a background image for the main canvas Here you may use a loop. I didn't.
let fontSize = 50;
const canvas = document.querySelector("canvas");
const canvas1 = document.createElement("canvas");
const canvas2 = document.createElement("canvas");
test.appendChild(canvas1);// you don't need to attach this to the DOM
test.appendChild(canvas2);// you don't need to attach this to the DOM
canvas.width = 500;
canvas.height = fontSize * 4;
canvas1.height = fontSize;
canvas2.height = fontSize;
canvas2.width = 2*canvas.width;
let ctx = canvas.getContext("2d");
let ctx1 = canvas1.getContext("2d");
let ctx2 = canvas2.getContext("2d");
ctx1.font = fontSize+"px 'Lucida Console', monospace";
theText.addEventListener("input",()=>{
ctx2.clearRect(0,0, canvas2.width, canvas2.height);
ctx.clearRect(0,0, canvas.width, canvas.height);
let _text = theText.value.toUpperCase();
let textLength = ctx1.measureText(_text).width;
canvas1.width = textLength || 1;// to avoid width 0 of the canvas
ctx1.font = fontSize+"px 'Lucida Console', monospace";
ctx1.fillStyle = "blue";
ctx1.textBaseline="middle";
ctx1.fillText(_text, 0, canvas1.height/2);
ctx2.fillStyle = ctx2.createPattern(canvas1,"repeat-x");
ctx2.fillRect(0,0, canvas2.width, canvas2.height);
ctx.drawImage( canvas2, 0, 0 );
ctx.drawImage( canvas2, -canvas2.width/2, fontSize );
ctx.drawImage( canvas2, canvas2.width/2, fontSize );
ctx.drawImage( canvas2, 0, 2*fontSize );
ctx.drawImage( canvas2, -canvas2.width/2, 3*fontSize );
ctx.drawImage( canvas2, canvas2.width/2, 3*fontSize );
})
canvas{border:1px solid;}
#test{display:none}
<canvas></canvas>
<textarea id="theText"></textarea>
<div id="test"></div>
In order to understand better what happens please delete #test{display:none} from the css. I hope this helps.
Related
I have an issue with the painting context.stokeText that style contains an alpha. A big value of line width makes some effect of intersected strokes, as a result, the color is darker.
How I can avoid this?
ctx.strokeStyle ="rgba(0,0,0,0.3)";
ctx.lineWidth = 15;
ctx.lineJoin="round";
ctx.strokeText(text, x, y);
Image
That's a bit of an inconsistency in the specs since usually overlapping sub-pathes are painted only once.
However strokeText() does create one shape per glyph, and thus this method will indeed paint each glyphs on their own, creating this visible overlapping.
To overcome this, you'll to be a bit creative:
first draw your text fully opaque,
then redraw the produced pixels with the desired alpha level (many ways to do so).
draw that on your scene (or draw the background behind).
Here are a few ways (there are many others):
Probably the easiest, but which costs more memory: use a second disconnected canvas:
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
// create a new canvas just for the text
const canvas2 = canvas.cloneNode();
const ctx2 = canvas2.getContext("2d");
ctx2.font = "60px sans-serif";
const text = "MY TEXT";
const x = canvas.width - ctx2.measureText(text).width - 20;
const y = canvas.height - 20;
// draw it fully opaque
ctx2.lineWidth = 15;
ctx2.lineJoin="round";
ctx2.strokeText(text, x, y);
// draw the background on the visible canvas
ctx.fillStyle = "#ffe97f";
ctx.fillRect(0, 0, canvas.width, canvas.height);
// now draw our text canvas onto the visible one
// with the desired opacity
ctx.globalAlpha = 0.3;
ctx.drawImage(canvas2, 0, 0);
<canvas width="465" height="234"></canvas>
More memory friendly, but which requires you to rewrite your drawing logic in a different direction, use compositing:
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
ctx.font = "60px sans-serif";
const text = "MY TEXT";
const x = canvas.width - ctx.measureText(text).width - 20;
const y = canvas.height - 20;
// first draw the text fully opaque
ctx.lineWidth = 15;
ctx.lineJoin="round";
ctx.strokeText(text, x, y);
// now apply the opacity
ctx.fillStyle ="rgba(0,0,0,0.3)";
ctx.globalCompositeOperation = "source-in";
ctx.fillRect(0, 0, canvas.width, canvas.height);
// and the background
ctx.fillStyle = "#ffe97f";
ctx.globalCompositeOperation = "destination-over";
ctx.fillRect(0, 0, canvas.width, canvas.height);
// if you want to keep drawing "normaly"
ctx.globalCompositeOperation = "source-over";
<canvas width="465" height="234"></canvas>
A mix of both, with different compositing rules:
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
ctx.font = "60px sans-serif";
const text = "MY TEXT";
const x = canvas.width - ctx.measureText(text).width - 20;
const y = canvas.height - 20;
// first draw the text fully opaque
ctx.lineWidth = 15;
ctx.lineJoin="round";
ctx.strokeText(text, x, y);
// now redraw over itself with the desired opacity
ctx.globalAlpha = 0.3;
ctx.globalCompositeOperation = "copy";
ctx.drawImage(canvas, 0, 0);
ctx.globalAlpha = 1;
// and the background
ctx.fillStyle = "#ffe97f";
ctx.globalCompositeOperation = "destination-over";
ctx.fillRect(0, 0, canvas.width, canvas.height);
// if you want to keep drawing "normaly"
ctx.globalCompositeOperation = "source-over";
<canvas width="465" height="234"></canvas>
My problem is simple. I just want to make invisible text parts when it's out of my rectangle. This image will help to understand what I want. How can I make invisible gray parts of text at canvas? Thanks for help!
After drawing your rectangle, invoke
ctx.clip();
Then draw the parts that should be only inside it.
Source
I would use ctx.globalCompositeOperation = "source-atop"
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
let cw = canvas.width = 400;
let ch = canvas.height = 110;
ctx.fillStyle = "#ccc";
ctx.beginPath();
ctx.fillRect(100,25,200,60);
ctx.globalCompositeOperation = "source-atop"
ctx.font="2em Verdana";
ctx.fillStyle = "#f00";
ctx.fillText("This is some text",110,65);
canvas{border:1px solid;}
<canvas id="canvas"></canvas>
I am working on a PWA, which will be used to conduct surveys, so what I'm doing is,
I'm capturing a snapshot from a video(within the app) and saving it in a canvas, which works fine.
Now I need to add date, time and geo-coordinates on it.
My Javascript code
var video = document.querySelector('video');
var takenPhotosDiv = document.getElementById( "taken-photos" );
var button = document.querySelector('button');
button.onclick = function() {
drawCanvas();
};
var drawCanvas = function(){
var canvas = window.canvas = document.createElement('canvas');
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
canvas.getContext('2d').drawImage(video, 0, 0, canvas.width, canvas.height);
canvas.getContext('2d').fillText( "30-08-2017" + " " + "15:25" + " " + "(79.85858454, 17.56852655)", 50, 150 );
takenPhotosDiv.appendChild( canvas );
}
The above code works fine and it does get close to what's being expected, here's the sample output of the above code
The final text-format should look like this (the text bar should be at the bottom of the image and not in the middle and with much bigger font)
PS: I don't just have to display this in the above mentioned format, even need to save and push it on Firebase later.
Edit:
var addTextToCanvas = function( canvas ){
canvas.lineWidth = 2;
canvas.fillStyle = "blue";
canvas.font = "bold 20px sans-serif";
canvas.textBaseline = "bottom";
canvas.fillText( "30-08-2017" + " " + "15:25" + " " + "(79.85858454, 17.56852655)", 0, 100 );
return canvas;
};
I tried this, but the font and font size remained the same.
This function is called from drawCanvas(), just before appending it to div, since it didn't work, I simply added called fillText on the canvas there itself
Edit 2:
Make sure that the methods and properties are set on the context not the canvas element itself.
We also need to calculate the actual vertical position of the text. Since it's aligned to the bottom we can use the height of the canvas minus some bottom padding:
var y = canvas.height - 10;
So, for example:
var addTextToCanvas = function( context ) { // pass in 2D context
var y = context.canvas.height - 10;
context.fillStyle = "blue";
context.font = "bold 20px sans-serif";
context.textBaseline = "bottom";
context.fillText( "30-08-2017"+" "+"15:25"+" "+"(79.85858454, 17.56852655)", 10, y );
return context;
};
or if you prefer to pass in the canvas:
var addTextToCanvas = function( canvas ) {
var context = canvas.getContext("2d");
var y = canvas.height - 10;
context.fillStyle = "blue";
context.font = "bold 20px sans-serif";
context.textBaseline = "bottom";
context.fillText( "30-08-2017"+" "+"15:25"+" "+"(79.85858454, 17.56852655)", 10, y );
return context;
};
The lineWidth doesn't do anything here so it can be removed.
I would recommend that you store the context once globally. It's the same context you get each time anyways but there is more overhead requesting it each time it will be used.
Functional example:
var ctx = c.getContext("2d");
var addTextToCanvas = function( context ) {
context.fillStyle = "blue";
context.font = "bold 20px sans-serif";
context.textBaseline = "bottom";
var y = context.canvas.height - 10;
context.fillText( "30-08-2017"+" "+"15:25"+" "+"(79.85858454, 17.56852655)", 10, y );
return context;
};
addTextToCanvas(ctx);
#c {border: 1px solid #999}
<canvas id=c width=600 height=180></canvas>
And finally, to extract as image the call needs to be made on the canvas element not context (can be confusing):
var dataUrl = canvas.toDataURL(); // saves out PNG image
or for JPEG:
var dataUrl = canvas.toDataURL("image/jpeg", 0.75);
Try this
var canvas = window.canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
var text = "30-08-2017\n15:25\n(79.85858454, 17.56852655)";
ctx.font = "30px Arial";
ctx.fillStyle = "red";
ctx.textAlign = "center";
ctx.fillText(text, canvas.width/2, canvas.height/2);
Here is my code. I am uploading a image and using like this :
> var canvas = document.createElement('canvas');
> var context = canvas.getContext('2d');
> context.drawImage(image, 0, 0);
This works fine but if I copy the imagedata like below to another canvas. It loads image partially.
var canvas = document.getElementById('myCanvas');
var context1 = canvas.getContext('2d');
context1.putImageData(context.getImageData(0, 0, image.width, image.height), 0, 0);
I tried same approach by creating two canvas and this code which worked fine but without image.
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.fillStyle = "red";
ctx.fillRect(0, 0, 300, 300);
var d = document.getElementById("myCanvas1");
var btx = d.getContext('2d');
var imgData = ctx.getImageData(0, 0, 300, 300);
btx.putImageData(imgData, 0, 0);
If i create two canvas it works fine but not like the above where I am using in memory canvas.
My HTML file has this :
<canvas id="myCanvas" width="960" height="960"></canvas>
<canvas id="myCanvas1" width="960" height="960"></canvas>
When you create canvases, you need to set their width manually. Default canvas size is 300x150. From here HTMLCanvasElement.
Something like this:
var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
canvas.width = image.width;
canvas.height = image.height;
context.drawImage(image, 0, 0);
To copy one canvas to another use drawImage rather than getImageData, setImageData That way you will use the GPU to move the pixels rather than the CPU. You also have the option to resize, crop, and apply a variety of FXs.
// create a copy of canvasSource
// returns the newly created canvas.
function copyCanvas(canvasSource){
var canvasCopy = document.createElement("canvas");
canvasCopy.width = canvasSource.width;
canvasCopy.height = canvasSource.height;
canvasCopy.getContext("2d").drawImage(canvasSource, 0, 0);
return canvasCopy;
}
If I try to draw text to my canvas at the onload event, the text shows up blurry. I draw to the same canvas later via a button click from another function and it's fine. But if I call this function from the button, it's still blurry. Can anybody see something wrong in this code?
window.onload = initCanvasRender;
function initCanvasRender() {
var c = document.getElementById("canvas");
var ctx = c.getContext('2d');
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillStyle = 'black';
ctx.font = '20px Times New Roman';
ctx.fillText('hello...', c.width/2, c.height/2);
}
There may be some problem with the
ctx.fillText('hello...', c.width/2, c.height/2);
Because if you for example set width of the canvas with css then c.width and c.height will be the default size for the canvas which is, 300x150 and not the size defined in css. Try to set two variables for the width and height that are global for your application. E.g
var canvasWidth = 400;
var canvasHeight = 200;
c.width = canvasWidth;
c.height = canvasHeight;
/* ... */
and then later in your code you can use canvasWidth and canvasWeight:
ctx.fillText('hello...', canvasWidth/2, canvasHeight/2);
Take a look at this test: http://jsfiddle.net/EsQfb/7/ it's important to use use the canvas.width and not canvas.style.width in your case.
Take a look at this for more information about this: http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#attr-canvas-width