Typescript: Shifting an image to the left and then returning it to the right

As a newcomer to Typescript, JavaScript, and front-end development, I am experimenting with creating a simulation of an AI opponent's "thinking" process when playing cards in a game. The idea is to visually represent the AI's decision-making by shifting each card slightly to the left and then back to the right before actually playing a card from its hand.

In my project, I have a collection of images that symbolize a hand of cards. Using Visual Studio Code for coding and Chrome for debugging, I've implemented a process where the API call triggers the AI logic, followed by a sequence that involves iterating through the cards, simulating the thinking process, and finally playing the chosen card. Despite having everything set up in synchronous callback functions, the visual effect only seems to work properly when a breakpoint is active during debugging.


// Function triggered on opponent's turn
opponentTurn(callback) {
   this.boardService.opponentTurn()
       .subscribe(
       cardPlayed =>
       {
         let cardData = [];
         cardData = JSON.parse(cardPlayed.toString());

        // Simulate the AI thought process
        this.selectCard(function(_thisagain) {
          _thisagain.dragService.simulateDragDrop(cardData);
        });        

         callback(this);
       }
     );
 }

 // Method to simulate selection of cards for AI's "thinking"
 selectCard(callback) {
  for (var i = 0; i < this.players[1].cardHand.length; i++)
  {
    let imgObj = document.getElementById(this.players[1].name + i);     

    if (imgObj != null)
    {
      this.moveCard(imgObj, '400px', function(_thisagain) {
        _thisagain.moveCard(imgObj, '350px', function() {
          
        });
      });
    }
  }

  callback(this);
 }

 moveCard(imgObj, position, callback) {
    this.wait(250, function() {
      imgObj.style.right = position;
    });
    callback(this);
 }

 wait(ms, callback) {
   var start = new Date().getTime();
   var end = start;
   while(end < start + ms)
    {
      end = new Date().getTime();
    }
    callback(this);
 }

The issue arises when the code runs without breakpoints: the card animations don't occur smoothly. My assumption is that the lack of redraws causes this problem. However, as a novice, I'm uncertain about how to address it effectively. Any guidance or insights would be greatly appreciated.

Answer №1

After thorough research and numerous attempts, I finally managed to get it up and running smoothly. The breakthrough moment came when I stumbled upon a particular post that guided me in the right direction. Here's the link to the post that proved to be instrumental: DOM refresh on long running function

The post included an answer that highlighted a crucial point: "Webpages are updated based on a single thread controller, and half the browsers don't update the DOM or styling until your JS execution halts, giving computational control back to the browser."

This insight was the missing piece of the puzzle for me. I realized that processing too much in a single statement was preventing the JavaScript from releasing control back to the browser. Consequently, the DOM/html wasn't being updated to display the desired "animation".

Following the example provided in a jsfiddle linked in another answer there, I devised a "worker" thread that broke down the process into manageable chunks using a procedural "status" approach and relinquished control back to the browser with setTimeout(). Each worker thread was structured as a callback function to ensure that each chunk's processing completed before moving on. This approach resolved the issues I initially faced. While I continue to refine the code, I am currently satisfied with the outcomes.

To aid potential future individuals who might come across my query, here is a snippet outlining my worker thread. Though certain terminologies may vary, the core concept remains consistent. When initiating a process flow, setting the "status" text and calling into the worker triggers the necessary flow processing.

doHeavyWork() {
    if (this.status == 'finish')
    {
      // All steps done 
    }
    else
    {
      let _this = this;
      switch (_this.status)
      {
        case 'start':
          _this.status = 'working';
          _this.opSelectCard = 0;
          this.opponentTurn(function(response) {
            _this.opCardData = response;
            _this.status = 'selectCard';
          });
          break;

        // Additional cases omitted for brevity

        case 'switchTurns':
          _this.status = 'working';
          this.switchTurns(function(_this) {
            if (_this.turn == 1)
            {
              _this.status = 'finish';
            }
            else
            {
              _this.status = 'start';
            }
          });
          break;
      }

      setTimeout(function() {
        _this.doHeavyWork();
      }, 0);
    }
  }

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

Unable to open file downloaded from Laravel with Vue.js support

I am facing an issue with my function in Laravel and vue.js. Even though it successfully downloads the desired file, when I try to open it, I consistently receive an error message stating that the file type is unsupported. Below is the vue.js function I a ...

What is the best way to implement a JavaScript pattern matching for both "aaaa" and "aaa aaa"?

Can anyone help me create a pattern that can accept both strings with spaces and without spaces in the same text box? I would appreciate any guidance on how to achieve this. Thanks! ...

Is it considered fashionable to utilize HTML5 data attributes in conjunction with JavaScript?

Currently, I am utilizing HTML5 data attributes to save information such as the targeted DOM element and to initialize events using jQuery's delegation method. An example of this would be: <a href="#" data-target="#target" data-action="/update"> ...

Unable to update values in Google Sheets using the node.js API

I have been working on a node.js project that involves extracting the location of a cell based on a person's name and date. While I am able to determine this information easily, I encounter difficulties when trying to update the cell using the .update ...

Listener of events calculates the outcome

In need of help with retrieving the current coordinates of a clicked point on Google Maps. Here is my code snippet: let latLng = new google.maps.LatLng(position.coords.latitude, position.coords.longitude); getCoords() { google.maps.event.addListener ...

What is the process for obtaining a flattened tuple type from a tuple comprised of nested tuples?

Suppose I have a tuple comprised of additional tuples: type Data = [[3,5,7], [4,9], [0,1,10,9]]; I am looking to develop a utility type called Merge<T> in such a way that Merge<Data> outputs: type MergedData = Merge<Data>; // type Merged ...

Transform the header style columns of react-js Material-tables into rows

Currently experimenting with gradient designs on a material table. While I am able to apply the right color combination to the rows, I seem to be getting column-based results on the title of the table. Attached is a screenshot of my output for reference. ...

Rendering a component in React based on multiple conditions

Checking sessionStorage and another state variable before rendering a component is essential for my application. I want to avoid showing the same message multiple times within the same session. This is how I have implemented it: const addSession = (noteId: ...

How to Target a Specific Element Using its Class with jQuery

Hey there! I'm currently working with the following snippet of HTML code: <li class="grey"> <div class="row"> <button id="test" style="width:50%;" class="btn btn-blue-white cartBtn">Add to Cart</button> </div ...

How can I move a complete range of values up using the Google Sheets API in Node.JS?

I'm working with a Google Spreadsheet that is being accessed and modified by a Node.JS app. There's a specific situation where I need to shift an entire range up (moving A3:D up by one cell), but due to my limited experience with the Google Shee ...

Dealing with errors in node.js

Node.js asynchronous functions typically have a callback, with some like fs.writeFile passing an err argument. fs.writeFile('message.txt', 'Hello Node', function (err) { if (err) throw err; console.log('It\'s saved!& ...

What is preventing the MenuItem component from functioning as a Link in React Material-UI?

Hey there! I've been trying to implement a popover menu that changes the URL and component after clicking on an item, but unfortunately it's not working as expected. I created a setup in this sandbox: https://codesandbox.io/s/romantic-surf-40p19? ...

Guide on managing firebase and webrtc tasks within a client-side component using Next.js 13

I developed a Next.js 13 application to share the camera feed using WebRTC and Firestore. Below is my page.tsx file where I am facing some challenges. I can't make this server-side because I'm using React hooks, and moving it to the client side i ...

What are the steps to modify the authorization header of an HTTP GET request sent from a hyperlink <a href> element?

I have a unique Angular application that securely saves JWT tokens in localstorage for authentication purposes. Now, I am eager to explore how to extract this JWT token and embed it into an HTTP GET request that opens up as a fresh web page instead of disp ...

What is the most effective method to prevent the auto-complete drop-down from repeating the same value multiple times?

My search form utilizes AJAX to query the database for similar results as the user types, displaying them in a datalist. However, I encountered an issue where it would keep appending matches that had already been found. For example: User types: "d" Datali ...

Converting a promise of type <any> to a promise of type <entity>: A beginner's guide

As a newcomer to TypeScript and NestJS, I am wondering how to convert Promise<any[]> to Promise<MyEntity[]> in order to successfully execute the following code: const usersfromTransaction = this.repoTransaction .createQueryBuilder() ...

Mastering the proper implementation of the factory method in TypeScript

Trying to articulate this question is proving to be a challenge, but I'll give it my best shot. In Sharepoint, a default ListItem comes with properties like id, title, createdby, createddate, modifiedby, and modifieddate. Custom lists can have addit ...

React hooks - Issue with updating state properties within sidebar display

When resizing the window, I have an event that will display either the desktop sidebar or the mobile sidebar. However, there are variables that are not immediately updated to show the sidebar correctly based on the window size. In a desktop window, this ca ...

Double quotes in JSON are not being escaped properly

When I try to evaluate some json on a screen, I keep encountering errors with the message 'unexpected identifier'... The problematic data that seems to be causing this issue is: "itemDescription":"STANDARD \"B\" RED BOX", To address ...

Updating the status of the checkbox on a specific row using Typescript in AngularJS

My goal is to toggle the checkbox between checked and unchecked when clicking on any part of the row. Additionally, I want to change the color of the selected rows. Below is my current implementation: player.component.html: <!-- Displaying players in ...