Up until now, I have set HTML canvas context the way in tutorials it is shown, like:
var canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d");
ctx.font = "15px calibri";
...
I was wondering whether it is possible to set the context of the canvas by passing in an object with the correct attributes to one of it's methods? For example:
var canvas = document.getElementById("canvas");
var context = {
font: "15px calibri",
...
);
canvas.setContext(context);
The reason for this is I am creating a custom canvas in angular. For example, my controller will get the <canvas> element. A method in a service will callback the context object to set for the canvas.
The custom canvas is to be converted to PNG and set as the icon for a Marker on Google Maps. The marker is added to the maps in the service:
addMarkerToMap: function(position, map, canvas) {
new google.maps.Marker({
position: position,
map: map,
icon: canvas.toDataURL("image/png")
});
}
So I am hoping to pass in the canvas element into this fucntion (with it's context already set) and just set it's PNG equivalent as the Marker icon.
EDIT:
I've now realised that other then just setting attributes (i.e. fillStyle), I am invoking the contexts methods (i.e. beginPath()).I think that this will make it much harder to accomplish what I am trying
Even though it looks like nonsence, after you mutate context of a canvas element, it is preserved:
const canvas1 = document.getElementById('myCanvas');
const ctx = canvas1.getContext('2d');
ctx.font = '15px Calibri';
const canvas2 = document.getElementById('myCanvas');
console.log(canvas2.getContext('2d').font); // -> "15px Calibri"
So, in you case, it is safe to rely on context at any moment in future after you pass reference to canvas element to addMarkerToMap function.
Based on this answer - and the spec as it says, you possibly cannot replace the canvas context with another, as "Every canvas has what is called a primary context".
If possible, you could create a canvas programmatically and then append it to HTML as a child (or even cloning & replacing the old one at cases - if not too many replacements happening).
You could for instance use jQuery to do something like:
// Just a new canvas, you could even clone the old one
var canvas1 = $('<canvas/>', {
id: 'canvas1',
height: 500,
width: 200,
font: '15 px'
});
document.body.appendChild(canvas1);
Related
I have a primary canvas element which I perform drawing operations on using the context. I can successfully draw images, shapes, and also transform those objects using the context.
I now need my own textbox. I want to create another canvas, render the text to that canvas, then copy that data onto the primary canvas... the catch is I want to have it transformable, almost is if I was just calling the drawImage function.
There exists the getImageData and putImageData methods, but those do not work because it does not take into consideration the transformation.
I am looking for something like this...
var tempcanvas = document.createElement("canvas");
var ctx = tempcanvas.getContext('2d');
ctx.fillRect(0,0,5,5);
then on my primary canvas which I already have, I would like to draw that as if it were an image object.
context = maincanvas.getContext('2d');
context.translate(50,50);
context.rotate(180);
context.drawImage(tempcanvas)
I think an older version of canvas had a canvas.PenPos property that let you see where the current pen location is. I'm mostly going to use this for debugging purposes and to draw relatively (e.g. a line 50px long to the right of the current position). Is there any way to do this currently? If not, why did they remove it...?
The pen position I'm referring to is the virtual "pen" that a drawing context (that you would get for example by calling var ctx = canvas.getContext('2d')) uses, rather than a physical pen or mouse.
I am not trying to draw with a mouse. Again, this is not a physical pen I'm looking for, it's the virtual pen that is moved with ctx.moveTo(x,y)
According to w3.org, there isn't a method that returns the pen position.
Because the .getContext("2d") method returns an object, you can store the pen position as properties and call them as needed:
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.beginPath();
//Start position
ctx.x = 100;
ctx.y = 100;
ctx.moveTo(ctx.x, ctx.y);
ctx.x = ctx.x + 100;
ctx.y = ctx.y + 300;
ctx.lineTo(ctx.x, ctx.y);
ctx.stroke();
When creating an arc though, you would need to calculate the pen's new position afterward.
I am trying to copy part of a fabricjs canvas to another canvas.I am not sure if fabric has a method suitable for doing it (please let me know if that's the case) and after some searching I decided to do it without using fabric. But the canvas was already created using fabricjs. new fabric.Canvas(). Now when I try to copy a part of this canvas using context.drawImage(), I get a TypeError. I tried replacing the canvas with a img or a canvas created without using fabric and that works. So, I am guessing I may have to use the fabric canvas object a bit differently.
If you want to copy a rectangular zone from the canvas in order to export it as an image you could use the following:
canvas.deactivateAll();
canvas.renderAll();
var ctx = canvas.getContext("2d");
var myImageData = ctx.getImageData(box.x, box.y, box.w, box.h);
var buffer = document.createElement('canvas');
var bufferCtx = buffer.getContext("2d");
buffer.width = box.w;
buffer.height = box.h;
bufferCtx.putImageData(myImageData, 0, 0);
window.open(buffer.toDataURL('image/png'));
I have two canvases that are different sizes. My goal is copy the user's drawing from the main canvas to a second canvas as a scaled down version. So far the drawImage() and scale appear to be working, but the second canvas keeps the old version of the main drawing along with the new copy. I tried clearing it each time before calling drawImage(), but that doesn't appear to do anything. How can I copy just the current image to my secondary canvas each time the function runs?
$('#hand').dblclick(function(){
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
//var imageData = context.getImageData(0, 0, 100, 100);
var newCanvas = document.getElementById('scaledCanvas');
var destCtx = newCanvas.getContext('2d');
destCtx.clearRect(0, 0, newCanvas.width, newCanvas.height);
destCtx.scale(.5,.5);
destCtx.drawImage(canvas, 0, 0);
});
I can include more code if necessary. I also just realized that scale keeps getting called; this explains why the new copied image would get smaller each time as well, so that might be another problem.
It's quite simple actually, you're using what's called a transform (translate, rotate, or scale).
In order to use them "freshly" each time you must save and restore the canvas state each time.
$('#hand').dblclick(function(){
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
//var imageData = context.getImageData(0, 0, 100, 100);
var newCanvas = document.getElementById('scaledCanvas');
var destCtx = newCanvas.getContext('2d');
destCtx.clearRect(0, 0, newCanvas.width, newCanvas.height);
//save the current state of this canvas' drawing mode
destCtx.save();
destCtx.scale(.5,.5);
destCtx.drawImage(canvas, 0, 0);
//restore destCtx to a 1,1 scale (and also 0,0 origin and 0 rotation)
destCtx.restore();
});
It's also important to note you can push several times before calling restore, in order to perform many cool geometric tricks using recursive functions etc...
Take a look at this explanation of states and transformations:
https://developer.mozilla.org/en-US/docs/HTML/Canvas/Tutorial/Transformations
Hope this helps you understand canvas transforms a bit better.
Is there any way to create a deep copy of a canvas element with all drawn content?
Actually the correct way to copy the canvas data is to pass the old canvas to the new blank canvas. Try this function.
function cloneCanvas(oldCanvas) {
//create a new canvas
var newCanvas = document.createElement('canvas');
var context = newCanvas.getContext('2d');
//set dimensions
newCanvas.width = oldCanvas.width;
newCanvas.height = oldCanvas.height;
//apply the old canvas to the new one
context.drawImage(oldCanvas, 0, 0);
//return the new canvas
return newCanvas;
}
Using getImageData is for pixel data access, not for copying canvases. Copying with it is very slow and hard on the browser. It should be avoided.
You can call
context.getImageData(0, 0, context.canvas.width, context.canvas.height);
which will return an ImageData object. This has a property named data of type CanvasPixelArray which contains the rgb and transparency values of all the pixels. These values are not references to the canvas so can be changed without affecting the canvas.
If you also want a copy of the element, you could create a new canvas element and then copy all attributes to the new canvas element. After that you can use the
context.putImageData(imageData, 0, 0);
method to draw the ImageData object onto the new canvas element.
See this answer for more detail getPixel from HTML Canvas? on manipulating the pixels.
You might find this mozilla article useful as well https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Canvas_tutorial/Drawing_shapes