Canvas draws once with translate and once without error - javascript

I've taken nearly every possible countermeasure to prevent my program from drawing two dots instead of one on my chart. I want the dot in the middle to be shown, not the one in the top left. It seems to me the dot is being drawn once in the top left, matching the coordinates and everything, but then it draws a second dot with the translate method. Of course this is just speculation from what's happening on screen. The problem is occurring somewhere in the draw() function, init() function, or the anim() function - I can't pinpoint where the problem is.
let graph = document.getElementById('chart');
let c = graph.getContext('2d');
graph.height = 754;
graph.width = 754;
function algebra() {
xVertex = 2 * 10;
yVertex = 5 * 10;
let radius = 3;
let node = [];
function Node(xVertex, yVertex, radius) {
this.r = radius;
this.xV = xVertex;
this.yV = yVertex;
this.draw = function() {
c.beginPath();
c.arc(this.xV, this.yV, this.r, 0, Math.PI * 2, false);
c.fillStyle = "red";
c.fill();
c.translate(377, 377);
c.stroke();
c.closePath();
};
this.update = function() {
this.draw();
};
};
function init() {
node.push(new Node(xVertex, yVertex, radius));
anim();
};
function anim() {
requestAnimationFrame(anim);
for (let i = 0; i < node.length; i++) {
node[i].update(node);
};
c.clearRect(0, 0, graph.width, graph.height);
console.log(node);
};
init();
};
#graph {
left: 100px;
background-color: grey;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title> Proof of concept </title>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<div id="graph">
<canvas id="chart"></canvas>
<div id="y-axis"></div>
<div id="x-axis"></div>
</div>
<div id="button" onclick="algebra()">
<div id="btext">Calculate</div>
</div>
<script type="text/javascript" src="app.js"></script>
</body>
</html>

I think I found your errors:
1) When you call anim() it must first clear the canvas and then redraw all points.
2) Call the next animation frame after all points are drawn on the canvas
And the main problem:
3) You are doing a translate of the canvas origin on each point drawn (and a large one (377, 377)). Since the origin is changing at every iteration or point drawn also the canvas section that is being erased is moving. The two points you got were the first and second iterarions, the others were offscreen.
What you need to do is translate the canvas origin to its middle only once, just after:
let c = graph.getContext('2d');
graph.height = 754;
graph.width = 754;
//Translate the origin to the canvas' center (do this only once)
c.translate(graph.width/2, graph.height/2);
If the canvas origin has moved to the center, then you must also erase the canvas from -width/2 to width/2 and height/2 to height/2. To do this you must use:
c.clearRect(-graph.width/2, -graph.height/2, graph.width, graph.height);
Just for fun, I've added three more points to the node array and adding a random number between -1 and 1 to each coordinate in every iteration. This results in a Brownian like motion simulation.
let graph = document.getElementById('chart');
let c = graph.getContext('2d');
graph.height = 754;
graph.width = 754;
//Translate the origin to the canvas' center (do this only once)
c.translate(graph.width/2, graph.height/2);
function algebra() {
//Changed to 0 to plot at center
xVertex = 0;
yVertex = 0;
let radius = 3;
let node = [];
function Node(xVertex, yVertex, radius) {
this.r = radius;
this.xV = xVertex;
this.yV = yVertex;
this.draw = function() {
c.beginPath();
c.arc(this.xV, this.yV, this.r, 0, Math.PI * 2, false);
c.fillStyle = "red";
c.fill();
c.stroke();
c.closePath();
};
this.update = function() {
//this will generate random movement in x and y.
this.xV += Math.random()*2-1;
this.yV += Math.random()*2-1;
this.draw();
};
};
function init() {
node.push(new Node(xVertex, yVertex, radius));
node.push(new Node(xVertex, yVertex, radius));
node.push(new Node(xVertex, yVertex, radius));
node.push(new Node(xVertex, yVertex, radius));
anim();
};
function anim() {
//First clear the canvas then redraw
c.clearRect(-graph.width/2, -graph.height/2, graph.width, graph.height);
for (let i = 0; i < node.length; i++) {
node[i].update(node);
};
//After all are drawn, call the next Animation Frame
requestAnimationFrame(anim);
};
init();
};
#graph {
left: 100px;
background-color: grey;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title> Proof of concept </title>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<div id="graph">
<canvas id="chart"></canvas>
<div id="y-axis"></div>
<div id="x-axis"></div>
</div>
<div id="button" onclick="algebra()">
<div id="btext">Calculate</div>
</div>
<script type="text/javascript" src="app.js"></script>
</body>
</html>

Related

hi i want to build a little app game called "sink ships"?

hi im a newbie and im currently trying to build an app called sink ships.
I already drew the the circles with a css property and the tanks which look like this <------00000 are also moving with a with javascript I used for that the window.addEventlistener and giving each movement a property case going left right up down. Now I want the circle which symbolices the tanks to move down and up and up again and disappearing when I the bazooka touched the circle (tank) my code looking like this:
let circle = document.getElementById(".circle");
let moveBy = 10;
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var x = canvas.width / 2;
var y = canvas.height - 30;
var dx = 2;
var dy = -2;
window.addEventListener("load", () => {
circle.style.position = "absolute";
circle.style.left = 0;
circle.style.top = 0;
});
window.addEventListener("keyup", (e) => {
switch (e.key) {
case "ArrowLeft":
circle.style.left = parseInt(circle.style.left) - moveBy + "px";
break;
case "ArrowRight":
circle.style.left = parseInt(circle.style.left) + moveBy + "px";
break;
case "ArrowUp":
circle.style.top = parseInt(circle.style.top) - moveBy + "px";
break;
case "ArrowDown":
circle.style.top = parseInt(circle.style.top) + moveBy + "px";
break;
}
});
function drawBall() {
ctx.beginPath();
ctx.arc(x, y, 10, 0, Math.PI * 2);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawBall();
x += dx;
y += dy;
}
setInterval(draw, 10);
.circle {
height: 100px;
width: 100px;
border-radius: 50%;
background-color: rgb(0, 0, 0);
text-align-last: grid;
justify-content: center;
align-items: center;
ast: right;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
</head>
<body style="background-color: rgb(177, 133, 133)">
<canvas id="myCanvas"></canvas>
<div id=".circle"><------000</div>
<div class="circle"></div>
</body>
</html>
Now my question could someone help me with a code that could make my circle move up and down I already copied a code from the internet maybe it could help with the first steps
The question is a little vague to me. I interpret it to mean that you want the large black circle to move up and down, the ASCII art to move with the keyboard, and if the front of the ASCII art touches the big circle, the big circle disappears.
Traditionally, one would write a game for the browser using a canvas object. In your code you have some content that is trying to use a canvas, but since you do not declare a canvas or create a canvas element in javascript, the canvas code is throwing exceptions. My recommendation would be stop using html elements and move to a canvas. However, to keep the answer as close to the origin code as possible, I'll provide some code that uses the original HTML elements followed by a canvas implementation.
Element-base solution
If you want to build the game using just html elements, you would need to make the following changes to your script:
// var canvas = document.getElementById("myCanvas");
// var ctx = canvas.getContext("2d");
// var x = canvas.width/2;
// var y = canvas.height-30;
let x = 100;
let y = 100;
let ticks = 0;
var dx = 2;
var dy = 100;
let bigCircle = document.getElementsByClassName('circle')[0];
// ctx.beginPath();
function drawBall() {
// ctx.arc(x, y, 10, 0, Math.PI*2);
// ctx.fillStyle = "#0095DD";
// ctx.fill();
// ctx.closePath();
}
function styleStringToNumber(string) {
return +(string.substring(0, string.length - 2));
}
function draw() {
//ctx.clearRect(0, 0, canvas.width, canvas.height);
// drawBall();
ticks++;
animatedY = Math.cos(ticks / 100) * 100 + dy;
bigCircle.style.top = animatedY;
let circleBoundary = document.getElementById(".circle").getBoundingClientRect();
let tip = { x: circleBoundary.left, y: (circleBoundary.top + circleBoundary.bottom) / 2 }
let distance = Math.sqrt((styleStringToNumber(bigCircle.style.top) + 50 - tip.y) ** 2 + (styleStringToNumber(bigCircle.style.left) + 50 - tip.x) ** 2)
if (distance < 50)
bigCircle.style.visibility = "hidden"
}
setInterval(draw, 10);
You also have some ill-formatted code in you css. You can resolve the issues to removing the end of the last line so it only reads "align-items: center;" and by appending a final closing curly brace.
Description
Lines that have to do with a canvas have been commented out
We get a reference to the big circle by querying for a list of elements with the class circle and grabbing the first one in the list.
We add a function "styleStringToNumber" that will take the positional data from the big circle's style and convert it from a string with a trailing "px" to a number.
Move the big circle up and down with time. There are many ways to do this. I chose to use a simple trigonometric function since it eases in and out of it's vertical movement.
Get the boundary of the element referenced by circle
Use the Pythagorean theorem to find the distance from the center of the big circle and the left side of the 'circle' bounding box.
If the distance is less than the radius of the big circle, then change the visibility to hidden.
Using a Canvas
If you were to convert to using a canvas, you could reproduce this behavior this:
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<meta http-equiv='X-UA-Compatible' content='IE=edge'>
<title>Page Title</title>
<meta name='viewport' content='width=device-width, initial-scale=1'>
<style>
html,
body {
overflow: hidden
}
</style>
</head>
<body onkeyup='keyup(event)'>
<canvas id="canv" width=640 height=480></canvas>
<script>
let ctx = document.querySelector("#canv").getContext("2d")
let asciiPosition = { x: 0, y: 10 }
let circlePosition = { x: 0, y: 0 }
let ticks = 0;
let showBigCircle = true;
function main() {
//update and draw every 10ms
setInterval(update, 10)
}
//Change the state of the game
function update() {
ticks++
circlePosition.y = Math.cos(ticks / 100) * 100 + 100;
//Check if they are in collision
let distance = Math.sqrt((asciiPosition.x - (circlePosition.x + 50))**2 + (asciiPosition.y - (circlePosition.y + 50))**2)
if(distance < 50)
showBigCircle = false;
draw();
}
//Draw the game
function draw() {
ctx.fillStyle = "lightgreen";
ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
ctx.fillStyle = "black"
ctx.fillText("<------000", asciiPosition.x, asciiPosition.y)
if (showBigCircle) {
ctx.beginPath();
ctx.arc(circlePosition.x + 50, circlePosition.y + 50, 50, 0, Math.PI * 2);
ctx.fill();
}
}
//Respondto keyboard events
function keyup(e) {
let jump = 10;
switch (e.key) {
case 'ArrowLeft':
asciiPosition.x -= jump;
break;
case 'ArrowRight':
asciiPosition.x += jump;
break;
case 'ArrowUp':
asciiPosition.y -= jump;
break;
case 'ArrowDown':
asciiPosition.y += jump;
break;
}
}
//Start the game loop
main();
</script>
</body>
</html>

My Javascript code for a flappy bird game isn't displaying the character as it's meant to do

I am new to Javascript and I am trying to create flappy bird in normal Javascript. I was following a tutorial and when I got to this point my code wasn't working and wasn't displaying the character (a yellow square) as it is apparently meant to be doing according to the tutorial. I was hoping that someone would be able to help me with my issue, thanks a lot.
This is my HTML code here:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Flappy Bird</title>
<style>
canvas {
border: 3px solid #000000;
display: block;
margin: 0 auto;
background-color: lightblue;
}
</style>
</head>
<body>
<canvas id="canvas" width="320" height="480"></canvas>
<script src="game.js"></script>
</body>
</html>
This is my Javascript code here:
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
class Player {
constructor(x, y) {
this.x = x;
this.y = y;
this.w = 40;
this.h = 40;
this.ySpeed = 3;
}
show() {
ctx.fillStyle = "yellow";
ctx.fillRect(this.x, this.y, this.w, this.h);
}
update() {
this.y += this.ySpeed;
this.ySpeed += gravity;
}
}
var p;
var gravity = 0.1;
window.onload = function () {
start();
setInterval(update, 10);
};
function start() {
p = new Player(400, 400);
}
function update() {
canvas.width = canvas.width;
//player
p.show();
p.update();
}
The size of your canvas is only 320px, but you are trying to draw a square at a position of 400px.
Try:
p = new Player(0, 400)
It works
The player is being drawn offscreen: the x coordinate for player (as well as the y coordinate) is 400, while the canvas is only 320 wide. I'd recommend you check the line p = new Player(400, 400) to ensure the numbers are correct.

get area of a polygon

I'm trying to get the area of a polygone draw onclick in a canvas element
In the image above I try to get the area inside the red point which has a some opacity.
Is there anyway to do that "on the fly" which mean for each polygon draw.
I've already seen earcut.js which allow triangulation but I don't really understand how to get area whith this
var canvas = $('canvas');
var context = canvas[0].getContext('2d');
var imageObj = new Image();
imageObj.onload = function() {
$(canvas).attr({
width : this.width,
height: this.height
});
context.drawImage(imageObj,0,0);
};
imageObj.src = 'https://www.html5canvastutorials.com/demos/assets/darth-vader.jpg';
var clicks = [];
function drawPolygon(){
context.fillStyle = 'rgba(100,100,100,0.5)';
context.strokeStyle = "#df4b26";
context.lineWidth = 1;
context.beginPath();
context.moveTo(clicks[0].x, clicks[0].y);
for(var i=1; i < clicks.length; i++) {
context.lineTo(clicks[i].x,clicks[i].y);
}
context.closePath();
context.fill();
context.stroke();
};
function drawPoints(){
context.strokeStyle = "#df4b26";
context.lineJoin = "round";
context.lineWidth = 5;
for(var i=0; i < clicks.length; i++){
context.beginPath();
context.arc(clicks[i].x, clicks[i].y, 3, 0, 2 * Math.PI, false);
context.fillStyle = '#ffffff';
context.fill();
context.lineWidth = 5;
context.stroke();
}
};
function redraw(){
canvas.width = canvas.width; // Clears the canvas
context.drawImage(imageObj,0,0);
drawPolygon();
drawPoints();
};
canvas
.mouseup(function (e) {
clicks.push({
x: e.offsetX,
y: e.offsetY
});
redraw();
});
<!DOCTYPE html>
<html lang="en" >
<head>
<meta charset="UTF-8">
<title>draw polygon with canvas</title>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<canvas width="600" height="400"></canvas>
<script src='http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js'></script>
<script src="js/index.js"></script>
</body>
</html>
There is very simple algorithm to calculate area of polygon with given vertex coordinates: Shoelace formula
A = 1/2* Sum((x[i+1] + x[i]) * ([y[i+1] - y[i]))
(note indexes wrap in circular manner, so x[n]=x[0])
that might be implemented in a single loop.

Bouncing Ball doesn't appear on page

I would like to point out that I'm a beginner at this. So please, I hope you don't mind me asking questions to your solutions.
What I'm trying to construct here is a graphical animation of a ball falling to the ground from a height and then slowly, after several subsequent bounces, the ball just rolls on the base of the canvas.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>JavaScript examples</title>
<!-- As a shortcut, I included style information here rather than a separate file -->
<style>
canvas {
border: 1px solid gray;
}
</style>
<!-- incorporate jQuery -->
<script src="http://code.jquery.com/jquery-1.10.2.min.js"></script>
<!-- now my written script -->
<script>
$(function(){
// initialise canvas and context
var canvas = document.getElementById('canvas');
// physical variables
var g = 0.1; // gravity
var fac = 0.8; // velocity reduction factor per bounce
var radius = 20; // ball radius
var color = "#0000ff"; // ball color
var intervalId
function initBall() {
// initialise position and velocity of ball
var x = 50;
var y = 50;
var horizontalvelocity = 2;
var verticalvelocity = 0;
}
function drawBall() {
with (context){
clearRect(0, 0, canvas.width, canvas.height); // clear canvas
fillStyle = color;
beginPath();
arc(x, y, radius, 0, 2*Math.PI, true);
closePath();
fill();
};
};
function render() {
// update velocity
verticalvelocity += g; // gravity
// update position
x += horizontalvelocity;
y += verticalvelocity;
// handle bouncing
if (y > canvas.height - radius){
y = canvas.height - radius;
verticalvelocity *= -fac;
}
// wrap around
if (x > canvas.width + radius){
x = -radius;
}
// update the ball
drawBall();
};
function init() {
<!-- get the rendering area for the canvas -->
context = $('#canvas')[0].getContext("2d");
WIDTH = $('#canvas').width();
HEIGHT = $('#canvas').height();
setInterval(update, 1000/60); // 60 frames per second
initBall();
<!-- start animation -->
intervalId = setInterval(render, 10);
}
$(document).ready(init);
</script>
</head>
<body>
<canvas id="canvas" width="700" height="500"></canvas>
</body>
</html>
I can't seem to detect the errors I made. Your ideas and solutions would be greatly appreciated. :)
Your issue relates to a scope issue : you are using x,y variables through all your code, so they should be global variables. But your issues are 1) is that you didn't declare them as global variable and 2) when you initialize x,y in initBall, you declare 2 local vars that are x,y, that will hide x,y global vars.
--> add with global scope :
var x,y ;
(by the way declare also
var horizontalvelocity = 2;
var verticalvelocity = 0;
)
--> remove the var declaration in
function initBall() {
// initialise position and velocity of ball
x = 50;
y = 50;
horizontalvelocity = 2;
verticalvelocity = 0;
}

update is not defined?

I'm trying to make a moving object on canvas, but each time the set interval goes off it gives me the error: "update is not defined" even though update's definition is right there before init. How do I get set interval to call update correctly?
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Test</title>
<meta name="description" content="An HTML5 Test">
<meta name="author" content="William Starkovich">
<link rel="stylesheet" href="css/styles.css?v=1.0">
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript">
$(document).ready(function(){
var angle = 0.0;
var increment = 0.1;
function incrementAngle(angle, increment){
angle += increment;
if(angle > Math.PI * 2)
angle -= (Math.PI * 2);
}
function update(angle, increment){
incrementAngle(angle, increment);
//get a reference to the canvas
var ctx = $('#canvas')[0].getContext("2d");
//draw a circle
ctx.strokeStyle = "#000000";
ctx.beginPath();
ctx.arc(20, 20, 15, angle, angle + Math.PI, true);
ctx.lineWidth = 5;
ctx.stroke();
ctx.closePath();
}
function init(angle, increment){
update(angle, increment)
setInterval("update(angle, increment)",1000);
}
init(angle, increment);
});
</script>
</head>
<body>
<canvas id="canvas" width="800px" height="100px">
<p>Your browser doesn't support canvas.</p>
</canvas>
</body>
</html>
You appear to be looking to use global variables, so why not go all the way?
http://jsfiddle.net/mblase75/8L62c/3/
var angle = 0.0;
var increment = 0.1;
function incrementAngle() {
angle += increment;
if (angle > Math.PI * 2) angle -= (Math.PI * 2);
}
function update() {
incrementAngle();
//get a reference to the canvas
var ctx = $('#canvas')[0].getContext("2d");
//draw a circle
ctx.strokeStyle = "#000000";
ctx.beginPath();
ctx.arc(20, 20, 15, angle, angle + Math.PI, true);
ctx.lineWidth = 5;
ctx.stroke();
ctx.closePath();
}
function init() {
update();
setInterval(update, 1000);
}
$(document).ready(function() {
init();
});
Don't use strings in eval because they are executed in global scope and your function is defined in the document.ready handler. Use an anonymous function if you want to provide arguments:
setInterval(function() { update(angle, increment); } ,1000);

Categories