I'm trying to make a game and I have the blocks spawning randomly in the grid in the one fixed row (for example row 5 [horizontally]). Every time I click the button I want the blocks to move from row 5 to row 4(vertically). And then I want the new random blocks to generate on row 5 and so on. How can I do this? Right now it only spawning the new blocks under the first row (on the row 6, then 7 and so on).
//Accessing canvas
var canvas = document.getElementById('grid');
var ctx = canvas.getContext('2d');
var w = ctx.canvas.width;
var h = ctx.canvas.height;
// Drawing grid
var drawingGrid = function() {
for (x = 0; x <= w; x += 60) {
for (y = 0; y <= h; y += 60) {
// Gray grid
ctx.globalCompositeOperation = 'destination-over';
ctx.strokeStyle = "#cccccc";
ctx.lineWidth = 1;
ctx.beginPath();
ctx.moveTo(x, 0);
ctx.lineTo(x, h);
ctx.moveTo(0, y);
ctx.lineTo(w, y);
if (x % 240 === 0) {
// Black X-axis grid |
ctx.globalCompositeOperation = "source-over";
if (x === 0 || x === 480) {
ctx.lineWidth = 5;
} else {
ctx.lineWidth = 1;
}
// Middle vertical line
if (x === 240) {
// 0-480
ctx.beginPath();
ctx.moveTo(x, 0);
ctx.lineTo(x, 480);
ctx.strokeStyle = "#222831";
ctx.stroke();
// 480-560
ctx.beginPath();
ctx.moveTo(x, 480);
ctx.lineTo(x, 540);
ctx.strokeStyle = "#cccccc";
ctx.globalCompositeOperation = 'destination-over';
} else {
ctx.beginPath();
ctx.moveTo(x, 0);
ctx.lineTo(x, h);
ctx.strokeStyle = "#222831";
}
} else if (y % 240 === 0 || y === 540) {
// Black Y-axis grid _
ctx.globalCompositeOperation = "source-over";
ctx.strokeStyle = "#222831";
if (y === 0 || y === 540) {
ctx.lineWidth = 5;
} else if (y === 480) {
ctx.lineWidth = 2.5;
} else {
ctx.lineWidth = 1;
}
ctx.beginPath();
ctx.moveTo(0, y);
ctx.lineTo(h, y);
}
ctx.stroke();
}
}
};
drawingGrid(480, 540, 'grid');
// Starting coordinates
var posX = 0;
var posY = 240;
// Move blocks on Y axis
function moveY(){
posY +=60;
}
// Spawn random amount of blocks on the field
function gener(){
posX = 60*Math.floor(8*Math.random());
}
function spawnRandomObject() {
// Game Object
ctx.fillStyle = '#f2a365';
ctx.globalCompositeOperation = "destination-over";
ctx.beginPath();
ctx.fillRect(posX, posY, 60, 60);
ctx.stroke();
}
// Blocks moving up
document.getElementById("button").addEventListener("click", function(){
// Spawn random amount of objects
for (var i=0; i<Math.floor((Math.random()*8)+1)*2; i++){
gener();
spawnRandomObject();
}
moveY();
});
body{
background-color: #ececec;
}
canvas{
padding-left: 0;
padding-right: 0;
margin-left: auto;
margin-right: auto;
display: block;
}
.row{
padding: 20px;
margin: 0;
}
.firstrow{
width:20%;
}
.mainrow{
width:60%;
display: block;
}
.thirdrow{
width: 20%;
}
.header{
background-color: #222831;
color: #ececec;
padding: 20px;
}
.container{
margin-top: 20px;
padding: 0px;
display: flex;
box-sizing: inherit;
}
.thirdrow{
text-align: right;
}
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>Shmetris</title>
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
<!-- Local CSS -->
<link rel="stylesheet" href="styles.css">
</head>
<body>
<!-- Header -->
<div class="header">
<h1>Shmetris</h1>
</div>
<div class="container">
<!-- Controls -->
<div class="row first">
<div class="col">
<h1>Score: 0</h1>
<br>
<button type="button" class="btn btn-dark" id="button">Refresh</button>
</div>
</div>
<!-- Game Area -->
<div class="row mainrow">
<div class="col-" id="gamearea">
<!-- Canvas -->
<canvas id="grid" width="480" height="540" style="background: #ececec "></canvas>
</div>
</div>
<!-- -->
<div class="row thirdrow">
<div class="col" style="text-align:left;">
</div>
</div>
</div>
<!-- Script -->
<script src="app.js"></script>
</body>
</html>
I removed your moveY() function and added the moveRow() function. The game objects (the rects) are saved to a list objects. Their y position is increased on each button click. The old drawn positions are removed, the new positions are drawn. Then the randomly generated blocks are added in the 5th row.
Note that the clearRect() function inside the removeCell() also removes parts of the grid. This causes to redraw the grid every time. You can improve the code by splitting your grid creation in using a sub function which draws the grid on only one cell. Then you can redraw the grid only on those cells that are needed. This probably is a performance boost and makes the code more beautiful in my eyes, but it works like this too.
I also suggest to use length instead of 60 and calculate the thicker grid lines by the length, e.g. 8 * length instead of 480 and so on.
//Accessing canvas
var canvas = document.getElementById('grid');
var ctx = canvas.getContext('2d');
var w = ctx.canvas.width;
var h = ctx.canvas.height;
// Drawing grid
var drawingGrid = function() {
for (x = 0; x <= w; x += 60) {
for (y = 0; y <= h; y += 60) {
// Gray grid
ctx.globalCompositeOperation = 'destination-over';
ctx.strokeStyle = "#cccccc";
ctx.lineWidth = 1;
ctx.beginPath();
ctx.moveTo(x, 0);
ctx.lineTo(x, h);
ctx.moveTo(0, y);
ctx.lineTo(w, y);
if (x % 240 === 0) {
// Black X-axis grid |
ctx.globalCompositeOperation = "source-over";
if (x === 0 || x === 480) {
ctx.lineWidth = 5;
} else {
ctx.lineWidth = 1;
}
// Middle vertical line
if (x === 240) {
// 0-480
ctx.beginPath();
ctx.moveTo(x, 0);
ctx.lineTo(x, 480);
ctx.strokeStyle = "#222831";
ctx.stroke();
// 480-560
ctx.beginPath();
ctx.moveTo(x, 480);
ctx.lineTo(x, 540);
ctx.strokeStyle = "#cccccc";
ctx.globalCompositeOperation = 'destination-over';
} else {
ctx.beginPath();
ctx.moveTo(x, 0);
ctx.lineTo(x, h);
ctx.strokeStyle = "#222831";
}
} else if (y % 240 === 0 || y === 540) {
// Black Y-axis grid _
ctx.globalCompositeOperation = "source-over";
ctx.strokeStyle = "#222831";
if (y === 0 || y === 540) {
ctx.lineWidth = 5;
} else if (y === 480) {
ctx.lineWidth = 2.5;
} else {
ctx.lineWidth = 1;
}
ctx.beginPath();
ctx.moveTo(0, y);
ctx.lineTo(h, y);
}
ctx.stroke();
}
}
};
drawingGrid(480, 540, 'grid');
var length = 60;
// Starting coordinates
var posX = 0;
var posY = 4 * length;
var objects = []
function moveRows(){
for(var i = 0; i < objects.length; i++){
// remove old objects
removeCell(objects[i][0], objects[i][1]);
// move objects
objects[i][1] += length;
}
drawingGrid();
for(var i = 0; i < objects.length; i++){
// redraw objects on new location
drawCell(objects[i][0], objects[i][1]);
}
}
// Spawn random amount of blocks on the field
function gener(){
posX = length*Math.floor(8*Math.random());
}
function spawnRandomObject() {
// Game Object
drawCell(posX, posY);
objects.push([posX, posY]);
}
function drawCell(x, y, color){
ctx.fillStyle = "#f2a365";
ctx.globalCompositeOperation = "destination-over";
ctx.beginPath();
ctx.fillRect(x, y, length, length);
ctx.stroke();
}
function removeCell(x, y){
ctx.clearRect(x, y, length, length);
}
// Blocks moving up
document.getElementById("button").addEventListener("click", function(){
// Spawn random amount of objects
moveRows();
for (var i=0; i<Math.floor((Math.random()*8)+1)*2; i++){
gener();
spawnRandomObject();
}
});
body{
background-color: #ececec;
}
canvas{
padding-left: 0;
padding-right: 0;
margin-left: auto;
margin-right: auto;
display: block;
}
.row{
padding: 20px;
margin: 0;
}
.firstrow{
width:20%;
}
.mainrow{
width:60%;
display: block;
}
.thirdrow{
width: 20%;
}
.header{
background-color: #222831;
color: #ececec;
padding: 20px;
}
.container{
margin-top: 20px;
padding: 0px;
display: flex;
box-sizing: inherit;
}
.thirdrow{
text-align: right;
}
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>Shmetris</title>
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
<!-- Local CSS -->
<link rel="stylesheet" href="styles.css">
</head>
<body>
<!-- Header -->
<div class="header">
<h1>Shmetris</h1>
</div>
<div class="container">
<!-- Controls -->
<div class="row first">
<div class="col">
<h1>Score: 0</h1>
<br>
<button type="button" class="btn btn-dark" id="button">Refresh</button>
</div>
</div>
<!-- Game Area -->
<div class="row mainrow">
<div class="col-" id="gamearea">
<!-- Canvas -->
<canvas id="grid" width="480" height="540" style="background: #ececec "></canvas>
</div>
</div>
<!-- -->
<div class="row thirdrow">
<div class="col" style="text-align:left;">
</div>
</div>
</div>
<!-- Script -->
<script src="app.js"></script>
</body>
</html>
Related
I'm trying to draw a canvas line diagonally on top 2 textboxes placed diagonally (like samsung's pattern passcode) on a button click, but am unable to do so.
I tried this, but without making the input position absolute (which overlaps some text boxes), I'm not finding a good solution.
<!DOCTYPE html>
<html>
<head>
<style>
* {
z-index: 0;
}
canvas {
z-index: 1;
position: absolute;
}
</style>
</head>
<body>
<div id="grid">
<script>
for(let i = 0; i < 2; i++){
for(let j = 0; j < 2; j++){
document.getElementById("grid").innerHTML += `<input type="text" id="cell-${i}-${j}" maxlength="1" value="${2*i+j}" pattern="[A-Za-z]"/>`;
}
document.getElementById("grid").innerHTML += "<br/>";
}
</script>
<button onclick="draw()" id="draw_btn">Draw Line</button>
</div>
<script>
function draw(){
const canvas = document.createElement("canvas");
canvas.width = 200;
canvas.height = 200;
const ctx = canvas.getContext("2d");
ctx.strokeStyle = "#ff0000";
ctx.lineWidth = 10;
ctx.beginPath();
ctx.moveTo(0,0);
ctx.lineTo(100,100);
ctx.stroke();
document.body.appendChild(canvas);
}
</script>
</body>
</html>
One approach is to make the canvas absolutely positioned, and place it over the top of the text boxes.
Absolutely positioned elements are positioned relative to their nearest absolutely or relatively positioned parent. If we pop position: relative on our #grid box, and place the canvas inside, then we can position it within the bounds of the grid itself, rather than the whole document.
for(let i = 0; i < 2; i++){
for(let j = 0; j < 2; j++){
document.getElementById("grid").innerHTML += `<input type="text" id="cell-${i}-${j}" maxlength="1" value="${2*i+j}" pattern="[A-Za-z]"/>`;
}
document.getElementById("grid").innerHTML += "<br/>";
}
function draw(){
const canvas = document.createElement("canvas");
canvas.width = 300;
canvas.height = 40;
const ctx = canvas.getContext("2d");
ctx.strokeStyle = "#ff0000";
ctx.lineWidth = 10;
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(300, 40);
ctx.stroke();
document.getElementById("grid").appendChild(canvas);
}
#grid {
position: relative;
}
#grid input {
width: 150px;
height: 20px;
box-sizing: border-box;
}
#grid canvas {
position: absolute;
left: 0;
top: 0;
pointer-events: none;
}
<div id="grid"></div>
<button onclick="draw()" id="draw_btn">Draw Line</button>
I'd also recommend adding
pointer-events: none;
to the canvas, as this means the user can still interact with the input boxes below.
I want make aimbooster. (http://www.aimbooster.com/)
I don't know how to make several circles that change in size at the same time.
My drawing process is...
Create a circle.
Draw a circle changing its size.
Reset the x- and y-coordinates when a circle is clicked.
Repeat this process.
The way I've tried to solve this problem is...
I tried to combine the draw function and the CircleForm function into a class and use a repeat statement.
I keep getting errors.
How do you make multiple circles?
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
// canvas maximum, minimum size
var max_x = 610,
min_x = 30,
min_y = 30,
max_y = 466;
// Initial Circle State
var x = 200,
y = 200,
r = 1,
startAngle = 0,
endAngle = Math.PI*2;
var moving;
var inc = true;
// -------------------------------------------------------------------
class Ball {
move(){
moving = setInterval(draw, 1);
}
stop(){
clearInterval(moving);
}
position(){
x = Math.floor(Math.random() * ((max_x) - (min_x))+min_x);
y = Math.floor(Math.random() * ((max_y) - (min_y))+min_y);
}
first_size(){
r = 1;
}
moving_size(){
var size_fast = 0.09; //0.09
if(inc){
r+=size_fast;
}else{
r-=size_fast;
}
}
}
let ball = new Ball();
// ---------------------------------------------------------------------------
function macroBall(){
ball.stop();
ball.position();
ball.first_size();
ball.move();
}
function CircleForm(x,y,r,startAngle, endAngle){
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
context.beginPath();
context.arc(x,y,r,startAngle, endAngle);
context.fillStyle = "orange";
context.fill();
context.stroke();
}
function draw(){
context.clearRect(0,0,canvas.width,canvas.height);
CircleForm(x,y,r,startAngle, endAngle);
rad_check(r);
ball.moving_size();
}
// Circle radius check
function rad_check(r){
if(r>=30){
inc = false;
}
if(r<=2){
inc = true;
}
}
canvas.addEventListener('mousedown', function(e) {
getCursorPosition(canvas, e)}
);
function getCursorPosition(canvas, event) {
const rect = canvas.getBoundingClientRect()
const xpos = event.clientX - rect.left
const ypos = event.clientY - rect.top
console.log("x: " + xpos + " y: " + ypos);
judgeHit(xpos,ypos);
}
// circle click event
function judgeHit(xpos, ypos,moving){
if(Math.abs(x-xpos)<=r && Math.abs(y-ypos)<=r){
macroBall();
}
}
ball.move();
*{
margin:0;
}
html, body{
height:100%;
}
body{
background:#376481 url(bg.jpg);
background-size: 100% 100%;
}
#page-container{
width:100%;
min-height:100%;
background:url(bg_stripes.png);
}
#column{
width: 640px;
margin-left: auto;
margin-right: auto;
display:grid;
}
#top{
height:80px;
}
.nav{
height:20px;
background-color:#CCCCCC;
}
.nav ul{
padding:0px;
margin-left:220px;
text-align: center;
}
.nav ul li{
font-size:10pt;
list-style:none;
float:left
}
.nav ul li a{
text-decoration:none;
color:#4477BB;
}
#myCanvas{
background-color:white;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Aim_Boost</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div id="page-container">
<div id="top"></div>
<div id="column">
<img src="header.png" style="width: 640px; height: 116px;" alt="AimBooster">
<div id="page">
<div class="nav">
<ul>
<li>Play</li>
<li> • News</li>
<li> • FAQ</li>
<li> • Feedback</li>
<li> • Donate</li>
</ul>
</div>
<div id="thi">
<canvas id="myCanvas" width="640px" height="497px"></canvas>
</div>
</div>
</div>
</div>
<script src="javas.js"></script>
</body>
</html>
You will need to add a constructor() method to the class to start. Read about it here developer.mozilla.org. Once you have that you can use the constructor to assign the objects properties.
Push all of the objects to any array and then iterate over them to animate. This a a very basic example showing how to create multiple circles. You can also create them without a loop.
let ball1 = new Ball();
let ball2 = new Ball();
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
let balls = [];
var inc = true;
class Ball {
constructor() {
this.x = Math.random() * canvas.width;
this.y = Math.random() * canvas.height;
this.r = 4;
this.c = "orange";
this.speed = 0.5;
}
draw() {
context.beginPath();
context.arc(this.x, this.y, this.r, 0, Math.PI * 2);
context.fillStyle = this.c;
context.fill();
context.stroke();
}
grow() {
if (inc) {
this.r += this.speed;
} else {
this.r -= this.speed;
}
}
incCheck() {
if (this.r >= 30) {
inc = false;
} else if (this.r < 2) {
inc = true;
}
}
}
function createBalls() {
for (let i = 0; i < 50; i++) {
balls.push(new Ball());
}
}
createBalls();
function drawBalls() {
for (let i = 0; i < balls.length; i++) {
balls[i].draw();
balls[i].grow();
balls[i].incCheck();
}
}
setInterval(() => {
context.clearRect(0, 0, canvas.width, canvas.height);
drawBalls()
}, 50)
*{
margin:0;
}
html, body{
height:100%;
}
body{
background:#376481 url(bg.jpg);
background-size: 100% 100%;
}
#page-container{
width:100%;
min-height:100%;
background:url(bg_stripes.png);
}
#column{
width: 640px;
margin-left: auto;
margin-right: auto;
display:grid;
}
#top{
height:80px;
}
.nav{
height:20px;
background-color:#CCCCCC;
}
.nav ul{
padding:0px;
margin-left:220px;
text-align: center;
}
.nav ul li{
font-size:10pt;
list-style:none;
float:left
}
.nav ul li a{
text-decoration:none;
color:#4477BB;
}
#myCanvas{
background-color:white;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Aim_Boost</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div id="page-container">
<div id="top"></div>
<div id="column">
<img src="header.png" style="width: 640px; height: 116px;" alt="AimBooster">
<div id="page">
<div class="nav">
<ul>
<li>Play</li>
<li> • News</li>
<li> • FAQ</li>
<li> • Feedback</li>
<li> • Donate</li>
</ul>
</div>
<div id="thi">
<canvas id="myCanvas" width="640px" height="497px"></canvas>
</div>
</div>
</div>
</div>
<script src="javas.js"></script>
</body>
</html>
I'm building a to-do list with a progress circle, using one of the alternatives given here (CSS Progress Circle). In my script.js I defined the function drawRingProgress() which renders the canvas when I execute it at the end of the script.
As the other functions of my script are executed to add tasks, edit, remove, or mark them as complete, the parameters pendingTasks and completedTasks get updated. However, if I call the function drawRingProgress() within the other mentioned functions, in order to update the progress, the canvas is wrongly drawn somewhere else multiple times (depending on the HTML elements these functions are acting on). What would be a correct approach to render the updated progress percentage?
Link to the working example: https://jsfiddle.net/tailslider13/f4qtmhzj/7/
let pendingTasks = 31;
let completedTasks = 69;
function drawRingProgress(pendingTasks, completedTasks) {
var el = document.getElementById('graph'); // get canvas
let progress_percentage = Math.floor((completedTasks / (completedTasks + pendingTasks)) * 100) || 0;
var options = {
// percent: el.getAttribute('data-percent') || 25,
percent: progress_percentage,
// size: 110,
size: el.getAttribute('data-size') || 220,
lineWidth: el.getAttribute('data-line') || 15,
rotate: el.getAttribute('data-rotate') || 0
}
var canvas = document.createElement('canvas');
var span = document.createElement('span');
span.textContent = options.percent + '%';
if (typeof (G_vmlCanvasManager) !== 'undefined') {
G_vmlCanvasManager.initElement(canvas);
}
var ctx = canvas.getContext('2d');
canvas.width = canvas.height = options.size;
el.appendChild(span);
el.appendChild(canvas);
ctx.translate(options.size / 2, options.size / 2); // change center
ctx.rotate((-1 / 2 + options.rotate / 180) * Math.PI); // rotate -90 deg
//imd = ctx.getImageData(0, 0, 240, 240);
var radius = (options.size - options.lineWidth) / 3.2;
var drawCircle = function (color, lineWidth, percent) {
percent = Math.min(Math.max(0, percent || 1), 1);
ctx.beginPath();
ctx.arc(0, 0, radius, 0, Math.PI * 2 * percent, false);
ctx.strokeStyle = color;
ctx.lineCap = 'round'; // butt, round or square
ctx.lineWidth = lineWidth
ctx.stroke();
};
drawCircle('#efefef', options.lineWidth, 100 / 100);
drawCircle('#046582', options.lineWidth, options.percent / 100)
}
drawRingProgress(pendingTasks, completedTasks);
Here is how I would draw the graph. I have removed all of the other functions from this so it is only showing the graph progress based on what you set the variables to. Once you get your other functions figured out you can updated them via that method.
First I would get the canvas at the beginning of the script and also designate the variables a global.
Second I would draw the white doughnut flat out. Unless you plan on changing it in some way the function drawGraph() will get called once and that's it.
Third the function drawRingProgress() will get called from your other functions when you add, delete, or complete a task. Be sure those function also update pendingTasks and completedTasks prior to calling drawRingProgress().
Inside drawRingProgress() I added the text since canvas has that built in method so you don't need to use a <span>. As far as all your options I removed them for this but you can add them back as where you see fit.
const inputField = document.getElementById("addTask");
const taskList = document.getElementById("taskList");
var canvas = document.getElementById('graph');
var ctx = canvas.getContext('2d');
canvas.width = 200;
canvas.height = 200;
let pendingTasks = 20;
let completedTasks = 5;
//Progress ring
function drawGraph() {
ctx.beginPath();
ctx.strokeStyle = "white";
ctx.arc(canvas.width/2, canvas.height/2, 50, 0, Math.PI*2, false);
ctx.lineCap = 'round'; // butt, round or square
ctx.lineWidth = 15;
ctx.stroke();
ctx.closePath();
}
drawGraph();
function drawRingProgress(pendingTasks, completedTasks) {
let progress_percentage = (completedTasks / pendingTasks) * 100;
ctx.font = "30px sans-serif";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillStyle = "#046582";
ctx.fillText(progress_percentage+'%', canvas.width/2,canvas.height/2);
percent = Math.min(Math.max(0, (progress_percentage/100) || 1), 1);
ctx.beginPath();
ctx.save();
ctx.translate(0, canvas.height); // change center
ctx.rotate((-1 / 2 + 0 / 180) * Math.PI); // rotate -90 deg
ctx.arc(canvas.width/2, canvas.height/2, 50, 0, Math.PI * 2 * percent, false);
ctx.strokeStyle = "#046582";
ctx.lineCap = 'round'; // butt, round or square
ctx.lineWidth = 15;
ctx.stroke();
ctx.restore();
ctx.closePath();
}
drawRingProgress(pendingTasks, completedTasks);
#body {
background-color: #046582;
}
header {
background-color: #f39189;
padding: 50px;
margin: 50px;
position: sticky;
top: 0px;
}
h1 {
text-align: center;
}
.listItem {
margin: 20px 0px;
background-color: white;
}
.container {
background-color: #c4c4c4;
}
.taskList {
list-style-type: none;
background-color: transparent;
overflow: hidden;
margin-top: 150px;
}
.inputContainer {
margin: 50px;
padding: 20px;
max-width: 50%;
width: 100%;
background-color: #f39189;
}
#footer {
text-align: center;
position: sticky;
bottom: 0px;
background-color: #f39189;
padding: 20px;
}
.deleteButton {
background-image: url("/content/delete.png");
background-repeat: no-repeat;
background-size: cover;
cursor: pointer;
width: 30px;
height: 30px;
margin: 15px;
}
#addTask {
font-family: Verdana, Geneva, Tahoma, sans-serif;
font-size: 1.3rem;
}
.taskName {
font-family: Verdana, Geneva, Tahoma, sans-serif;
font-size: 1.2rem;
}
.listContainer {
height: 1080px;
}
.inputContainer {
position: fixed;
}
.checkedbox {
text-decoration: line-through;
color: #f39189;
}
/* START Styling Progress ring */
.chart {
position: relative;
/* margin:0px; */
width: 220px;
height: 220px;
}
canvas {
display: block;
position: absolute;
top: 0;
left: 0;
}
span {
color: #046582;
display: block;
line-height: 220px;
text-align: center;
width: 220px;
font-family: sans-serif;
font-size: 30px;
font-weight: 100;
margin-left: 5px;
}
/* Links progress ring */
/* https://stackoverflow.com/questions/14222138/css-progress-circle
http://jsfiddle.net/Aapn8/3410/ */
/* END Styling Progress ring */
<!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>Document</title>
<!-- Required meta tags -->
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<!-- Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.0.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-wEmeIV1mKuiNpC+IOBjI7aAzPcEZeedi5yW5f2yOq55WWLwNGmvvx4Um1vskeMj0" crossorigin="anonymous" />
</head>
<div class="container">
<body id="body">
<header class="row justify-content-end">
<h1 class="col-4">Take note</h1>
<!-- Progress ring -->
<div class="col-4">
<canvas class="chart" id="graph"></canvas>
</div>
</header>
<!-- Input field and button -->
<div class="row inputContainer rounded">
<input class="col-auto" type="newTask" placeholder="Enter new Task" id="addTask" />
<button class="col-auto" id="btnAdd">Add</button>
</div>
<!-- List of tasks created -->
<div class="listContainer">
<ul class="taskList rounded" id="taskList"></ul>
</div>
<footer class="row" id="footer">
<h6 class="col w-100">2021</h6>
</footer>
<!-- BOOTSTRAP -->
<script src="https://cdn.jsdelivr.net/npm/#popperjs/core#2.9.2/dist/umd/popper.min.js" integrity="sha384-IQsoLXl5PILFhosVNubq5LC7Qb9DXgDA9i+tQ8Zj3iwWAwPtgFTxbJ8NT4GN1R8p" crossorigin="anonymous">
</script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.0.0/dist/js/bootstrap.min.js" integrity="sha384-lpyLfhYuitXl2zRZ5Bn2fqnhNAKOAaM/0Kr9laMspuaMiZfGmfwRNFh8HlMy49eQ" crossorigin="anonymous">
</script>
</body>
</div>
</html>
I also wasn't sure what you intent was with using bootstraps chart. I haven't used it before but from checking the docs it didn't appear you were actually coding appropriatly for it. Also you had a <div> with the class of chart and not a <canvas> which appeared wrong to me (but like I said I haven't used it before). In the example here I changed it to <canvas> and also got rid of the canvas you were creating along with the span.
Hopefully this is what you wanted if not maybe you can still piece together what I have here with what exactly you want.
Hey Carlos and everybody interested in a solution.
After investigating the code I noticed the problem lies in creating the elements span and canvas everytime the function gets invoked but never removed.
The solution to that is to have these elements in place to begin with, namely in the html code || or create them once before the function is called.
As for the variables pendingTasks and completedTasks, I would suggest changing them to pendingTasks and totalAmountOfTasks. (Unless there is a third state in which they can be.)
Then the ratio you would feed into the circle is pendingTasks/totalAmountOfTasks.
Remember to check for dividing by zero, when there are no tasks!
Cheers,
Thomas
I have a canvas that is the only thing on a page I want really want to see. I'm trying to make it such that when I resize my window, I always have the entire canvas viewable with no scroll bars and maintain the aspect ratio.
MCVE
let canvas = document.getElementById('canvas');
let ctx = canvas.getContext('2d');
let w = canvas.width;
let h = canvas.height;
ctx.fillStyle = 'teal';
ctx.fillRect(0, 0, w, h);
ctx.strokeStyle = 'red';
ctx.lineWidth = 10;
ctx.rect(5, 5, w - 5, h - 5);
ctx.stroke();
* {
background-color: white;
max-height: 100%;
max-width: 100%;
margin: 0;
padding: 0;
}
div#canvasDiv {}
canvas#canvas {
display: block;
margin: auto;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
</head>
<body>
<div id="canvasDiv">
<canvas id="canvas" width="500" height="500" />
</div>
</body>
</html>
All here at jsfiddle
With this attempt, it rescales just fine when I resize the width. However, when I resize the height, I get overflow.
Resize Width with appropriate rescaling
Resize Height with unwanted overflow
You may like to read this article: [Centering in CSS: A Complete Guide](https://css-tricks.com/centering-css-complete-guide/
let canvas = document.getElementById('canvas');
let ctx = canvas.getContext('2d');
let w = canvas.width;
let h = canvas.height;
ctx.fillStyle = 'teal';
ctx.fillRect(0, 0, w, h);
ctx.strokeStyle = 'red';
ctx.lineWidth = 10;
ctx.rect(5, 5, w - 5, h - 5);
ctx.stroke();
* {
background-color: white;
max-height: 100%;
max-width: 100%;
margin: 0;
padding: 0;
}
canvas#canvas {
display: block;
margin: auto;
position:absolute;
top:0;bottom:0;
left:0;
right:0;
}
<div id="canvasDiv">
<canvas id="canvas" width="500" height="500"/>
</div>
So I'm just trying to make a simple animated HMTL canvas with an animated block that moves around the canvas using WASD. I initially noticed that painting a rectangle on the canvas of size 5,5 made what looked like a rectangle of size 5,10. When testing my redrawing function and printing to the console the x and y location of the element in the canvas, I noticed that my rectangle can go from 1-300 in the X direction, but only 1-150 in the Y direction. This happens even though the canvas is styled as 300,300. Can anyone figure out if I've done something silly?
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="style.css">
<script type="text/javascript" src="script.js" defer></script>
</head>
<body>
<div class="text-holder holder" id="instruction-holder">
<p class="text" id="instruction">Use WASD to navigate around the viewer</p>
</div>
<div class="holder" id="canvas-holder">
<canvas id="canvas"></canvas>
</div>
</body>
</html>
and the css
#canvas {
width: 300px;
height:300px;
margin-left: auto;
margin-right: auto;
display: block;
border-style: solid;
border-color: grey;
border-radius: 1px;
}
.holder {
display: block;
margin-left: auto;
margin-right: auto;
text-align: center;
}
and the js
var UP = "87", DOWN = "83", LEFT = "65", RIGHT = "68", X = 10, Y = 5, XSIZE = 10, YSIZE = 5;
var c = document.getElementById("canvas");
var ctx = c.getContext("2d");
var xPos, yPos;
window.addEventListener("load",init);
document.addEventListener('keydown',move);
function init() {
xPos = 1;
yPos = 1;
ctx.fillStyle = "black";
ctx.fillRect(xPos,yPos,XSIZE,YSIZE);
}
function clear() {
ctx.clearRect(0,0,300,300);
}
function reDraw(delX, delY) {
console.log(yPos+delY + " " + (xPos+delX));
if (xPos+delX > 0 && xPos+delX < 300 &&
yPos+delY > 0 && yPos+delY < 150) {
clear();
ctx.fillStyle = "black";
xPos = xPos+delX;
yPos = yPos+delY;
ctx.fillRect(xPos,yPos,XSIZE,YSIZE);
}
}
function move(ev) {
var delX, delY;
var key = ev.keyCode;
if (key == UP) {
delX = 0;
delY = -Y;
} else if (key == DOWN) {
delX = 0;
delY = Y;
} else if (key == LEFT) {
delX = -X;
delY = 0;
} else if (key == RIGHT) {
delX = X;
delY = 0;
}
if (delX != undefined && delY != undefined) {
reDraw(delX, delY);
}
}
You have to set the size of canvas explicitly or it will use the default size of 300x150 (CSS only scales the element, not the bitmap - the bitmap of 300x150 is stretched to fit what you see on screen by the CSS rule, but the bitmap will remain the same size internally):
<canvas id="canvas" width=300 height=300></canvas>
Then just remove these:
#canvas {
/* width: 300px; */
/* height:300px; */
...