I am trying to make a rectangle gradually change its colour (fade) from yellow to white using Javascript after a button is pressed. Sadly my code does not work. Could you help me figure out what is wrong with the code and how to fix it?
I have just begun studying Javascript. Sorry, if this question is stupid. Thank you in advance.
This is my code:
<!DOCTYPE html>
<html>
<body>
<canvas id="myCanvas" width="300" height="150" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.</canvas> // create canvas to work with
<button onclick="fade(ctx)">Change the colour!</button>
<script>
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d"); //set context
ctx.rect(20, 20, 150, 100); // draw a rectangle
ctx.stroke(); // with border
ctx.fillStyle="#FFFF00"; // fill with yellow
ctx.fillRect(20,20,150,100);
function fade(ctx) { // fade function responsible for changing colour
var dom = getElementById(ctx), level = 1; // new object based on rectangle object, initial iterator is set to 1
function step() { // inner step function
var h = level.toString(16);
dom.fillStyle = '#FFFF' + h + h; // construct a new colour using h variable
if (level < 15) {
level += 1;
setTimeout(step, 100); // do this after every 100 ms
}
}
setTimeout(step, 100);
}
</script>
</body>
</html>
You almost have it with your code though. You are passing the context into the function already so no need for the getElementById(ctx) bit. In fact that will give you an error so remove that line from your code. Instead directly set the fillStyle on the ctx variable like this:
ctx.fillStyle = '#FFFF' + h + h;
and you also need to redraw the rectangle, so add this line:
ctx.fillRect(20,20,150,100);
after you set the colour. And that will do it.
Related
I'm working on a HTML5 Canvas project and have some text drawn on the screen. Right now, it appears and just stay there, but what I need is for it to disappear after a few seconds so that every time it's called it's not just new text being drawn on top of the old text.
I tried clearRect() but that completely clears the entire rectangle and removes some of my background too, which I don't want.
Is there a way to do this?
I'm drawing the text with this basic function:
function drawText() {
ctx.font = "30px Arial";
ctx.fillText("Please wait...", 575, 130);
}
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
</style>
</head>
<body>
<button onclick="showTheText()">Click to show text</button>
<canvas id="myCanvas" width="578" height="200"></canvas>
<script>
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
function showTheText() {
var myText = {
text: 'Hello World',
x: 0,
y: 75,
fill: 1
};
drawText(myText, context);
// wait one second before starting animation
setTimeout(function() {
animate(myText, canvas, context);
}, 1000);
}
function drawText(myText, context) {
context.font="30px Arial";
context.fillStyle="rgb(0, 0, 0, " + myText.fill + ")";
context.fillText(myText.text, myText.x, myText.y);
}
function animate(myText, canvas, context) {
// clear
context.clearRect(0, 0, canvas.width, canvas.height);
// !!!!!!!! redraw your background !!!!!!!!
// then redraw your text with new opacity
myText.fill -= .1;
drawText(myText, context);
// request new frame
if (myText.fill > -.1) {
setTimeout(function() {
animate(myText, canvas, context);
}, 2000 / 60);
}
}
</script>
</body>
</html>
Hope this can help you. What it does it immediately draws the text (and the rest of your background, you didn't provide it), then sets up a recursive timeout that will clear the rect, redraw your background, decrement the amount of opacity to apply to the text's fill, and redraw the text as well. You can slow it down by changing the time of the last setTimeout.
I adapted it from this example: https://www.html5canvastutorials.com/advanced/html5-canvas-animation-stage/
you can create a simple function to delete ,
you will need some values. For example, font height. width of character ... etc ,
for example in this case , you can use the following function , With few modifications :
function removeText(x,y,txt_length,font_height,char_width,ctx) {
ctx.clearRect(x, y-font_height ,char_width*txt_length,font_height);
}
and this function for write your string :
function drawText(x,y,text,ctx) {
ctx.font = "30px Arial";
ctx.fillText(text,x,y);
}
The same parameters x and y are passed to the functions and txt_length = text.length;
Once you've drawn text to canvas, it's no longer text - it's just a bunch of pixels! Since those pixels overwrite what is already there, there's no way to delete just the text.
Generally what you can do is re-draw the entire scene without the text, if you want to get rid of it.
You could also try re-drawing the text in the same position using the background color, which would remove the text, but this only works if the text is on a solid background.
To achieve expected use below option of fillStyle in clearText function
Create another function clearText with fillStyle white color with same text and x , y coordinates
Call clearText function from the drawText
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
function drawText() {
clearText()
ctx.font = "30px Arial";
ctx.fillStyle = "black";
ctx.fillText("Please wait...", 575, 130);
}
function clearText() {
ctx.font = "30px Arial";
ctx.fillStyle = "white";
ctx.fillText("Please wait...", 575, 130);
}
<button onclick="drawText()">draw text</button><br>
<canvas id="myCanvas" width="800" height="800"
style="border:1px solid #d3d3d3;">
Your browser does not support the canvas element.
</canvas>
code sample - https://codepen.io/nagasai/pen/oqOXxz
I want to show a countdown timer using JavaScript. However when I insert the current value to be 31,41,51,99,61,81 and few other numbers I am unable to get the Arc based on the inserted current value. The Arc should display the current value. As the number gets reducing, closer to Zero, the Arc should keep moving towards completing the circle.
I tried using HTML5 Canvas, I almost close to getting the answer but it's throwing some error.
The fields should have Maximum Value input text field and Current Value text field and a button which on clicked should display the Current Value Arc inside Canvas Element. Please help
<!-- Click event function, works when button is clicked -->
function clickevent()
{
var max=document.getElementById("maxsec").value;
var curr=document.getElementById("currsec").value;
myFunction(max,curr);
}
//This is the
function myFunction(maxvalue,currentvalue) {
//alert(maxvalue + ' ' + currentvalue);
if (currentvalue<=maxvalue)
{
var x = (2*3.14*currentvalue/maxvalue);
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.clearRect(0, 0, c.width, c.height);
ctx.font="15px Georgia";
ctx.textAlign = "center";
ctx.fillText(currentvalue,c.width/2, c.height/2);
ctx.beginPath();
ctx.arc(75, 75, 50, x, 2 * Math.PI);
// ctx.lineWidth = 10;
// line color
ctx.strokeStyle = 'black';
ctx.stroke();
}
if (maxvalue==currentvalue)
{
ctx.clearRect(0, 0, c.width, c.height);
ctx.font="15px Georgia";
ctx.textAlign = "center";
ctx.fillText("Time Up",c.width/2, c.height/2);
ctx.textAlign="center";
}
}
<!DOCTYPE html>
<html>
<body>
<div>
Max Second: <input type="text" id="maxsec" value="300"><br/>
Current Second: <input type="text" id="currsec" value="150">
<button onclick="clickevent()">Click me</button>
<br/>
//This is the canvas section where the Arc or the curvature will be displayed.
<canvas id="myCanvas" width="150" height="150" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.</canvas>
</div>
</body>
</html>
You are passing the values as a string into the function instead of number, if you change the below lines of code, it works fine!
JS:
var max=parseInt(document.getElementById("maxsec").value);
var curr=parseInt(document.getElementById("currsec").value);
myFunction(max,curr);
JSFiddle Demo
Please use this attempt of making your timer using setTimeout() function as a reference and build your code!
JSFiddle Demo
I am learning JavaScript. And I have this task - to draw two rectangles, in one of them, I should move the cursor, and it should appear in the second rectangle. It is not that hard to track the cursor, bu I have no idea how to display it somewhere else. Do I need to create separate canvas? How to display cursor image?
I would be very grateful for any tips!
Here is a simple code that I have for now:
<html>
<body>
<canvas id="myCanvas" width="800" height="600" ></canvas>
<script>
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.rect(20, 20, 300, 200);
ctx.stroke();
ctx.rect(350, 20, 300, 200);
ctx.stroke();
var cursorX;
var cursorY;
document.onmousemove = function(e){
cursorX = e.pageX;
cursorY = e.pageY;
}
</script>
</body>
You should create an IMG with a cursor in it. Then, when you are moussing over one rectangle, use the img's (or containing DIV's) css to display it over the second rectangle correctly. It is similar to how you might display a tooltip
function (event) {
var x = event.pageX;
var y = event.pageY;
var mouseImg = document.getElementById('mouseImg');
if (mouseImg ) {
$(mouseImg ).css('left',(x + rectangleOffset.x) + 'px');
$(mouseImg ).css('top',y + rectangleOffset.y + 'px');
$(mouseImg ).show();
}
}
I'm trying to increase the radius of a circle drawn in canvas using JavaScript functions.
There were many topics with similar issues but couldn't find an answer that would fix this one, I've tried using built-in methods that were suggested like setInterval, setTimeout, window.requestAnimationFrame and clearing the canvas to redraw the circle with the updated variable.
So far the setInterval method displayed the update but kept the previous iterations in the canvas, the clear method doesn't work.
Here's the example :
//Define globals
var radiusIncrement = 5;
var ballRadius = 20;
//Helper functions
function increaseRadius() {
ballRadius += radiusIncrement;
}
function decreaseRadius() {
if (ballRadius > 0) {
ballRadius -= radiusIncrement;
}
}
//Draw handler
function draw() {
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext('2d');
ctx.beginPath();
ctx.arc(canvas.height/2,canvas.width/2,ballRadius,0,2*Math.PI);
ctx.stroke();
}
//Event handler
setInterval(function() {
draw();
ctx.clearRect(0,0,canvas.width,canvas.height);
}, 100);
<!--Create frame and assign callbacks to event handlers-->
<button type="button" onclick="increaseRadius()">Increase Radius</button>
<button type="button" onclick="decreaseRadius()">Decrease Radius</button>
<canvas id="myCanvas" width="400" height="400" style="border:1px solid #000000;"></canvas>
Rather than using setInterval, is there a way to streamline the code using and use an event handler to refresh the canvas on every onlick ?
Thanks for your help.
Cheers.
If I understand you correctly, you only want to redraw on the button click, i.e. on a radius change. You don't need any timing functions for this, you can call the draw function whenever a radius change happens:
//Define globals
var radiusIncrement = 5;
var ballRadius = 20;
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext('2d');
//initialize
draw();
//Helper functions
function increaseRadius() {
ballRadius += radiusIncrement;
draw();
}
function decreaseRadius() {
if (ballRadius > 0) {
ballRadius -= radiusIncrement;
draw();
}
}
//Draw handler
function draw() {
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.beginPath();
ctx.arc(canvas.height/2,canvas.width/2,ballRadius,0,2*Math.PI);
ctx.stroke();
}
As you can see I also extracted the variable definition for canvas and ctx out of the draw function, since you don't need to re-assign these on every draw call.
I want to draw some continuously growing lines in HTML5 and Javascript. Here is what I want to do:
A point located at the center of my screen will have 3 lines growing (120 degree to each other) to a certain length, say 50 pix, then each of this 3 vertex will become a new center and have another 3 lines.
(I couldnt post images due to low reputation I have, hopefully you know what I mean abt the image here...)
I already written the function to have a array of all the points I need as the centers, starting from the center of my screen. I am thinking to write a loop over this array to draw the lines. I DO NOT want to directly use the stroke so that the line just appears on the screen. I want to have something like the the lines are drawn bit by bit (bad english here, please excuse my english) until it reaches the pre-defined length. However my code dont work quite well here, it only displays all the center points and only the last center point has the movement to have the 3 lines to grow...
I need to know the correct way to do this... many thanks in advance!
(please ignore the variable time or startTime in my code... )
<script>
window.requestAnimFrame = (function(callback) {
return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame ||
function(callback) {
window.setTimeout(callback, 1000 / 60);
};
})();
var canvas = document.getElementById('myCanvas');
canvas.width= window.innerWidth;
canvas.height= window.innerHeight;
var context = canvas.getContext('2d');
var totalLength = 50;
var centreSet = new Array();
var counter = 0;
var centre = {
x: canvas.width / 2,
y: canvas.height / 2,
};
var myLine = {
length : 0,
color : 'grey',
lineWidth : 0.5,
};
function drawLine(centre, context, mylength) {
context.beginPath();
context.moveTo(centre.x, centre.y);
context.lineTo(centre.x, centre.y - mylength);
context.moveTo(centre.x, centre.y);
context.lineTo(centre.x - 0.866 * mylength, centre.y + mylength/2);
context.moveTo(centre.x, centre.y);
context.lineTo(centre.x + 0.866 * mylength, centre.y + mylength/2);
context.lineWidth = myLine.lineWidth;
context.strokeStyle = myLine.color;
context.closePath();
context.stroke();
}
function startAnimate(centre, canvas, context, startTime, mylength) {
// update
var time = (new Date()).getTime() - startTime;
var linearSpeed = 5;
// pixels / second
var newX = linearSpeed / 10;
if(mylength < totalLength) {
mylength = mylength + newX;
// clear
//context.clearRect(0, 0, canvas.width, canvas.height);
drawLine(centre, context, mylength);
// request new frame
requestAnimFrame(function() {
startAnimate(centre, canvas, context, startTime, mylength);
});
}
}
function animate(centre, canvas, context, startTime){
//create array to have all the center points
centreSet = getCentres();
for (var i = 0; i < centreSet.length; i++){
//pass the x and y values in a object for each center we have in the array
centre.x = str2x(centreSet[i]);
centre.y = str2y(centreSet[i]);
startAnimate(centre, canvas, context, startTime, 0);
}
}
setTimeout(function() {
var startTime = (new Date()).getTime();
animate(centre, canvas, context, startTime);
}, 1000);
I just edited your code, I added the following part:
var length = 0;
for(var i = 0; i < 380; i++){
window.setTimeout(function() {drawFrame(length);},16.67);
length = length + 0.25;
}
I expect the screen appears to draw the incremental lines bit by bit until it reaches the length I want. However, it seems like the whole incremental process is not shown and it only shows the finished drawing.
Can anyone tell me why?
Regarding your followup question about why your animation loop fails
By putting your setTimeout in a for-loop, each new setTimeout is cancelling the previous setTimeout.
So you’re just left with the very last setTimeout running to completion.
In an animation loop, you typically do 3 things during each "frame":
Change some data to reflect how the new frame is different from the previous frame.
Draw the frame.
Test if the animation is complete. If not, do another frame (go to #1).
The setTimeout function is used to do the last part of #3 (do another frame)
So setTimeout is really acting as your animation loop. --- Your for-loop is not needed.
This is how you would restructure your code to follow this pattern:
var length=0;
var maxLength=50;
function draw(){
// make the line .25 longer
length=length+.25;
// draw
drawFrame(length);
// test if the line is fully extended
// if not, call setTimeout again
// setTimeout(draw,100) will call this same draw() function in 100ms
if(length<maxLength){
setTimeout(draw,100);
}
}
[Edited: to include spawning of child objects after lines reach terminal distance]
In your code you were not spawning new center points when the lines reached their maximum extension.
I would suggest that each of your centre objects have at least this much information in order to spawn a new set of centre objects when their lines reach terminal length:
var newCentrePoint={
x:x,
y:y,
maxLength:newMaxLength,
growLength:growLength,
currentLength:0,
isActive:true
}
The x,y are the centerpoint’s coordinates.
maxLength is the maximum extension of the 3 lines before they are terminated.
growLength is the amount by which each line will grow in each new frame.
currentLength is the current length of the line.
isActive is a flag indicating if this point is growing lines (true) or if it’s terminated (false)
Then when each line reaches terminal length you can spawn a new set of lines like this:
// spawns 3 new centre points – default values are for testing
function spawn(point,newMaxLength,newColor,growLength,newLineWidth){
var max=newMaxLength||point.maxLength/2;
var color=newColor|| (colors[++colorIndex%(colors.length)]);
var grow=growLength||point.growLength/2;
var lw=newLineWidth||point.lineWidth-1;
// new center points are spawned at the termination points of the 3 current lines
newPoint((point.x),(point.y-point.maxLength),max,color,grow,lw);
newPoint((point.x-0.866*point.maxLength),(point.y+point.maxLength/2),max,color,grow,lw);
newPoint((point.x+0.866*point.maxLength),(point.y+point.maxLength/2),max,color,grow,lw);
}
// creates a new point object and puts in the centreSet array for processing
function newPoint(x,y,newMaxLength,newColor,growLength,newLineWidth){
var newPt={
x:x,
y:y,
maxLength:newMaxLength,
color:newColor,
lineWidth:newLineWidth,
growLength:growLength,
currentLength:0,
isActive:true
}
centreSet.push(newPt);
}
Here is code and a Fiddle: http://jsfiddle.net/m1erickson/Vc8Gf/
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; }
canvas{border:1px solid red;}
</style>
<script>
$(function(){
var canvas=document.getElementById("canvas");
var context = canvas.getContext('2d');
// colors
var colors=["red","blue","gold","purple","green"];
var colorIndex=0;
//
var centreSet=[]
var generations=1;
// seed point
newPoint(canvas.width/2,canvas.height/2,100,"red",15);
// start
draw();
//
function draw(){
//
context.clearRect(0,0,canvas.width,canvas.height);
//
for(var i=0;i<centreSet.length;i++){
//
var centre=centreSet[i];
//
if(centre.isActive){
//
centre.currentLength+=centre.growLength;
//
if(centre.currentLength>=centre.maxLength){
centre.isActive=false;
centre.currentLength=centre.maxLength;
spawn(centre);
}
}
//
drawLines(centre);
}
//
if(generations<120){
setTimeout(draw,500);
}else{
context.font="18pt Verdana";
context.fillText("Finished 120 generations",40,350);
}
}
function spawn(point,newMaxLength,newColor,growLength,newLineWidth){
var max=newMaxLength||point.maxLength/2;
var color=newColor|| (colors[++colorIndex%(colors.length)]);
var grow=growLength||point.growLength/2;
var lw=newLineWidth||point.lineWidth-1;
newPoint((point.x),(point.y-point.maxLength),max,color,grow,lw);
newPoint((point.x-0.866*point.maxLength),(point.y+point.maxLength/2),max,color,grow,lw);
newPoint((point.x+0.866*point.maxLength),(point.y+point.maxLength/2),max,color,grow,lw);
generations++;
}
function newPoint(x,y,newMaxLength,newColor,growLength,newLineWidth){
var newPt={
x:x,
y:y,
maxLength:newMaxLength,
color:newColor,
lineWidth:newLineWidth,
growLength:growLength,
currentLength:0,
isActive:true
}
centreSet.push(newPt);
}
function drawLines(centre) {
var length=centre.currentLength;
//
context.beginPath();
context.moveTo(centre.x, centre.y);
context.lineTo(centre.x, centre.y - length);
//
context.moveTo(centre.x, centre.y);
context.lineTo(centre.x - 0.866 * length, centre.y + length/2);
//
context.moveTo(centre.x, centre.y);
context.lineTo(centre.x + 0.866 * length, centre.y + length/2);
//
context.strokeStyle=centre.color;
context.lineWidth = centre.lineWidth;
context.stroke();
}
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvas" width=400 height=400></canvas>
</body>
</html>