I've been experimenting with creating a canvas element in a few different ways and was wondering if anyone knows which of these (or some other) ways is the most efficient.
the most basic seems to be placing a canvas element in the html like this:
<canvas id="myCanvas" width="500", height="500"></canvas>
and then in the javascript:
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext('2d');
there are times I need to keep all my canvas biznass in a .js file (ex when I want to dynamically change the width/height of the element) and I'll do it like this:
var canvas = document.createElement('canvas');
document.body.appendChild(canvas);
canvas.height = '500';
canvas.width = '500';
var ctx = canvas.getContext('2d');
or when I get lazy, something like this:
document.write("<canvas id='myCanvas' width='500', height='500'></canvas>");
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext('2d');
Pros? Cons? Edits? Other options?
The first one is the best by far.
The first one wins on efficiency (slightly) because the second and third ones cause the page to re-layout unnecessarily. Also, if there's an error in the JavaScript that halts subsequent execution the page will look awfully weird.
Furthermore, you should always choose the first one for accessibility purposes. If someone has JavaScript disabled you will still want them to see the fallback content. Even if it is just to say "turn on JavaScript!" or "Get a modern browser!"
If you use the second or third method, the user might never know, and they will continue on merely thinking that you suck at page layouts because there's a strange space where fallback content (or a canvas for that matter) ought to be.
Even aside from all that, methods 2 and 3 break the order of things a little bit. When are you adding the canvas? after onload fires? Well by firing onload the page just said that the DOM was done doing it's dance and its all ready! And then you go and change the DOM!
...How rude!
Of course you probably won't be using any libraries that rely on the the implicit promise made in onload that you are sorta breaking by using 2 or 3, but it's an unnecessary break of convention if you can avoid it.
By the way for the start of simple apps or examples I have this fiddle bookmarked:
http://jsfiddle.net/eAVMs/
Which uses the first method. If you use canvas a lot, you should bookmark this fiddle too!
document.write("<canvas id='myCanvas' width='500', height='500'></canvas>");
Is the only method Id caution against. Using document.write is generally considered bad practice for arbitrarily creating elements.
I could just repeat why here, but this answer explains it well enough.
The other two methods are perfectly valid and fine. Its really just a matter of preference. Generally I create a canvas tag, unless I need a temp canvas to do something, in which Ill use the createElement method.
Other than that its really just a matter of preference and overall doesn't affect performance in any way.
Related
I want to generate a blurred image from a normal image. I've searched on the internet and found out that people have done it by putting CSS filter property through javascript on Image to make it blur. But it can be removed by inspecting the page and I don't want that.
I want to generate a blurred version of image through javascript. I think I can do it with canvas but I never worked with canvas and any help will be highly appreciated (:
So, it depends. If you're worried about them removing it with developer tools, then the answer is probably "you can't".
The reason for this, is if you want to blur it with JavaScript, you need to send the unblurred image. And, if you send the unblurred image, they can easily scoop it out of the network tab, even if you never add it directly to the DOM. Anything you use as an input for JavaScript can be obtained by a clever enough user.
If you want the user to never be able to see the original, only the blurred, you'll have to blur it server-side.
If, for some weird reason, you're okay with that and still want to blur it in canvas, you'll need to pick and implement a blur algorithm for canvas. There are lots of different blur algorithms to choose from. Probably the most common one would be a Gaussian blur.
The algorithm isn't super insane, but it also isn't exactly super straightforward either, and I'd recommend using a library instead, such as this one: glur. I've not directly used that one, so can't vouch for it, but it has half a million downloads a week on NPM, so probably pretty solid.
Simple filters
You can apply a blur via the canvas using ctx.filter. CanvasRenderingContext2D.filter will accept a (limited set of) filters defined as strings. Eg ctx.filter = "blur(10px)";
See ctx.filter for set of filters you can use directly.
Example
Example uses CanvasRenderingContext2D.filter to blur image over time.
const img = new Image;
img.src = "https://i.stack.imgur.com/C7qq2.png?s=256&g=1";
img.addEventListener("load", () => requestAnimationFrame(uodate));
function drawImageBlur(img, blurAmount) {
const ctx = can.getContext("2d");
ctx.clearRect(0,0,128,128);
ctx.filter = "blur(" + blurAmount+ "px)";
ctx.drawImage(img, 128 - img.naturalWidth * 0.5, 128 - img.naturalHeight * 0.5);
}
var frameCount = 0;
function uodate(time) {
if (frameCount++ % 10 === 0) { // no point burning CPU cycles so only once every 10 frames
drawImageBlur(img, Math.sin(time / 1000) * 5 + 6);
}
requestAnimationFrame(uodate);
}
canvas {border: 1px solid black;}
<canvas id="can" width="256" height="256"></canvas>
There is no way to protect the image from inspection if you apply the image blur on the client (no matter what method you use). If you want to obfuscate (blur) the image it must be done on the server.
I am trying to verify that this happens no matter what, and there's no way to bypass it. It seems pretty silly to me that createjs uses this architecture. But I noticed that creating a stage from an existing canvas element removes all shapes, writings, etc from the canvas? Code is below:
html:
<canvas id="canvas" width="800" height="400"></canvas>
js:
var canv = document.getElementById("canvas");
var stage = new createjs.Stage(canv);
var ctx = canv.getContext('2d');
ctx.beginPath();
ctx.arc(50,50,10,0,2*Math.PI);
ctx.stroke();
createjs.Ticker.addEventListener("tick", tick);//circle created is overwritten here!!!?! Why createjs!?
//stage.update();
createjs.MotionGuidePlugin.install();
var shape1 = new createjs.Shape();
shape1.graphics.f("#000000").dc(0,0,10);
var path1 = new createjs.Shape();
path1.graphics.beginStroke("#ff0000").mt(0,0).qt(50,100,100,0);
stage.addChild(path1, shape1);
createjs.Tween.get(shape1).to({guide:{ path:[0,0, 50,100, 100,0] }},2000, createjs.Ease.cubicInOut);
function tick(event) {
stage.update();
}
Is this something that cannot be bypassed? It seems silly to me that createjs wouldn't just actually use the existing element unerased. If not, what is the point in passing in an element in the first place, why doesn't it just create a canvas element, and give you the ID? Anyways, if this is how it's going to be, unfortunately, I am going to have to go somewhere else. Sad, because createjs seemed pretty useful.
CreateJS uses a retained graphics mode, that is, it stores the state and redraws it each time. This is because the canvas is basically a big Bitmap with drawing commands – clearing the stage is the only way to remove the previous state.
But good news! There are lots of ways to get around these limitations if you want to blend CreateJS content with other content, or even make additive drawing effects.
The first is easy, which is setting autoClear. This will prevent the clear, and just draw the new contents over the old one.
stage.autoClear = false;
The second is a bit tougher, but great for instances where you want to mix CreateJS content with other libraries or effects. You can basically use the other canvas as the source to a Bitmap you include in CreateJS:
// Create a child for CreateJS referencing the other canvas
var bmp = new createjs.Bitmap(otherCanvas);
// Add it at the bottom (or top or wherever) in your new CreateJS canvas
stage.addChildAt(bmp, 0);
This is a great approach because it lets you put your content wherever you want, edit it separately, etc.
If you have a different case this doesn't cover, let me know and I can try to make a recommendation!
Cheers.
Long time lurker but never made an account. Just wanted to preface that I'm by no means a dev and just tinkering and experimenting for fun, so I apologise in advance if I seem really dumb.
I'm working on a dynamic overlay for Twitch streaming and was previously using AS3 but I've switched over to HTML5 now. I'm trying to load an image onto the canvas (which will eventually be a profile picture fetched using Twitch API... but one step at a time). I'm using Adobe Animate and I have the following so far applied in Actions on the first frame of the layer:
var canvas = document.getElementById('canvas'),
context = canvas.getContext('2d');
show_image();
function show_image() {
source_image = new Image();
source_image.src = 'https://cdn.sstatic.net/stackexchange/img/logos/so/so-icon.png';
source_image.onload = function () {
context.drawImage(source_image, 100, 100);
}
}
When I hit Ctrl+Enter and see it in Chrome, the image appears for the first frame then disappears. I'm not sure how I'm supposed to get it to stay indefinitely. I need to be able to animate it later, and it'll change depending on the latest follow/donation/sub, etc.
I tried extending the frame itself in the timeline, however, this just changed long how it took to loop and didn't make the image itself stay longer. I'm probably missing something really simple!
Any help would be appreciated. Thanks!
Your code is okay if your approach is using a canvas with HTML and JS, without any libraries involved. However, this is not the case, as you are using Animate, and the way to draw graphics with it is different than using default canvas methods like drawImage().
Animate includes the CreateJS suite, which includes the EaselJS library ,and this allows you to use another tools to draw to your canvas. Two or them are the Stage object, the visual container of your animate project, and the Bitmap object, who represents an image, canvas or video. For effects of this question, only both objects are required.
Note that the code below is only for the first frame:
/* It is not necessary to declare the canvas or stage element,
as both are already declared. At this point the stage is ready to be drawn */
show_image();
function show_image() {
var source_image = new Image();
source_image.src = 'https://cdn.sstatic.net/stackexchange/img/logos/so/so-icon.png';
source_image.onload = function(event) {
/* A new Bitmap object is created using your image element */
var bmp = new createjs.Bitmap(event.currentTarget);
/* The Bitmap is added to the stage */
stage.addChild(bmp);
}
}
I have a very simple question : is it possible to use globalCompositeOperation for only a restricted number of images?
For example, I draw a lot of stuff into my canvas. And on top of everything, and completed unrelated, I want to do some operations on two images (and I just want the result to be displayed, not both images). How can that be done?
For now, doing such operations affects everything that's already drawn underneath.
So a solution I found is doing the operations in another canvas, which I display on top of my main, first canvas. But this looks bad. First, it hits performances. Then, it doesn't feel intuitive. And last, I loose control over the layers : whatever is in my second canvas will always be on top of the first canvas.
This looks like a pretty simple feature, I hope I'm just bad at googling!
Thanks a lot!
Create a offscreen canvas and use it as a work space. You can create many as long as you have the RAM to store them.
To create an offscreen canvas
function createCanvas(w,h){
var canvas = document.createElement("canvas");
canvas.width = w;
canvas.height = h;
canvas.ctx = ctx.getContext("2d");
return canvas;
}
Easy as that and then you just treat it as an image. To draw to another canvas
var offScreenCan = createCanvas(1024,1024);
offScreenCan.ctx.drawImage(myImage); // put something on the canvas
ctx.drawImage(offScreenCan,0,0); // draw that canvas to another
I attach the context to the canvas rather than wrap the canvas in a containing object. I used to worry that the canvas would affect performance now I convert all images to canvas as soon as I load them and it does not impact performance at all.
Hi I am playing around with shapes and canvas and I have a question:
So say I have this code that draws a nice rectangle on the canvas:
$("#create_rectangle").bind("click", function() {
if(canvas[0].getContext){
var ctx = canvas[0].getContext('2d');
ctx.strokeRect(50,50,50,50);
}
});
Now I say I want to store a reference to that rectangle so that I can make alteration to it at a later stage. The stokeRect() method does not seem to return any value. How do I reference that particular rectangle that was created?
Well you can't reference it, but you can include it in a draw function which depending your arguments allow you to move/rotate hide etc.
It very depend on what you want to do with this shape.
This tutorial can be helpfull to understand manipulation of shape.
http://simonsarris.com/blog/140-canvas-moving-selectable-shapes
You can't.
Canvas is basically just a canvas. You throw some paint at it, it dries and you're done. You can't take your paint and move it somewhere else—but you can paint over it.
What you may want is SVG. It keeps track of shapes and other assorted things so that you can change them, deal with interactions much more precisely, et cetera.