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);
Related
I'm trying to re-create a game inspired by the minigame in New Super Mario Bros. called "Wanted!". Here's the situation:
I'm trying to have a countdown timer of 10 seconds, using JavaScript. When the timer counts down, I want the timer to refresh every second that passes. But as you'll see in the picture below, the timer writes over itself. I'm trying to do this with pure JavaScript, but HTML will also work if it is a preferred method. Keep in mind that this is a still frame. Here's what I have:
function drawTimer() {
var timeLeft = 10; // Set seconds
let countDown = setInterval(function() {
// Check if we reached 0.
if (timeLeft <= 0) {
alert("Time's up!");
isWinner = false;
document.location.reload(); // reload the page
clearInterval(countDown);
}
else { // Less than 10,
requestAnimationFrame(drawTimer);
ctx.beginPath();
ctx.font = "16px Arial";
ctx.fillStyle = "#FFFFFF";
ctx.strokeStyle = "#000000";
ctx.fillText("Time left: " + timeLeft, 200, 20);
ctx.closePath();
}
timeLeft -= 1;
}, 1000);
}
Here's what it looks like:
Not sure if you understand what canvas do. Its just a "canvas", as it says, and you draw pixels.
For example, if you draw something and you want to move it somewhere, you should draw new pixels on the place where that should be moved and erase previous pixels. Its like you are drawing a circle on a paper, and wanna draw it (move it) to another place (that would be another frame), you should erase current circle and draw a new one on another place.
In your case, for showing timer text you draw pixels, each drawn pixel will stay on canvas unless you erase it at some point. You should find a way to erase it, but easier would be to have an element in html that is above canvas (absolute position) and you will not have a problems with repainting.
I'm trying to create a platform game in Canvas. I have main character and some enemies. When player touch enemy, he will lose some HP and he will be untouchable for about 3s. Now I have one problem. After loosing HP, I want to set opacity of character image to 0.5 (to show that untouchable thing).
var mainchar = new Image();
mainchar.src = 'mainch.png';
I don't want to use ctx.globalCompositeOperation = "lighter" or ctx.globalAlpha = 0.5 becouse both of them change the opacity of all elements (it's global). Is there any way to change the image opacity? For example 'mainchar.changeopacity' ?
You have to either change globalAlpha or draw the image to an off-screen canvas that has globalAlpha set, then draw this canvas onto the main canvas.
Just set alpha, draw the image and reset alpha back to full opacity. Setting alpha does not change the content that is already drawn to the canvas - it only applies to the next thing drawn (which would be the image in this case).
And of course, you can always prep your image with an alpha-channel in case of PNG images.
/// only image will have alpha affected:
context.globalAlpha = 0.5;
context.drawImage(image, x, y);
context.globalAlpha = 1.0;
You can also use save and restore.
context.save();
context.globalAlpha = 0.5;
....
context.restore(); //this will restore canvas state
I am trying to create my first website using the p5.js library, with the end goal being an online digital portfolio. I am currently working on a splash screen, in which I have some large title text filling the center of the screen on a simple black background, which actively resizes to fill the window.
I would like to place a simple doodle in the background to add some interest. My challenge is that I would not like this doodle to draw on top of my text, but instead place it underneath my text. Initially I was thinking of infinitely redrawing the text so it stays at the top, however I have deduced there is no way to do this while still animating something beneath it.
My knowledge of HTML / CSS is minimal, however I was thinking of making the background of the title sketch transparent, a separate sketch with the doodle, and use the z index property in CSS to place the doodle beneath the title, is this even possible?
Thanks!
Further edits based on recommendations:
function preload() {
myFont = loadFont('assets/HighTide.otf');
}
function setup() {
canvas = createCanvas(window.innerWidth, window.innerHeight);
title = text("Welcome", width/2, height/2);
background(30);
fsize = window.innerHeight/4;
pg = createGraphics(window.innerWidth, window.innerHeight);
}
function draw() {
background(30);
pg.fill(random(0,255), random(0,255), random(0,255));
//pg.translate(width/2, height/2);
pg.ellipse(random(window.innerWidth), random(window.innerHeight), 60, 60)
image(pg, 0, 0);
textFont(myFont);
textSize(fsize);
textAlign(CENTER);
fill(255);
text("Welcome", width/2, height/2);
}
window.onresize = function() {
var w = window.innerWidth;
var h = window.innerHeight;
canvas.size(w,h);
fsize = window.innerHeight/4;
title.textSize(fsize);
width = w;
height = h;
}
It depends on exactly how you're drawing everything, but if you're doing this all in P5.js then you've already described exactly what you need to do.
Step 1: Each frame, clear out old frames by calling the background() function.
Step 2: Then draw your doodle.
Step 3: Finally, draw your text. Since you're drawing the text after the doodle, it shows up "on top" of the doodle.
This is how most P5.js sketches work: every frame, you clear out the old frames and then draw the next frame.
Edit: If you need a sketch that doesn't clear out old frames but still shows two different layers (your doodle and your text), then what you could do is draw your doodle to a buffer, then draw that buffer each frame, then draw the text on top of the buffer. Check out the createGraphics() function in the reference.
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.
I am creating a click and clear game. Once the user clicks some brick its adjacent bricks are checked for same color and all these bricks are bricks are cleared at once.
These are Cleared using clearRect() function.
Now this leaves a white patch right between the bricks above and bricks below leaving the above bricks hanging.
Now i want to bring these bricks above downward. How do i do this..?
Plz help
The question is quite vague, but based on the title, you'll need to clear your canvas before you can redraw. Otherwise, the drawn elements would simply stack on top of each other.
To do this, call the function clearRect on the canvas itself:
function clear() {
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.clearRect(0, 0, 500, 500);
}
Where canvas is the ID of your canvas, and 500, 500 the dimensions. Now you'll have an empty canvas where you can redraw everything again.
I once created a simple HTML5 canvas game as well, you might learn from the source code.
I think I understand what you're asking. If so then you're wanting to know how to move the blocks down when the blocks below have been removed.
This is just a matter of increasing the x position (remember the canvas starts at 0,0) with each iteration of your game loop.
How far to increase? Well that would be to where the highest "solid tower" is. I.E., say you have a column of 10 tokens and you remove the 7. The 3 below need all fall to the height of the remaining 6 - so that would be board height - (6*token height)
*
*
*
+ <- remove
* <- 6x token height (and less the board height)
*
*
*
*
*
I had success at redrawing the HTML Canvas by DOM.
var c = document.getElementsByName("myCanvas")[0];
if (c != null)
{
c.remove();
}
var c = document.createElement("canvas");
c.setAttribute("name", "myCanvas");
c.setAttribute("width", 900);
c.setAttribute("height", 600);
c.setAttribute("style", "border:1px solid #d3d3d3");