Why isn't my drawing showing on canvas? - javascript

I drew various shapes and text on my canvas, but nothing is showing in the browser. There are no errors in Chrome's console. I opened it in another browser, thinking it may have been a problem with cache, but still nothing except the "Draw Canvas" button shows. Here it is in jsfiddle: https://jsfiddle.net/0Lakv2do/
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css">
#content-wrapper {
width: 600px;
margin: 0 auto;
text-align: center;
}
#canvasRun {
background-color: #c00;
border: 0;
color: #fff;
}
</style>
</head>
<body>
<div id="content-wrapper">
<button id="canvasRun">Draw Canvas</button><br><br>
<canvas id="myCanvas" width="600" height="450"></canvas>
</div>
<script type="text/javascript">
var contentWrapper = document.getElementById('contentWrapper');
var runButton = document.getElementById('canvasRun');
var canvas = document.getElementById('myCanvas');
myCanvas.style.visibility="hidden";
runButton.addEventListener('click', showCanvas, false);
function showCanvas() {
myCanvas.style.visibility = "visible";
if (myCanvas.getContext){
var logo = new Image();
logo.src = 'IIT_SAT_stack_186_white.png';
function renderMyCanvas() {
var ctx = canvas.getContext('2d');
var linearGrad = ctx.createLinearGradient(0,0,0,450);
linearGrad.addColorStop(0, 'white');
linearGrad.addColorStop(1, 'black');
ctx.fillStyle=linearGrad;
ctx.fillRect(0,20,600,450);
ctx.font = "32px sans-serif";
ctx.fillStyle = 'red';
ctx.fillText("ITMD 565 Canvas Lab", 135, 75);
ctx.beginPath();
ctx.moveTo(15, 90);
ctx.lineTo(580, 90);
ctx.lineWidth = 3;
ctx.strokeStyle = 'red';
ctx.closePath();
ctx.stroke();
ctx.font = "14px sans-serif";
ctx.fillStyle = 'white';
ctx.fillText("", 15, 410);
ctx.fillText("", 15, 430);
ctx.drawImage(logo, 300, 360, 250, 60);
ctx.fillStyle= 'white';
ctx.fillRect(250, 250, 310, 100);
var x = canvas.width / 2;
var y = canvas.height / 2;
var radius = 75;
var startAngle = 1.1 * Math.PI;
var endAngle = 1.9 * Math.PI;
var counterClockwise = false;
ctx.beginPath();
ctx.arc(x, y, radius, startAngle, endAngle, counterClockwise);
ctx.lineWidth = 15;
ctx.arc.strokeStyle = 'yellow';
ctx.stroke();
ctx.setLineDash([10, 10]);
ctx.beginPath();
ctx.moveTo(270,300);
ctx.quadraticCurveTo(330, 220, 395, 300, 395, 300);
ctx.strokeStyle = 'black';
ctx.stroke();
ctx.beginPath();
ctx.moveTo(395, 300);
ctx.quadraticCurveTo(450, 375, 540, 300);
ctx.strokeStyle = 'black';
ctx.stroke();
}
}
}
</script>
</body>
</html>

You have just copy/pasted a function inside your other function and you don't ever call it. You also have a different variable canvas there while in the outer one you have myCanvas.
When copy/pasting make sure you actually know what you are copying and how it works.
See a Fiddle with the function definition removed and the variable name fixed.

Related

Making a analog clock by using html canvas

Below is my preliminary Javascript code for making a analog clock. My main problem is I don't know how to clear the "previous second lines" on the clock surface:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<script>
setInterval(timing, 1000);
var canvas1 = document.createElement("canvas");
canvas1.id = "canvas-1";
document.body.appendChild(canvas1);
canvas1.width = 500;
canvas1.height = 500;
canvas1.style.backgroundColor = "#3d3d3b";
var radius = (canvas1.height/2) * 0.9;
var ctx = canvas1.getContext("2d");
ctx.beginPath();
ctx.arc(250,250,radius,0,2*Math.PI);
ctx.fillStyle = "white";
ctx.fill();
ctx.beginPath();
ctx.arc(250, 250, radius * 0.1, 0, 2 * Math.PI);
ctx.fillStyle = '#333';
ctx.fill();
ctx.beginPath();
ctx.lineWidth = radius * 0.05;
ctx.stroke();
ctx.font = "40px Georgia"
ctx.textBaseline="middle";
ctx.textAlign="center";
for (i=1;i<13;i++){
ctx.fillText(i.toString(), 250+(Math.sin(i*Math.PI/6)*radius*0.8), 250-Math.cos(i*Math.PI/6)*radius*0.8);
}
function timing(){
const d = new Date();
ctx.beginPath();
ctx.moveTo(250,250);
ctx.lineWidth = radius*0.01;
ctx.lineTo(250+(Math.sin(d.getSeconds()*Math.PI/30)*radius*0.85), 250-Math.cos(d.getSeconds()*Math.PI/30)*radius*0.85);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(250,250);
ctx.lineWidth = radius*0.03;
ctx.lineTo(250+(Math.sin(d.getMinutes()*Math.PI/30)*radius*0.78), 250-Math.cos(d.getMinutes()*Math.PI/30)*radius*0.78);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(250,250);
ctx.lineWidth = radius*0.05;
ctx.lineTo(250+(Math.sin(d.getHours()*Math.PI/6)*radius*0.7), 250-Math.cos(d.getHours()*Math.PI/6)*radius*0.7);
ctx.stroke();
}
</script>
</body>
</html>
I have tried to use "ctx.globalCompositeOperation = "destination-over";", however not successful:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<script>
setInterval(timing, 1000);
var canvas1 = document.createElement("canvas");
canvas1.id = "canvas-1";
document.body.appendChild(canvas1);
canvas1.width = 500;
canvas1.height = 500;
canvas1.style.backgroundColor = "#3d3d3b";
var radius = (canvas1.height/2) * 0.9;
var ctx = canvas1.getContext("2d");
ctx.beginPath();
ctx.arc(250,250,radius,0,2*Math.PI);
ctx.fillStyle = "white";
ctx.fill();
ctx.beginPath();
ctx.arc(250, 250, radius * 0.1, 0, 2 * Math.PI);
ctx.fillStyle = '#333';
ctx.fill();
ctx.beginPath();
ctx.lineWidth = radius * 0.05;
ctx.stroke();
ctx.font = "40px Georgia"
ctx.textBaseline="middle";
ctx.textAlign="center";
for (i=1;i<13;i++){
ctx.fillText(i.toString(), 250+(Math.sin(i*Math.PI/6)*radius*0.8), 250-Math.cos(i*Math.PI/6)*radius*0.8);
}
function timing(){
const d = new Date();
ctx.beginPath();
ctx.arc(250,250,radius,0,2*Math.PI);
ctx.fillStyle = "white";
ctx.fill();
ctx.globalCompositeOperation = "destination-over";
ctx.beginPath();
ctx.moveTo(250,250);
ctx.lineTo(250+(Math.sin((d.getSeconds()-1)*Math.PI/30)*radius*0.85), 250-Math.cos((d.getSeconds()-1)*Math.PI/30)*radius*0.85);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(250,250);
ctx.lineWidth = radius*0.01;
ctx.lineTo(250+(Math.sin(d.getSeconds()*Math.PI/30)*radius*0.85), 250-Math.cos(d.getSeconds()*Math.PI/30)*radius*0.85);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(250,250);
ctx.lineWidth = radius*0.03;
ctx.lineTo(250+(Math.sin(d.getMinutes()*Math.PI/30)*radius*0.78), 250-Math.cos(d.getMinutes()*Math.PI/30)*radius*0.78);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(250,250);
ctx.lineWidth = radius*0.05;
ctx.lineTo(250+(Math.sin(d.getHours()*Math.PI/6)*radius*0.7), 250-Math.cos(d.getHours()*Math.PI/6)*radius*0.7);
ctx.stroke();
}
</script>
</body>
</html>
Could you tell me how to clear these "previous second lines" by using globalCompositeOperation if such function can really do in my case? Thanks.
The reason i believe it is possible to do it through globalCompositeOperation, is because i had tried some test as below:
<html>
<body>
<canvas id="myCanvas" width="300" height="150" style="border:1px solid #d3d3d3;">
</canvas>
<button onclick="myFunction()">Click me</button>
<script>
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.beginPath();
ctx.arc(50, 50, 50, 0, 2*Math.PI);
ctx.fillStyle = 'red';
ctx.fill();
ctx.beginPath();
ctx.moveTo(50,50);
ctx.lineTo(90,90);
ctx.stroke();
function myFunction() {
ctx.beginPath();
ctx.arc(50, 50, 50, 0, 2*Math.PI);
ctx.fillStyle = 'red';
ctx.fill();
ctx.globalCompositeOperation = "destination-over";
ctx.beginPath();
ctx.moveTo(50,50);
ctx.lineTo(90,90);
ctx.stroke();}
</script>
</body>
</html>
The globalCompositeOperation property cannot really be used for this purpose.
You can however do this:
Create a second canvas element that overlays the first (using position: absolute). It is transparent, so the other canvas will be seen through it.
After drawing the background on the original canvas, switch the context (ctx) to the second canvas, so that the timing function will only deal with the overlayed canvas
In the timing function, start by clearing that overlay canvas
setInterval(timing, 1000);
// Create second canvas that will overlay the first
var canvas2 = document.createElement("canvas");
canvas2.width = 500;
canvas2.height = 500;
canvas2.style.position = "absolute";
document.body.appendChild(canvas2);
var canvas1 = document.createElement("canvas");
canvas1.id = "canvas-1";
document.body.appendChild(canvas1);
canvas1.width = 500;
canvas1.height = 500;
canvas1.style.backgroundColor = "#3d3d3b";
var radius = (canvas1.height/2) * 0.9;
var ctx = canvas1.getContext("2d");
ctx.beginPath();
ctx.arc(250,250,radius,0,2*Math.PI);
ctx.fillStyle = "white";
ctx.fill();
ctx.beginPath();
ctx.arc(250, 250, radius * 0.1, 0, 2 * Math.PI);
ctx.fillStyle = '#333';
ctx.fill();
ctx.beginPath();
ctx.lineWidth = radius * 0.05;
ctx.stroke();
ctx.font = "40px Georgia"
ctx.textBaseline="middle";
ctx.textAlign="center";
for (i=1;i<13;i++){
ctx.fillText(i.toString(), 250+(Math.sin(i*Math.PI/6)*radius*0.8), 250-Math.cos(i*Math.PI/6)*radius*0.8);
}
// Switch the context to the overlayed canvas
ctx = canvas2.getContext("2d");
function timing(){
// Clear the second canvas (only)
ctx.clearRect(0, 0, 500, 500);
const d = new Date();
ctx.beginPath();
ctx.moveTo(250,250);
ctx.lineWidth = radius*0.01;
ctx.lineTo(250+(Math.sin(d.getSeconds()*Math.PI/30)*radius*0.85), 250-Math.cos(d.getSeconds()*Math.PI/30)*radius*0.85);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(250,250);
ctx.lineWidth = radius*0.03;
ctx.lineTo(250+(Math.sin(d.getMinutes()*Math.PI/30)*radius*0.78), 250-Math.cos(d.getMinutes()*Math.PI/30)*radius*0.78);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(250,250);
ctx.lineWidth = radius*0.05;
ctx.lineTo(250+(Math.sin(d.getHours()*Math.PI/6)*radius*0.7), 250-Math.cos(d.getHours()*Math.PI/6)*radius*0.7);
ctx.stroke();
}
You should probably be re-drawing the clockface for every new date that you render. I broke it down into individual pieces and used Promises but sure these were not strictly necessary.
(() => {
let cnvs;
let ctxt;
let radius;
const buildcanvas = () => new Promise((resolve, reject) => {
cnvs = document.createElement("canvas");
cnvs.id = "canvas-1";
cnvs.width = 500;
cnvs.height = 500;
cnvs.style.backgroundColor = "#3d3d3b";
document.body.appendChild(cnvs);
resolve(true)
});
const buildclockface = () => new Promise((resolve, reject) => {
radius = (cnvs.height / 2) * 0.9;
ctxt = cnvs.getContext("2d");
ctxt.beginPath();
ctxt.arc(250, 250, radius, 0, 2 * Math.PI);
ctxt.fillStyle = "white";
ctxt.fill();
ctxt.beginPath();
ctxt.arc(250, 250, radius * 0.1, 0, 2 * Math.PI);
ctxt.fillStyle = '#333';
ctxt.fill();
ctxt.beginPath();
ctxt.lineWidth = radius * 0.05;
ctxt.stroke();
ctxt.font = "40px Georgia"
ctxt.textBaseline = "middle";
ctxt.textAlign = "center";
for (i = 1; i < 13; i++) {
ctxt.fillText(
i.toString(),
250 + (Math.sin(i * Math.PI / 6) * radius * 0.8),
250 - (Math.cos(i * Math.PI / 6) * radius * 0.8)
);
}
resolve(true)
});
const showtime = (d) => new Promise((resolve, reject) => {
let d = new Date();
buildclockface();
secondhand(d);
minutehand(d);
hourhand(d);
});
const secondhand = (d) => {
ctxt.beginPath();
ctxt.moveTo(250, 250);
ctxt.lineWidth = radius * 0.01;
ctxt.lineTo(250 + (Math.sin(d.getSeconds() * Math.PI / 30) * radius * 0.85), 250 - Math.cos(d.getSeconds() * Math.PI / 30) * radius * 0.85);
ctxt.stroke();
}
const minutehand = (d) => {
ctxt.beginPath();
ctxt.moveTo(250, 250);
ctxt.lineWidth = radius * 0.03;
ctxt.lineTo(250 + (Math.sin(d.getMinutes() * Math.PI / 30) * radius * 0.78), 250 - Math.cos(d.getMinutes() * Math.PI / 30) * radius * 0.78);
ctxt.stroke();
}
const hourhand = (d) => {
ctxt.beginPath();
ctxt.moveTo(250, 250);
ctxt.lineWidth = radius * 0.05;
ctxt.lineTo(250 + (Math.sin(d.getHours() * Math.PI / 6) * radius * 0.7), 250 - Math.cos(d.getHours() * Math.PI / 6) * radius * 0.7);
ctxt.stroke();
}
buildcanvas()
.then(bool => setInterval(showtime, 1000))
.catch(err => alert(err))
})();
classic case of redraw the background here, nice little program though :)
setInterval(timing, 1000);
var canvas1 = document.createElement("canvas");
canvas1.id = "canvas-1";
document.body.appendChild(canvas1);
var radius = (canvas1.height/2) * 0.9;
var ctx = canvas1.getContext("2d");
function timing(){
canvas1.width = 500;
canvas1.height = 500;
canvas1.style.backgroundColor = "#3d3d3b";
ctx.beginPath();
ctx.arc(250,250,radius,0,2*Math.PI);
ctx.fillStyle = "white";
ctx.fill();
ctx.beginPath();
ctx.arc(250, 250, radius * 0.1, 0, 2 * Math.PI);
ctx.fillStyle = '#333';
ctx.fill();
ctx.beginPath();
ctx.lineWidth = radius * 0.05;
ctx.stroke();
ctx.font = "40px Georgia"
ctx.textBaseline="middle";
ctx.textAlign="center";
for (i=1;i<13;i++){
ctx.fillText(i.toString(), 250+(Math.sin(i*Math.PI/6)*radius*0.8), 250-Math.cos(i*Math.PI/6)*radius*0.8);
}
const d = new Date();
ctx.beginPath();
ctx.moveTo(250,250);
ctx.lineWidth = radius*0.01;
ctx.lineTo(250+(Math.sin(d.getSeconds()*Math.PI/30)*radius*0.85), 250-Math.cos(d.getSeconds()*Math.PI/30)*radius*0.85);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(250,250);
ctx.lineWidth = radius*0.03;
ctx.lineTo(250+(Math.sin(d.getMinutes()*Math.PI/30)*radius*0.78), 250-Math.cos(d.getMinutes()*Math.PI/30)*radius*0.78);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(250,250);
ctx.lineWidth = radius*0.05;
ctx.lineTo(250+(Math.sin(d.getHours()*Math.PI/6)*radius*0.7), 250-Math.cos(d.getHours()*Math.PI/6)*radius*0.7);
ctx.stroke();
}//timing
i just reread your post and you were asking about globalCompositeOperation
if you really dont want to redraw the background, and use globalCompositeOperation,
the globalCompositeOperation appears to operate only on filled areas, ie not lines
you would have to store your draw coordinates for each hand, redraw each hand at the old position - to remove it, then calculate new draw coordinates, draw and save
but check this out
var canvas = document.createElement("canvas");
document.body.appendChild(canvas);
canvas.width=500;
canvas.height=500;
var ctx = canvas.getContext("2d");
ctx.globalCompositeOperation = 'xor';
ctx.beginPath();
ctx.moveTo(50,50);
ctx.lineWidth = 1;
ctx.lineTo(250,250);
ctx.strokeStyle = '#ff0000'
ctx.stroke();
ctx.beginPath();
ctx.moveTo(50,250);
ctx.lineWidth = 1;
ctx.lineTo(250,50);
ctx.strokeStyle = '#ff0000'
ctx.stroke();
ctx.fillStyle='blue';
ctx.fillRect(20,20,60,60);
seems to show it wouldnt work for your clock hands
After some further research of the globalCompositeOperation, I find it is necessary to add another instruction to tell the program that the globalCompositeOperation restore to its previous state once the "previous second line" is cleared, therefore i further modified my program as below, and eventually it proof that using globalCompositeOperation can solve the problem. However, I had to admit that simply redraw the clock background each time should be better solution in this case.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Analog Clock-4 (using globalCompositeOperation)</title>
</head>
<body>
<script>
var canvas1 = document.createElement("canvas");
canvas1.id = "canvas-1";
document.body.appendChild(canvas1);
canvas1.width = 500;
canvas1.height = 500;
canvas1.style.backgroundColor = "#3d3d3b";
var radius = (canvas1.height/2) * 0.9;
var ctx = canvas1.getContext("2d");
setInterval(timing, 1000);
function timing(){
const d = new Date();
ctx.beginPath();
ctx.arc(250,250,radius,0,2*Math.PI);
ctx.fillStyle = "white";
ctx.fill();
ctx.beginPath();
ctx.arc(250, 250, radius * 0.1, 0, 2 * Math.PI);
ctx.fillStyle = '#333';
ctx.fill();
ctx.beginPath();
ctx.lineWidth = radius * 0.05;
ctx.stroke();
ctx.font = "40px Georgia"
ctx.textBaseline="middle";
ctx.textAlign="center";
for (i=1;i<13;i++){
ctx.fillText(i.toString(), 250+(Math.sin(i*Math.PI/6)*radius*0.8), 250-Math.cos(i*Math.PI/6)*radius*0.8);
}
ctx.globalCompositeOperation = "destination-over";
ctx.beginPath();
ctx.moveTo(250,250);
ctx.lineTo(250+(Math.sin((d.getSeconds()-1)*Math.PI/30)*radius*0.5), 250-Math.cos((d.getSeconds()-1)*Math.PI/30)*radius*0.5);
ctx.stroke();
ctx.globalCompositeOperation = "source-over";
ctx.beginPath();
ctx.moveTo(250,250);
ctx.lineWidth = radius*0.01;
ctx.lineTo(250+(Math.sin(d.getSeconds()*Math.PI/30)*radius*0.85), 250-Math.cos(d.getSeconds()*Math.PI/30)*radius*0.85);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(250,250);
ctx.lineWidth = radius*0.03;
ctx.lineTo(250+(Math.sin(d.getMinutes()*Math.PI/30)*radius*0.78), 250-Math.cos(d.getMinutes()*Math.PI/30)*radius*0.78);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(250,250);
ctx.lineWidth = radius*0.05;
ctx.lineTo(250+(Math.sin(d.getHours()*Math.PI/6)*radius*0.7), 250-Math.cos(d.getHours()*Math.PI/6)*radius*0.7);
ctx.stroke();
}
</script>
</body>
</html>

how can i create dynamic shapes in html?

I need to create a dynamic triangle, such that a user is able to grab either a vertex or side and move it. The angle should get updated in real-time. Unfortunately, I have no clue how one can do that. I started out by simply drawing the triangle using the following code.
<!DOCTYPE html>
<html>
<head>
<title>Triangle Canvas Example</title>
</head>
<body>
<canvas id="myCanvas" width="700" height="700"></canvas>
<script>
var canvasElement = document.querySelector("#myCanvas");
var context = canvasElement.getContext("2d");
context.beginPath();
context.strokeStyle = '#0000ff';
context.arc(400, 100, 8, 0, 2 * Math.PI, true);
context.stroke();
context.font = "15px Comic Sans MS";
context.fillStyle = "#0000ff";
context.textAlign = "center";
context.fillText("81", 390, 140);
context.beginPath();
context.arc(200, 300, 8, 0, 2 * Math.PI, true);
context.strokeStyle ='red';
context.stroke();
context.font = "15px Comic Sans MS";
context.fillStyle = "red";
context.textAlign = "center";
context.fillText("49", 230, 300);
context.beginPath();
context.arc(520, 400, 8, 0, 2 * Math.PI, true);
context.strokeStyle ='#008000';
context.stroke();
context.font = "15px Comic Sans MS";
context.fillStyle = "#008000";
context.textAlign = "center";
context.fillText("50", 500, 385);
// the triangle
context.beginPath();
context.moveTo(400, 100);
context.lineTo(200, 300);
context.lineTo(520, 400);
context.closePath();
// the outline
context.lineWidth = 2;
context.strokeStyle = '#666666';
context.stroke();
</script>
</body>
</html>
to get the following image. please see image
the problem is that my code is purely hardcoded, the angle value, the circle, and the triangle. My approach is probably wrong because I cannot see how one can turn all that into one dynamic image. I tried googling to see if someone created something similar but I was unable to find anything useful. Some insight on how to approach this problem would be great (a Youtube video or article would be greatly appreciated).
I created dynamic trinagle but i don't know math. Hope I help you.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Trinagle</title>
<style>
body {
margin: 0;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}
canvas {
border: 1px solid #000;
}
</style>
</head>
<body>
<canvas width="500" height="500"></canvas>
<script>
let mousePosition = [0, 0];
let mouseClicked = false;
let dragged = null;
const getMousePosition = (canvas, event) => {
const rect = canvas.getBoundingClientRect();
const x = Math.min(Math.max(event.clientX - rect.left, 0), canvas.width);
const y = Math.min(Math.max(event.clientY - rect.top, 0), canvas.width);
return [x, y];
}
document.addEventListener('DOMContentLoaded', () => {
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');
document.addEventListener('mousemove', (event) => {
mousePosition = getMousePosition(canvas, event);
});
document.addEventListener('mousedown', () => mouseClicked = true);
document.addEventListener('mouseup', () => mouseClicked = false);
const points = [
[50, 200, '#f00'],
[150, 50, '#0f0'],
[200, 150, '#00f'],
];
const radius = 10;
const draw = () => {
ctx.clearRect(0, 0, canvas.width, canvas.height);
const [mX, mY] = mousePosition;
for (const [index, [x, y, color]] of points.entries()) {
const hovered = (mX - x) ** 2 + (mY - y) ** 2 < radius ** 2;
const style = hovered ? 'fill' : 'stroke';
ctx.beginPath();
ctx.arc(x, y, radius, 0, Math.PI * 2, true); // Outer circle
ctx[`${style}Style`] = color;
ctx[style]();
if(hovered && mouseClicked) {
dragged = index;
}
if(dragged === index) {
points[index] = [...mousePosition, color];
if(!mouseClicked) dragged = null;
}
}
ctx.beginPath();
ctx.moveTo(points[0][0], points[0][1]);
ctx.lineTo(points[1][0], points[1][1]);
ctx.lineTo(points[2][0], points[2][1]);
ctx.lineTo(points[0][0], points[0][1]);
ctx.strokeStyle = '#000';
ctx.stroke();
window.requestAnimationFrame(draw);
}
window.requestAnimationFrame(draw);
});
</script>
</body>
</html>

How to change the color of the circle on canvas every n seconds?

How could the size of the shadow change, every n seconds? I guess you have to constantly create a new circle and eliminate the previous one? How would this be done? And also, is not there a more optimal way?
function main() {
var canvas = document.getElementsByTagName("CANVAS")[0],
ctx = canvas.getContext("2d");
canvas.width = window.innerWidth;
canvas.height = document.documentElement.scrollHeight;
var cW = canvas.width,
cH = canvas.height;
ctx.fillStyle = "#000";
ctx.fillRect(0, 0, cW, cH);
ctx.fill();
ctx.beginPath();
ctx.fillStyle = "#FFF";
ctx.shadowBlur = 5;
ctx.shadowColor = "#FFF";
ctx.arc(cW/2, cH/2, 50, 0, 2 * Math.PI, false);
ctx.fill();
ctx.closePath();
}
window.addEventListener("load", main);
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<canvas></canvas>
</body>
</html>
Create a setInterval & an array of colors. Use Math.random to randomly select any color.
Modify the main function to accept colors as two parameters.
function main(bckColor, circleColor) {
var canvas = document.getElementsByTagName("CANVAS")[0],
ctx = canvas.getContext("2d");
if (canvas.height) {
canvas.height = 0;
}
canvas.width = window.innerWidth;
canvas.height = document.documentElement.scrollHeight;
var cW = canvas.width,
cH = canvas.height;
ctx.fillStyle = bckColor || "#000";
//ctx.fillStyle = "red" ;
ctx.fillRect(0, 0, cW, cH);
ctx.fill();
ctx.beginPath();
ctx.fillStyle = circleColor || "#FFF";
ctx.shadowBlur = 5;
ctx.shadowColor = "#FFF";
ctx.arc(cW / 2, cH / 2, 50, 0, 2 * Math.PI, false);
ctx.fill();
ctx.closePath();
}
var colorArray = ['red', 'green', 'yellow', 'blue', 'pink', 'brown', 'orange']
var changeColor = setInterval(function() {
let bckColor = colorArray[Math.floor(Math.random() * 7 + 1)];
let circleColor = colorArray[Math.floor(Math.random() * 7 + 1)];
main(bckColor, circleColor)
}, 2000)
window.addEventListener("load", main);
<canvas></canvas>
instead of animating the canvas itself with a redraw every x seconds, i would suggest using an overlay , create a circle div, position it over the canvas' circle and animate its shadow using css, you'll have all the controls you want like the shadow's color and distance, animation speed ..etc.
here's a fiddle ( the overlay is better positionned )
function main() {
var canvas = document.getElementsByTagName("CANVAS")[0],
ctx = canvas.getContext("2d");
canvas.width = window.innerWidth;
canvas.height = document.documentElement.scrollHeight;
var cW = canvas.width,
cH = canvas.height;
ctx.fillStyle = "#000";
ctx.fillRect(0, 0, cW, cH);
ctx.fill();
ctx.beginPath();
ctx.fillStyle = "#FFF";
ctx.shadowBlur = 5;
ctx.shadowColor = "#FFF";
ctx.arc(cW / 2, cH / 2, 50, 0, 2 * Math.PI, false);
ctx.fill();
ctx.closePath();
// position the overlay over the circle
overlay.style.top = (cH / 2 - 99) + 'px'
overlay.style.left = (cW / 2 - 50) + 'px'
}
window.addEventListener("load", main);
main()
const animationDuration = 2;
function getRandomColor() {
var letters = '0123456789ABCDEF';
var color = '#';
for (var i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
}
overlay.style.animationDuration = animationDuration + 's';
setInterval(function() {
overlay.style.color = getRandomColor()
}, animationDuration * 1000)
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
canvas {
width: 100vw;
height: 100vh;
display: block;
}
#overlay {
border-radius: 50%;
background: none;
animation: shadow linear infinite;
margin: auto;
transform: translate(0, 50%);
color: green;
position: absolute;
z-index: 99;
width: 100px;
height: 93px;
}
#keyframes shadow {
0% 100% {
box-shadow: 0 0 0
}
50% {
box-shadow: 0 0 50px 20px
}
}
<canvas></canvas>
<div id="overlay">
</div>

Moving and rotating with HTML5

What needs to be done:
The pink object should move from the left to the right (by itself). And then when it's 5px from the edge it should rotate 90 degrees.
Does anyone know how to do this?
I haven't been learning javascript for a long time, and it's the first time I'm creating something using HTML5. So it's all new. I really hope you can help me understand the code better and how I can make it move and rotate.
<!DOCTYPE html>
<html>
<head>
<script>
var canvas, ctx;
window.onload = function draw() {
canvas = document.getElementById("myCanvas");
ctx = canvas.getContext("2d");
var height = 90;
var width = 40;
var radius = width / 2;
ctx.clearRect(0,0, canvas.width, canvas.height);
ctx.fillStyle = "#FFE2E8";
ctx.strokeStyle = "black";
ctx.beginPath();
ctx.moveTo(20,20);
ctx.lineTo(70,20);
ctx.arc(70,40,20, -Math.PI/2, Math.PI/2);
ctx.lineTo(20,60);
ctx.lineTo(20,20);
ctx.closePath;
ctx.fill();
ctx.stroke();
requestAnimationFrame(draw);
}
function init() {
canvas = document.getElementById("myCanvas");
ctx = canvas.getContext("2d");
draw();
}
</script>
</head>
<body>
<canvas id="myCanvas" width="400" height="300" style="background:#00CC66">
</canvas>
</body>
</html>
var canvas, ctx;
canvas = document.getElementById("myCanvas");
ctx = canvas.getContext("2d");
var radius = 20;
var width = 70;
var margin = 5;
var offsetx = -20
var translate = {
x: 0,
y: 0,
xmax: canvas.width - margin - width + offsetx,
ymax: canvas.height - margin - width
};
var rotate = 0;
var to_radians = Math.PI / 180;
function draw() {
ctx.save();
ctx.translate(translate.x, translate.y);
if (translate.x >= translate.xmax) {
translate.x = translate.xmax;
if (rotate >= 90) {
rotate = 90;
} else {
rotate++;
}
ctx.rotate(rotate * to_radians);
} else {
translate.x++;
}
var height = 90;
var width = 40;
var radius = width / 2;
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = "#FFE2E8";
ctx.strokeStyle = "black";
ctx.beginPath();
ctx.moveTo(20, 20);
ctx.lineTo(70, 20);
ctx.arc(70, 40, 20, -Math.PI / 2, Math.PI / 2);
ctx.lineTo(20, 60);
ctx.lineTo(20, 20);
ctx.closePath;
ctx.fill();
ctx.stroke();
ctx.restore();
requestAnimationFrame(draw);
}
function init() {
canvas = document.getElementById("myCanvas");
ctx = canvas.getContext("2d");
draw();
}
init();
<canvas id="myCanvas" width="400" height="300" style="background:#00CC66">
</canvas>

Trying to fill in two different colors in canvas fill()

I'm trying to draw a house using Canvas and Javascript. If you look at my drawHouse() method, I want to color the roof red, and everything else white. But only the white is filling in to color everything.
Jsfiddle link
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>My Site's Title</title>
</head>
<body>
<canvas id="myDrawing" width="300" height="300" style="border:1px solid #EEE">
</canvas>
<script>
var canvas = document.getElementById("myDrawing");
var ctx = canvas.getContext("2d");
//draws a house
function drawImage() {
drawSky();
drawGrass();
drawHouse();
}
//sets the dimensions of the canvas
var x = canvas.width / 2;
var y = 400;
var radius = 200;
var startAngle = 0;
var endAngle = 22 * Math.PI;
//draws the sky
function drawSky() {
var context = canvas.getContext('2d');
context.beginPath();
context.rect(0, 0, 300, 300);
context.fillStyle = '#0099FF';
context.fill();
context.lineWidth = 1;
context.strokeStyle = 'black';
context.stroke();
}
//draws green grass
function drawGrass() {
ctx.beginPath();
ctx.arc(x, y, radius, startAngle, endAngle);
ctx.stroke();
ctx.fillStyle = "#009900";
ctx.fill();
}
function drawHouse() {
var c = document.getElementById('myDrawing');
var ctx = c.getContext('2d');
ctx.beginPath();
ctx.moveTo(95, 165);
ctx.lineTo(140, 215);
ctx.lineTo(260, 215);
ctx.lineTo(240, 165);
ctx.lineTo(95, 165);
ctx.closePath();
ctx.fillStyle = "#C81E1E";
ctx.fill();
ctx.moveTo(139, 215);
ctx.lineTo(94, 165);
ctx.lineTo(45, 215)
ctx.closePath();
ctx.fillStyle = "white";
ctx.fill();
ctx.moveTo(48, 212);
ctx.lineTo(48, 275);
ctx.lineTo(139, 275);
ctx.lineTo(139, 215);
ctx.lineTo(45, 215);
ctx.closePath();
ctx.fillStyle = "white";
ctx.fill();
ctx.stroke();
ctx.moveTo(139, 275);
ctx.lineTo(260, 267);
ctx.lineTo(260, 215);
ctx.lineTo(140, 215);
ctx.closePath();
ctx.fillStyle = "white";
ctx.fill();
ctx.stroke();
}
drawImage();
</script>
</body>
</html>
You are missing a call to ctx.beginPath in your drawHouse funciton. The fillStyle is per path, so will need to have multiple paths.
Here is the fiddle: http://jsfiddle.net/sVDSs/6/
var canvas = document.getElementById("myDrawing");
var ctx = canvas.getContext("2d");
//draws a house
function drawImage() {
drawSky();
drawGrass();
drawHouse();
}
//sets the dimensions of the canvas
var x = canvas.width / 2;
var y = 400;
var radius = 200;
var startAngle = 0;
var endAngle = 22 * Math.PI;
//draws the sky
function drawSky() {
var context = canvas.getContext('2d');
context.beginPath();
context.rect(0, 0, 300, 300);
context.fillStyle = '#0099FF';
context.fill();
context.lineWidth = 1;
context.strokeStyle = 'black';
context.stroke();
}
//draws green grass
function drawGrass() {
ctx.beginPath();
ctx.arc(x, y, radius, startAngle, endAngle);
ctx.stroke();
ctx.fillStyle = "#009900";
ctx.fill();
}
function drawHouse() {
var c = document.getElementById('myDrawing');
var ctx = c.getContext('2d');
ctx.beginPath();
ctx.moveTo(95, 165);
ctx.lineTo(140, 215);
ctx.lineTo(260, 215);
ctx.lineTo(240, 165);
ctx.lineTo(95, 165);
ctx.fillStyle = "red";
ctx.closePath();
ctx.fill();
ctx.beginPath(); // THIS IS THE LINE
ctx.moveTo(139, 215);
ctx.lineTo(94, 165);
ctx.lineTo(45, 215)
ctx.closePath();
ctx.fillStyle = "white";
ctx.fill();
ctx.moveTo(48, 212);
ctx.lineTo(48, 275);
ctx.lineTo(139, 275);
ctx.lineTo(139, 215);
ctx.lineTo(45, 215);
ctx.closePath();
ctx.fillStyle = "white";
ctx.fill();
ctx.stroke();
ctx.moveTo(139, 275);
ctx.lineTo(260, 267);
ctx.lineTo(260, 215);
ctx.lineTo(140, 215);
ctx.closePath();
ctx.fillStyle = "white";
ctx.fill();
ctx.stroke();
}
drawImage();

Categories

Resources