adob animate JS cannot draw on canvas - javascript

Cannot get rectangle drawn on canvas with javascript in Adobe Animate with code below.
Successful only when using Createjs Ticker function with eventListener. Please note I'm NOT asking about animation -- but just about drawing something on the Canvas.
Am I incurring in a coding or in a conceptual error?
Thanks in advance for kind help to beginner.
this.stop();
//Line below not needed as far as I checked (when in in Adobe Animate)
//var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
// I get the rectangle and text on Canvas ONLY when I uncomment the three commented lines below
//createjs.Ticker.addEventListener("tick", handleTick);
//function handleTick() {
alert("ctx 25")
ctx.lineWidth = 5;
ctx.strokeRect(20, 20, 100, 100);
ctx.font = "bold 25px Verdana";
ctx.fillText("Index", 200, 70);
//}

You are accessing the context directly. EaselJS will clear the canvas each time it redraws.
There are a number of ways to add your own content:
1. Ensure it happens after the stage.update() or after a child's draw method
2. Draw to an external canvas, and use that as a source of a Bitmap
3. Draw to EaselJS's display list instead.
Here is how to draw to the stage using EaselJS
// You just need to do this once, not on every tick
var shape = new createjs.Shape();
shape.graphics.setLineStyle(5).drawRect(0,0,100,100);
shape.set({x: 20, y: 20}); // You can also set the x/y directly, or offset the shape in the drawRect call
stage.addChild(shape); // Wherever the stage is constructed.
var text = new createjs.Text("Index", "bold 25px Verdana", "#000");
text.set({x: 200, y:70});
stage.addChild(text);
Hope that helps!

Related

smoother canvas noise transition - fade in of particles

Here is my canvas on jsfiddle:
https://jsfiddle.net/vzrandom/fkho6grf/8/
I'm using simplex-noise.js and dat.GUI to create movement of particles. There is simulated click on canvas every 5 seconds. On click first animation is coming in background and new animation starts.
My problem is that animation on click starts too abruptly. I would like to have some kind of fade in of particles.
It seems like a simple problem but somehow I can't get it how to make fade in of elements that are inside the canvas - not entire canvas himself.
Entire code is on jsfiddle, here is part that handles the click:
function onCanvasClick(e) {
context.save();
context.globalAlpha = 1;
context.fillStyle = Configs.backgroundColor;
context.fillRect(0, 0, screenWidth, screenHeight);
context.restore();
simplexNoise = new SimplexNoise();
}
You need to render to an offscreen canvas.
Just create a second canvas
var canvas2 = document.createElement("canvas");
canvas2.width = canvas.width;
canvas2.height = canvas.height;
var ctx2 = canvas.getContext("2d");
Then for all your drawing calls use the background canvas 2dContext
To do the fade just render that canvas onto the display canvas setting alpha to make it fade.
The function called by requestAnimationFrame is passed a hi resolution time as the first argument. The code below is for the update function. Note that if you are using a polyfill for requestAnimationFrame you should use one that matches the standard.
var fadeTime = 1; // one second
var fadeTimeStart = undefined; // when undefined then this indicates start of fade
function update(time){
// render your particles to offscreen canvas
if(fadeTimeStart === undefined){ // get the current time as start
fadeTimeStart = time;
}
// get amount of fade
var fTime = (time - fadeTimeStart) / fadeTime;
// is it fading
if(fTime < 1){ // yes
ctx.globalAlpha = fTime;
clearRect(0,0,canvas.width,canvas.height); // clear last rendered scene
ctx.drawImage(canvas2,0,0); // draw the offscreen canvas
}else{
// you may or may not have to clear the canvas
ctx.drawImage(canvas2,0,0); // if no fade and assuming canvas is opaque then just draw the canvas onto the display.
}
requestAnimationFrame(update);
}
Then in the click event to start a new fade in just set the fadeTimeStart = undefined and it will start a new fade in.
I don't know if this is the effect you want to achieve, but you might get away with clearing the canvas a little on each iteration by filling it with a semi-transparent color in update function, instead of clearing it completely on each click.
See my fork here: https://jsfiddle.net/640e32ua/
Main change is changing Configs.backgroundColor to something semi-transparent and adding these two lines to update:
context.fillStyle = Configs.backgroundColor;
context.fillRect(0, 0, screenWidth, screenHeight);

Erasing Parts of an Image on HTML5 Canvas?

I have an HTML5 Canvas. I am using the KineticJS(KonvaJS) canvas library. On a blank canvas I dram an image as shown in the figure below. Now I want to create a circle Shape which can be used to erase parts of the image. The red circle in the image is the eraser.
How can I erase parts of an Image on HTML5 Canvas?
You can use Compositing to "erase" pixels.
Specifically you use destination-out compositing.
KineticJS does not support compositing, but you still have a couple of options:
(Note: KineticJS has become KonvaJS and I haven't checked whether KonvaJs supports compositing. If it now does, just use destination-out compositing inside KonvaJS)
Option#1: Use a native canvas element as your Kinetic.Image source
Create an in-memory html5 canvas using var c=document.createElement,
Resize the canvas to image size,
drawImage your image onto the canvas,
Create a Kinetic.Image and set its image property to a reference to the native canvas. The Kinetic.Image will display whatever is drawn onto the native canvas.
var kImage=new Kinetic.Image({
...
image:c,
...
Set the canvas Compositing to cause new drawings to "erase" existing pixels:
c.globalCompositeOperation='destination-out';
Listen for drag events on your circle-eraser. Use those events to draw a circle on the canvas that move just like the Kinetic circle-eraser moves. Since the canvas's compositing is set to "erase", new drawings of the circle on the canvas will erase the image on the canvas.
Your Kinetic.Image exactly reflects its canvas source (var c), so your Kinetic.Image will also display the image being erased in response to the Kinetic circle-eraser movements.
Option#2: Use a Kinetic.Shape
You can do the same operation as Option#1 by creating a Kinetic.Shape on a separate layer and getting a reference to the native canvas context using:
var ctx = myShapeLayer.getContext()._context;
This is a weaker option because KineticJS will redraw the shape--causing your erasing to be undone. Therefore you must do the additional step of saving all your circle-eraser's movements and replaying those movements (in drawFunc) to redo your erasing.
Thanks for markE for his detailed answer,
I have tried to get the context from the Konva.Layer() and it worked.
var freeHandDrawingImage = new Image();
freeHandDrawingImage.onload = function() {
var context = freeHandDrawingLayer.getContext('2d');
context.drawImage(this, 0,0);
context.globalCompositeOperation='destination-out';
freeHandDrawingLayer.draw();
};
freeHandDrawingImage.src = "image.png";
and I have used the Konva.Shape to erase by "destination-out" and draw free draw by custom "source-over":
freeDrawingType = 'brush';
isFreeDrawingMode = false;
isPaint = false;
lastPointerPosition = {};
drawFreeDrawings = function(){
var freeDraw = new Konva.Shape({
name: "freeDraw",
stroke: 'black',
strokeWidth: 5,
closed : false,
sceneFunc: function(context){
// free draw quad
debugger;
if(isPaint){
if (freeDrawingType === 'brush') {
context.globalCompositeOperation = 'source-over';
}
if (freeDrawingType === 'eraser') {
context.globalCompositeOperation = 'destination-out';
}
context.beginPath();
context.moveTo(lastPointerPosition.x, lastPointerPosition.y);
var newPosition = stage.getPointerPosition();
context.lineTo(newPosition.x, newPosition.y);
context.stroke();
debugger;
lastPointerPosition = newPosition;
context.strokeShape(this);
}
}
});
freeHandDrawingLayer.add(freeDraw);
// now we need to bind some events
// we need to start drawing on mousedown
// and stop drawing on mouseup
selectionBoxBackground.on('mousedown', function() {
if(isFreeDrawingMode){
isPaint = true;
lastPointerPosition = stage.getPointerPosition();
stage.draw();
}
});
selectionBoxBackground.on('mouseup', function() {
if(isFreeDrawingMode){
isPaint = false;
}
});
// and core function - drawing
selectionBoxBackground.on('mousemove', function() {
if (!isPaint) {
return;
}
freeHandDrawingLayer.draw();
});
}
In plain JavaScript this is pretty straight forward.
First get your canvas and drawing context ready:
var context=document.getElementById("your_canvas_id").getContext("2d");
var image=document.getElementById("your_image_id");
Now you want to draw the image to the context:
context.drawImage(image,0,0,image.width,image.height,0,0,image.width,image.height);
Now, when you want to erase part of your image, just draw over the canvas:
var x=y=radius=10;// Circle coordinates and radius.
context.fillStyle="#ffffff";// Your eraser color (not transparent)
context.beginPath();
context.arc(x,y,radius,0,Math.PI*2);
context.fill();
This only simulates erasing, however. If you want what you erase to be transparent afterwards, you might look into context.clearRect, but I'm not sure how you would do that with a circle.

Draw a Play button on canvas in javascript - triangle in a circle

So I'm creating a simple userscript for me - I want to draw a play button over shaded version of any GIF image on the site to have them only played when I want to.
I have inspired myself here. To make the whole thing nice, I'm drawing a green circle over the animation. This is my intended effect (I really wonder if once can make some shapes in GIMP):
And this is what I currently have:
The Cleese ironic face animation comes from this GIF portal
I made a fiddle of my current GIF pauser userscript.
The critical code for printing the circle:
//Assume these variables
var ctx = canvas context (2d)
var w = canvas width
var h = canvas height
//The code:
ctx.beginPath();
//I'm making sure the circle will always fit - therefore Math.min
ctx.arc(w/2, h/2, Math.min(60, w/2-20, h/2-20), 0, 2 * Math.PI, false);
ctx.fillStyle = 'rgba(0,180,0,0.5)';
ctx.fill();
ctx.lineWidth = 1;
ctx.strokeStyle = 'red';
ctx.stroke();
ctx.closePath();
I hope it's clear that the triangle must always fit into the circle (size of which may vary). It must have the vertical line a little bit shorter then the other two, which must be of equal length.
I'm totally not interested in any existing GIF pausing libraries. Keep in mind that the question is about the triangle, not the GIFs.
Like this? http://jsfiddle.net/32ECU/
//Draw a triangle in it
ctx.strokeStyle = 'white';
ctx.beginPath();
ctx.moveTo(w/3, h/3);
ctx.lineTo(w/3, h-h/3);
ctx.lineTo(w-w/4, h/2);
ctx.lineTo(w/3, h/3);
ctx.fillStyle = 'white';
ctx.fill();

animating custom shapes in html5 canvas

I'm new to canvas in html5 and would like to know how to animate a custom shape with lots of coordinates. I searched the web but with n o results. I'm only seeing results for circles or squares.
Here's an example of a random drawing. I would like it to move around the screen without setting coordinates for each point. http://jsfiddle.net/ZJdus/
var drawing = function(){
// rand drawing drawing
context.strokeStyle = "red";
context.beginPath();
context.moveTo(318, 200);
context.lineTo(183, 87);
context.lineTo(446, 125);
context.lineTo(446, 202);
context.lineTo(383, 236);
context.lineTo(318, 202);
context.lineTo(318, 125);
context.lineTo(446, 125);
context.lineTo(183, 236);
context.lineTo(318, 125);
context.lineTo(383, 187);
context.lineTo(383, 125);
context.lineTo(613, 180);
context.lineTo(446,400);
context.lineTo(413, 180);
context.lineTo(350, 180);
context.lineTo(318, 202);
context.lineTo(350, 180);
context.lineTo(183, 125);
context.stroke();
};
Is there a way to achieve this?
I'm also fairly new to Javascript so please explain as much as possible if you can.
Thanks
You can use translate() before you redraw the shape:
/// clear canvas before each redraw
context.clearRect(0, 0, context.canvas.width, context.canvas.height);
/// translate canvas (move origin)
context.translate(deltaX, deltaY);
... draw points here...
/// reset translate (faster than save()/restore())
context.translate(-deltaX, -deltaY);
Modified fiddle here
Optionally, instead of resetting the translate just use it as delta values directly instead of the absolute delta as now.
You can also add the delta values directly on your coordinates but that is slower than using the translate approach.
Hope this helps.
If your shape doesn't change, you should absolutely not redraw it every frame. Instead draw the shape once to a buffer canvas and then use drawImage at the location to animate the shape.
var drawing = //same as your code above only context is a buffer canvas...
contextOfDisplayedCanvas.drawImage(canvasWithShape, shape.x, shape.y);
Let me know if that doesn't make sense and I can expand.

Drawing a circle inside another circle canvas

I am trying to draw a gear in Canvas but running into issues from the start. I want to have a filled circle with a hallowed out middle. Instead, I am getting what looks to be an outline of a single circle.
Here is my code:
var ctx = document.getElementById("canvas").getContext("2d"),
i = 0;
function drawGear(){
ctx.fillStyle = "#000";
ctx.translate(50,50);
ctx.arc(0,0,20,0,Math.PI*2);
ctx.fill();
ctx.fillStyle = "#FFF";;
ctx.arc(0,0,5,0,Math.PI*2);
ctx.fill();
}
drawGear();
http://jsfiddle.net/te3jn/
I believe that the issue is something related to the globalCompositeOperation, but I tried several of them (source-over, source-atop, destination-over) and none seem to work the way I want.
You should begin a new path when drawing the second circle, like this:
ctx.fill();
ctx.beginPath();
ctx.fillStyle = "#FFF";
// ...
JS Fiddle.
Without this, you'll essentially redraw both circles - the inner and the outer one - with the second fill call (check this fiddle for demonstration)

Categories