Use a loop with requestAnimationFrame to continuously clear the canvas and reset the drawing board

I have been experimenting with creating interactive elements in a canvas using requestAnimationFrame. The issue I am facing is that the function to clear and create a 'blank' canvas space does not seem to be working properly within the loop. From previous tests, it seems like my code may be incomplete or not optimal as I am trying to improve it by following Object-Oriented Programming (OOP) and Model-View-Presenter (MV+) patterns. I am able to move a basic shape (a 'test square'), but the old drawing still remains on the screen. In a basic HTML structure like this:

    <!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>test action game</title>
<style type="text/css" rel="stylesheet" >
body{margin:0;padding:0;background-color:#000;overflow:hidden;}
</style>
</head>
<body>
<script>/* separated for better forum readability, see below */
</script></body></html>

Below is my JavaScript code:

/** global utility functions */
function isReal(val){ return val !== 'undefined' && val !== null ? true : false; }

/** animation loop */
window.requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
function animate(){
if(ctrls.input.states.up === true){ rc.y -= moveSpeed; }
if(ctrls.input.states.down === true){ rc.y += moveSpeed; }
if(ctrls.input.states.left === true){ rc.x -= moveSpeed; }
if(ctrls.input.states.right === true){ rc.x += moveSpeed; }
cnv.ctx.fillStyle = '#c0ffc0';
cnv.ctx.clearRect(0, 0, cnv.w, cnv.h);
drawRect(cnv.ctx, rc.x, rc.y, rc.w, rc.h, '#ff0000', '#0000ff');
requestAnimationFrame(animate);

}
/** Canvas drawing utilities */
function addCanvas(id, ancestor, w, h){
let canvas = document.createElement('canvas');
    canvas.id = id;
canvas.setAttribute('WIDTH', w);
canvas.setAttribute('HEIGHT', h);
ancestor.appendChild(canvas);
return {tag: canvas, ctx: canvas.getContext('2d'), w: w, h: h};
}

function drawRect(ctx, x, y, w, h, stroke='#ffffff', fill='#ffffff'){
if(typeof ctx === typeof document.createElement('canvas').getContext('2d')){
ctx.rect(x, y, w, h);
if(isReal(stroke) && stroke !== false){
ctx.strokeStyle = stroke;
ctx.stroke();
console.log('drawRect stroke '+x+','+y+','+w+','+h+' '+stroke);
}
if(isReal(fill) && fill !== false){
ctx.fillStyle = fill;
ctx.fill();
console.log('drawRect fill '+x+','+y+','+w+','+h+' '+fill);

}

return ctx;
}
console.log('ERROR - Drawing Context: '+ctx+' should be CanvasRenderer2D');
return;
}


let cnv = addCanvas('cnv', document.body, window.innerWidth, window.innerHeight );
console.log('Canvas size: '+cnv.w+'X'+cnv.h);
function testItem(){ let tmp = Math.round(cnv.w/50); return {w: tmp, h: tmp, x: tmp, y: tmp}; }
let rc = testItem();
console.log('('+rc.x+' '+rc.y+')');


/** Input Management: Keyboard Controls */
function Controls(id){
return{
id: id,
input:{
states: {},
keys:{
up: 38,
down: 40,
right: 39,
left: 37
}
}
}
}

let moveSpeed = 2;
let controls = Controls('controller');
document.addEventListener('keydown', function(e){
switch(e.keyCode){
case controls.input.keys.up:
controls.input.states['up'] = true;
break;
case controls.input.keys.right:
controls.input.states['right'] = true;
break;
case controls.input.keys.down:
controls.input.states['down'] = true;
break;
case controls.input.keys.left:
controls.input.states['left'] = true;
break;
default: break;
}
console.log('States: up='+controls.input.states.up+'\tright='+controls.input.states.right+'\tdown='+controls.input.states.down+'\tleft='+controls.input.states.left);
});
document.addEventListener('keyup', function(e){
switch(e.keyCode){
case controls.input.keys.up: if(isReal(controls.input.states['up'])){ controls.input.states.up = false; }
break;
case controls.input.keys.right: if(isReal(controls.input.states['right'])){ controls.input.states.right = false; }
break;
case controls.input.keys.down: if(isReal(controls.input.states['down'])){ controls.input.states.down = false; }
break;
case controls.input.keys.left: if(isReal(controls.input.states['left'])){ controls.input.states.left = false; }
break;

default: break;
}
});

let animation = animate();
body{margin:0;padding:0;background-color:#000;overflow:hidden;}

I have attempted using .save() and .restore() methods during the initial draw without success, along with using .beginPath() and .closePath() while drawing shapes, but the results are not what I expected. Any advice on how to resolve this issue would be greatly appreciated.

Answer №1

To reset the context, you can utilize a clever hack by manipulating its canvas element:

canvas.width = canvas.width

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Mocking a promise rejection in Jest to ensure that the calling function properly handles rejections

How can I effectively test the get function in Jest, specifically by mocking Promise rejection in localForage.getItem to test the catch block? async get<T>(key: string): Promise<T | null> { if (!key) { return Promise.reject(new Error(&apo ...

Clicking on a link in HTML with the onclick event

I am looking to create a button that will direct me to a different page. Here is the code snippet I have: <div align="right" ><input type="submit" id="logout" onclick="location.href='/login?dis=yes'" value="Sign Out" ></div>& ...

Having trouble getting NextJS to work with jsmpeg/node-rtsp-stream for displaying an RTSP stream

Exploring: https://github.com/kyriesent/node-rtsp-stream and How to display IP camera feed from an RTSP url onto reactjs app page? I attempted to showcase the RTSP stream from a CCTV but encountered an error. ReferenceError: document is not defined at scri ...

Utilize recursive and for loop methods for parsing JSON efficiently

I have a JSON file that requires parsing. I'm attempting to implement a recursive method for this task. The current JSON data is structured as shown below: Item 01 SubItem 01 InnerSubItem 01 Item 02 SubItem 01 InnerSubItem 01 Unfortunately, t ...

Is it possible to use v-model on an input that is being dynamically updated by another script?

How can I retrieve the lat and lng values stored in two input fields when a user changes the marker's position on a Google map? When the user clicks to select a new place, I need to update these inputs accordingly. I attempted using v-model but it onl ...

What is the process for adjusting the code to manage the labels of specific buttons?

There is a code $("button").click(function() { var btn = this; if (btn.loaded) { $(btn).prev("div").html(btn.originalContent); btn.loaded = false; $(btn).text('Get Dynamic chart'); } else { btn.originalConte ...

Creating Typescript packages that allow users to import the dist folder by using the package name

I am currently working on a TypeScript package that includes declarations to be imported and utilized by users. However, I have encountered an issue where upon publishing the package, it cannot be imported using the standard @scope/package-name format. I ...

Exploring the implementation of if statements within the array map function in the context of Next.js

Is there a way to wrap certain code based on the remainder of the index number being 0? I attempted the following approaches but encountered syntax errors. {index % 3 === 0 ? ... : ...} {index % 3 === 0 && ...} export default function UserPosts() { / ...

Tips for applying an active class to buttons using ng-click?

Here is the HTML code for the buttons. The taskfilter is the filter that controls how the buttons work when clicked and the class name is 'sel' <a class="clear-completed" ng-click="taskfilter = 1" ng-class="{'sel':enabled}"> &l ...

Dealing with problematic hover behaviors in Cypress: A guide

I encountered an issue with Cypress hover functionality while trying to access a sub menu that appears after hovering over a main menu item. The error message I received was This element is not visible because it has CSS property: position: fixed and it&ap ...

jQuery - Endless paging

My attempt at implementing infinite scrolling on my page seems to have hit a snag. Instead of triggering at the bottom of the page, it's activating when I scroll back to the top. Can anyone shed some light on what might be causing this issue? $(windo ...

Using a promise inside an Angular custom filter

I am attempting to implement a filter that will provide either a success or error response from the ret() function. The current code is returning {}, which I believe is its promise. .filter('postcode', ['$cordovaSQLite', '$q' ...

Bringing to life in Vue.js

I am a beginner with Vue.js and I have been attempting to integrate Materialize into my project. I have experimented with various plugins such as vue-materialize (https://github.com/paulpflug/vue-materialize) and vue-material-components (https://www.npmjs. ...

Tips for properly formatting the sort_by parameter in Cloudinary to avoid errors

Greetings to the helpful stack overflow community, I have encountered an issue with fetching images from cloudinary via a post request. Everything works fine until I include the sort_by parameter in the URL. This results in an error related to the format ...

The preventDefault function fails to work in Firefox

My input is called shop_cat_edit and I've included the following code. However, it seems to work fine in IE but doesn't work in FireFox. Can anyone help me figure out what's wrong? $('[name=shop_cat_edit]').on('click',fu ...

Issues encountered - nodejs-lts (exit code 1603) - Problem occurred during execution of 'C:ProgramDatachocolateylib odejs-lts oolschocolateyinstall.ps1' script

Encountering Issues with Installing 64-bit Version of nodejs-lts... Received a Generic MSI Error during installation, indicating a local environment issue rather than a problem with the package or MSI file itself. Possible reasons for thi ...

Enable users to provide ratings ranging from 0.5 up to 5

I recently created a rating component that allows users to rate on a scale from 0 to 4.5, with increments of 0.5, which is causing unexpected behavior. I actually want users to be able to rate from 0.5 to 5 instead. How can I achieve this adjustment? Below ...

A custom class that uses toggleClass() does not trigger an alert upon a click event

I am encountering an issue with the toggleClass() function in jQuery that I haven't seen addressed before. Despite successfully toggling the class of one button when clicked, I am unable to trigger a click event on the newly toggled class. Here is th ...

Saving user input as a local variable to be utilized on a different web page

I am attempting to capture a user input from a form and then utilize that variable on a separate page. This process should be straightforward, but I am not receiving any results and I am unsure of the reason why. Here is the code on the first page: <di ...

Platform for managing web push notifications and directing users to specific URLs

I am not very familiar with coding, but I recently had a developer create a self-hosted web-push panel for my website and provided a plugin for my WordPress site. The admin panel is functioning properly, however, there seems to be an issue with it, possibl ...