I've been stuck on this for about a week now and can't figure out why the shape instance inside my container is getting blurred when it is animated at 60 fps. My container holds one shape instance. The shape instance is associated with one graphics instance. There seems to be a white blur that trails the direction of the animation. Is there a way to stop this blurring or is it a limitation of tweenJS? Here's the jsFiddle.
http://jsfiddle.net/1chh2de6/
Here are some additional details, I am working on a billiards game which involves a lot of moving circles. I've created a class for each pool ball, which will hold more shape instances in the future. However, at 60 fps the shape instances are blurred during animations. Here's the 'poolBall' class.
function poolBall(number, posX, posY) {
this.number = number;
this.shapesArray = [];
this.shapesArray.push(new createjs.Shape());
this.containerInstance = new createjs.Container();
this.containerInstance.addChild(this.shapesArray[0]);
this.containerInstance.x = posX;
this.containerInstance.y = posY;
this.drawGraphic = function(){
this.shapesArray[0].graphics.beginFill('white')
.setStrokeStyle(1)
.beginStroke("#000000")
.drawCircle(14, 14, 14)
.endFill()
.endStroke();
};
};
This is just a symptom of how the canvas displays the contents as they change, and not related to EaselJS or TweenJS. Here is a fiddle using raw canvas APIs.
http://jsfiddle.net/lannymcnie/97vLu9q9/1/
Circle Code
context.beginPath();
context.arc(0,0,20,0,2* Math.PI,false);
context.fillStyle = "white";
context.fill();
context.lineWidth = 1;
context.strokeStyle = "black";
context.stroke();
Note that I used RequestAnimationFrame to update the stage. I tested RAF with EaselJS as well, with no change in how it animated.
Unless I'm missing something here, this is just persistence of vision, which is just how normal human vision works, especially with high contrast graphics on computer screens.
Try going outside on a dark night and waving a bright light back and forth, you will similarly see a subtle "trail" behind it.
An even better way to prove this, is to capture a screen shot while the animation is happening. Looking at the static frame, you will see that it does not have the blur.
Related
I'm looking for a way to render graphics onto an HTML5 canvas using JavaScript, but I want to only render said graphics if they're inside a pre-defined mask.
I'm creating a GUI framework that can be used to easily and quickly create GUIs on an HTML5 canvas. I think that something that would be really nice to have is a way to render graphics inside an element, and make the element auto-crop the graphics so that they always stay inside of it. For example, I can make a rectangular element and animate a circular pulse inside of it, and as the circle extends past the outside of the element, those parts of he circle should just not render to keep it looking smooth and sharp. This is similar to what CSS does with overflow: hidden;
Now, I know that one option is to use a mask-like feature. For example, P5.js has mask(). However, this is very very slow. Masking a single element a single time using P5.js significantly reduces framerate, and I want to be doing this potentially hundreds of times per frame without frame drops. I know that CSS does this incredibly efficiently (from my own experience working with it), but I can't seem to think of any way to make it efficient on a canvas element.
I could do it pretty simply if it was just a rectangle, but I want to do this for any shape. For example, a circle, a star, a rectangle with rounded edges, or really any polygon at all.
How can this be done? I thought of potentially rendering to an off screen canvas (which is shrunken to the size of the element in question), then render the element onto that screen using one color (let's say the background color will be white, and the shape will be black), then rendering the image we want masked onto another off screen canvas that's the same width as our other OSC, then looping through one of their image data arrays and mapping one to the other based on whether said pixel is white or black on the mask canvas.
But........ I can't help but think that that's going to be incredibly slow for the computer to process. I assume that CSS somehow leverages the GPU to do this type of computation incredibly efficiently and that's why they get such an increase in performance. Is it possible for me to do the same or am I just dreaming?
Okay, so I have found two different means of doing this (huge thank you to #Kaiido). One method is to use ctx.clip() while one works with CanvasPattern.
This snippet shows both means in action:
<canvas id = "c" width = "400" height = "400"></canvas>
<canvas id = "c2" width = "400" height = "400"></canvas>
<script>
var canvas = document.getElementById("c");
var ctx = canvas.getContext("2d");
ctx.fillStyle = "yellow";
ctx.fillRect(0,0,400,400);
ctx.beginPath();
ctx.arc(200,200,100,0,6);
ctx.clip();
ctx.beginPath();// This clears our previous arc from the path so that it doesn't render in when we `fill()`
ctx.fillStyle = "rgb(255,0,0)";
for(var i = 0;i < 20;i++){
for(var j = 0;j < 40;j++){
ctx.rect(i * 20 + j % 2 * 10,j * 10,10,10);
}
}
ctx.fill();
</script>
<script>
var canvas2 = document.getElementById("c2");
var ctx2 = canvas2.getContext("2d");
ctx2.fillStyle = "orange";
ctx2.fillRect(0,0,400,400);
var osc = new OffscreenCanvas(400,400);
var oscctx = osc.getContext("2d");
oscctx.fillStyle = "rgb(255,0,0)";
for(var i = 0;i < 20;i++){
for(var j = 0;j < 40;j++){
oscctx.rect(i * 20 + j % 2 * 10,j * 10,10,10);
}
}
oscctx.fill();
var pattern = ctx2.createPattern(osc,"no-repeat");
ctx2.fillStyle = pattern;
ctx2.arc(200,200,100,0,6);
ctx2.fill();
</script>
Which one is more efficient and better to be run hundreds of times per frame?
Another edit:
I spent about an hour messing around with it on a sandbox website, and I made this small project:
https://www.khanacademy.org/computer-programming/-/6446241383661568
There I run each one every millisecond and see how quickly each one updates to see which appears more efficient. clip() is on top while CanvasPattern is on the bottom. They both appear to be incredibly fast to me, and I feel that no matter which I chose I will have almost exactly the same results. However, clip() does still appear to be a bit faster as far as I can tell.
See for yourself and let me know what you think!
I have drawn 2 images in canvas using javascript (lineTo, moveTo, rect etc.), and I want to manipulate these images in a rollover kinda way. I know I'm supposed to write functions like "onmouseover" and "onmouseaway", thing is I don't know how I can manipulate the two shapes I already have in the canvas given that I don't have their sources... I tried googling but it got a bit confusing.
alert: i'm beginner in JS
http://jsfiddle.net/aertop9416/J7Brj/embedded/result/
.js file
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
function drawTriangle(){
context.beginPath();
context.moveTo(225,275);
context.lineTo(25,25);
context.lineTo(0,275);
context.fill();
// context.fillStyle = 'rgb(200, 95, 124)';
};
function drawRect(){
context.fillRect(300,25,100,100);
// context.clearRect(245,245,60,60);
// context.strokeRect(250,250,50,50);
context.fillStyle = 'rgb(120, 195, 124)';
};
If you're not using a library such as EasleJS for interactivity (http://www.ajohnstone.com/test/hackday/CreateJS-EaselJS-b262a85/tutorials/Mouse%20Interaction/), It's going to be a bit tricky, since canvas uses immediate render mode you need to retain the state of your objects. Use the mouse interaction event listeners to trigger an animation loop (hopefully using requestAnimationFrame for performance see: http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/). I hope this gets you going in the right direction.
I'm trying to accomplish an effect similar to what you might see on the cartoon Chowder (example link) , where shapes serve as masking layers for a texture underneath that stays static. I've begun playing around with this idea by creating a render loop that clears the canvas, saves it's state, then draws a rectangular clipping region, followed by drawing the background texture that occupies the entire width and height of the canvas.
Here's the draw function:
function draw()
{
context.clearRect(0,0, 640, 480);
context.save();
x += velocityX;
y += velocityY;
context.rect(x, y, 40, 40);
context.clip();
context.drawImage(image, 0,0, 640, 480);
context.restore();
}
Basically it just runs at 60 frames per second, updating the position of the rectangle and clipping a background image inside the clipping region. (I know the code isn't structured perfectly, but I was just experimenting to see if this effect was even possible on the canvas).
http://jsfiddle.net/JERje/86/
The problem I seem to be having is that the clipping area from the previous iteration of the loop hangs around creating the weird effect that you see in the fiddle above. I've tried reordering everything in the draw() step of the loop, but the only thing that seems to work is the canvas.width = canvas.width trick for clearing the screen. I'd like to avoid this method of clearing the screen, since it doesn't seem to work in IE, and it also destroys the canvas state. clearRect() should work to clear the screen. What am I doing wrong?
You're using the same HTML5 Canvas paperback I am aren't you.
If you set up an adhoc canvas as I did on your jsfiddle like so:
var newCanvas = document.createElement('canvas');
newCanvas.getContext("2d").drawImage(image,0,0);
A function such as this would be able to hack a section out of that canvas:
context.putImageData(newCanvas.getContext("2d").getImageData(x,y,40,40),x,y);
Thus giving you the chowder effect. Good show man, good luck. Pst me if it doesn't work
EDIT: However this solution will ignore some context scaling transformations. Just be smart about how you handle scale on your own (and you really should be anyways if you want the true "chowder" effect)
So, feel pretty dumb about this, but apparently when you call rect() you also have to make sure to call closePath afterwards in order to close the clipping area. Glad I figured it out finally, now on to adding multiple layers!
Here's the working fiddle: http://jsfiddle.net/JERje/129/
Say I drew a rectangle on the canvas. Surely there is some sort of built in method to get the XY coordinates, and dimensions of that rectangle? But after some googling I came up with nothing. And just to clarify, I am not talking about the coordinates of the canvas element itself, but rather a shape/image that is drawn unto the canvas.
Any help is appreciated.
If you're talking about a 2D canvas drawing, then the drawing maps 1:1 with screen coordinates, so it is just location of <canvas> + location of the drawing.
To clarify, drawing on a <canvas> basically just changes the pixels of the canvas - after you draw to it, you can't reference the drawn object the same way you can reference an html element.
Canvas is 2D table (Array) of numbers (= pixels = colors). When drawing into canvas, you are just editing this table. When you draw into canvas (= change numbers in table), what should be the coordinates of your adjustment?
If you are drawing rectangles only and you can define the coordinates for your rectangle, you must know your coordinates inside a program, because you have just drawn it.
If you want your image to be separated into some "objects" (shapes), you should use SVG.
Basically, you should be using canvas as a means to output graphics to the screen and the rest of your logic goes straight into the JavaScript that powers your game/application. The best way to go about making something like this is to create objects and assign properties to them; in its simplest form that can look like this:
function Player(x, y)
{
this.x = x;
this.y = y;
}
var examplePlayerObject = new Player(20, 20);
By extending this object via prototyping you can create multiple copies of an object that has the exact same functions; such as draw. Drawing the player in this instance could just be a red square that is 20px*20px.
Player.prototype.draw = function()
{
context.clearRect(0, 0, canvas.width, canvas.height);
context.fillStyle = 'red';
context.fillRect(this.x, this.y, 20, 20);
}
Then, you should have an update step with some means of clearing what is on the screen and redrawing the parts which have changed.
function animationStep()
{
examplePlayerObject.x++;
examplePlayerObject.y++;
examplePlayerObject.draw();
}
This animation step should run each frame; look into requestAnimationFrame for smooth animation. Paul Irish has a good shim for older browsers. Add in requestAnimationFrame(animationStep) at the end of that function and you will have a red square moving slowly across the screen. Good luck!
I'm trying to make Pong using canvas with JavaScript.
It has been many years since I made any game, and therefore am quite the beginner.
I have a problem where I am trying to move the ball (just its x position, for now) and trying to remove its previous position. The code I am using worked for the paddle (up and down keys to move it).
But, it doesn't seem to want to work with the ball.
What am I doing wrong?
this.draw = function() {
ctx.clearRect(this.prevX - this.radius, this.prevY - this.radius, this.radius * 2, this.radius * 2);
ctx.fillStyle = this.color;
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, true);
ctx.fill();
this.prevX = this.x;
this.prevY = this.y;
}
jsFiddle.
I know I am using clearRect(), but I was under the impression it just removes a rectangular portion of the canvas.
clearRect(x,y,width,height) : Clears the specified area and makes it fully transparent
Source.
Feel free to give me any other tips too, as I'm pretty much a beginner with this.
It's actually because you are not calling beginPath, so every new circle you draw also redraws all of the old circles!
Fix here with illustration:
http://jsfiddle.net/UvGVb/15/
Take out the call to beginPath to see what was happening before.
I am no expert on canvas, so I will go with the "other tips too" plead. :-) If you step away from canvas and instead use html elements like div to draw your paddles and ball, you won't have to bother with removing, only moving. Then there are lots of libraries to help you with element positioning, animation etc, of which jQuery would be my first choice.
You might be giving incorrect coordinates to the 'clearrect' function when you render the new position of the ball. Some of your references to 'this' look like they might be dodgy too:
var that = this;
The above is inside a function - I think it is referencing 'this' in the local scope of the function rather than the scope of the ball (which is I assume what you intend). You can set up a reference to this (ball scope) and use that from inside inner functions if you need to.
Try printing out the coordinates of the ball, and the coordinates of its previous position. You can then work out whether or not you are clearing the right area of the canvas. I'd also check your use of the this keyword and make sure it's in the right scope for what you want to do.
I have only had a quick look so I'm sorry if I've misunderstood what you're trying to do.