Show a portion of decimal numbers without altering their true numerical values

Currently, I am immersed in a web project that involves incrementation animations. To achieve this, I have devised a counter function similar to the one shown below:

const counters = document.querySelectorAll('.counter');

    counters.forEach(counter => {
        const updateCount = () => {
            const target = +counter.getAttribute('data-target');
            const count = +counter.innerText;

            const speed = target / 1000; //this will not work accurate if using Math.ceil or floor to round number up
           
            if (count < target) {
                counter.innerText = count + speed;
                setTimeout(updateCount,1);
            } else {
                counter.innerText = target;
            }
        }
        updateCount();
    });
* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}
html , body {
  width: 100%;height: 100%;
  display: flex;
  justify-content: center;
  flex-direction: column;
  align-items: center;
}
/* HEADER */

.counter {
  font-size: 20px;
  font-weight: bold;
  padding: 5px;
}
<span data-target="20" class="counter">0</span>
    <span data-target="100" class="counter">0</span>
    <span data-target="50" class="counter">0</span>
    <span data-target="250000" class="counter">0</span>

The challenge lies in the fact that the numbers displayed on the website are in decimal format. Various attempts such as math.ceil,math.floor, ... were made to rectify this issue but they interfered with the speed of the counter. Is there any method to solely display the integer portion WITHOUT affecting the speed?

Answer №1

When calling the function, be sure to pass in the updated value rather than relying on the current printed value.

Check out the code comments for more details.

const counters = document.querySelectorAll('.counter');

    counters.forEach(counter => {
  
        /* Make sure to provide a parameter */
        const updateCount = (count) => {
            const target = +counter.getAttribute('data-target');

            /* On initial function call without an argument,
             * use the innerText value. Otherwise, use the argument
             * by changing 'const' to 'var'
             */
            var count = count || +counter.innerText;

            const speed = target / 1000;
            
            
            if (count < target) {

                /* Use parseInt() when updating the value to keep
                 * only the integer part
                 */
                counter.innerText = parseInt(count + speed, 10);

                /* Call the function with the original sum of
                 * count + speed
                 */
                setTimeout(function() {
                  updateCount(count+speed)
                }, 1);

            } 
            else {
                /* Utilize parseInt() */
                counter.innerText = parseInt(target, 10);
            }
        }
        updateCount();
    });
  
.counter {
  font-size: 20px;
  font-weight: bold;
  padding: 5px;
  display: block;
}
<span data-target="20" class="counter">0</span>
<span data-target="100" class="counter">0</span>
<span data-target="50" class="counter">0</span>
<span data-target="250000" class="counter">0</span>

Additionally, consider passing a second target argument to the function instead of repeatedly accessing the DOM for its value, similar to how it's done for count, as it remains constant.

Answer №2

When using the same value for calculation and display, rounding off can result in losing precision. For example, if 1.3 + 3 = 4.3 on the first iteration, then on the next iteration, 4.3 will be rounded up to 5 and the sum would become 5 + 3. This discrepancy can make the speed appear inconsistent.

To address this issue, adding a hidden attribute called count-value to the span allows you to store the full number with all decimals for calculations. You can then display the number without decimals to users without affecting the sum.

const counters = document.querySelectorAll('.counter');

    counters.forEach(counter => {
        const updateCount = () => {
            const target =+ counter.getAttribute('data-target');
            //update count with the full value
            const count =+ counter.getAttribute('count-value');

            const speed = target / 1000; //this will not work accurately if using Math.ceil or floor to round number up
           
            if (count < target) {
                //set the innertext to the rounded up value
                counter.innerText = Math.ceil(count + speed);
                //update the hidden attribute with the full value
                counter.setAttribute('count-value', count + speed);
                setTimeout(updateCount,1);
            } else {
                counter.innerText = target;
            }
        }
        updateCount();
    });
* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}
html , body {
  width: 100%;height: 100%;
  display: flex;
  justify-content: center;
  flex-direction: column;
  align-items: center;
}
/* HEADER */

.counter {
  font-size: 20px;
  font-weight: bold;
  padding: 5px;
}
    <span data-target="20" count-value="0" class="counter">0</span>
    <span data-target="100" count-value="0" class="counter">0</span>
    <span data-target="50" count-value="0" class="counter">0</span>
    <span data-target="250000" count-value="0" class="counter">0</span>

Answer №3

If you need assistance, you can refer to: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toFixed

Here is an example with an additional data-attribute:

const counters = document.querySelectorAll('.counter');

counters.forEach(counter => {
  const updateCount = () => {
    const target = +counter.getAttribute('data-target');
    const count = +counter.getAttribute('data-count');

    const speed = target / 1000; //this approach may not be precise when using Math.ceil or floor to round up numbers

    if (count < target) {
      counter.setAttribute('data-count', count + speed);
      let stripped = (count + speed).toFixed(0);
      counter.innerText = stripped
      setTimeout(updateCount, 1);
    } else {
      counter.innerText = target;
    }
  }
  updateCount();
});
* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

html,
body {
  width: 100%;
  height: 100%;
  display: flex;
  justify-content: center;
  flex-direction: column;
  align-items: center;
}


/* HEADER */

.counter {
  font-size: 20px;
  font-weight: bold;
  padding: 5px;
}
<span data-target="20" class="counter">0</span>
<span data-target="100" data-count="0" class="counter">0</span>
<span data-target="50" data-count="0" class="counter">0</span>
<span data-target="250000" data-count="0" class="counter">0</span>

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

Creating a Twitter share link for your website with concise blog posts is simple and effective

I am looking to generate a Twitter share link on my website that shares the initial lines of a user's blog by retrieving data from a PHP database. The content of the blog is saved in HTML format within the database. I attempted to retrieve the data an ...

Rotation snapping feature 'control.setRotationSnap' in TransformControls.js (Three.js) is not functioning properly

Attempting to utilize the functionality of "control.setRotationSnap" from the script "TransformControls.js", but unfortunately, it is not working as expected. After conducting some research, I came across a forum post suggesting that the code might not be ...

Ensure that buttons are cropped when extending beyond the border of another DIV

My issue involves a main DIV with buttons contained within it. I am seeking a solution to ensure that the buttons are cut off at the edge of the DIV, similar to the concept illustrated in this image. In the image, the blue represents the body, the light gr ...

Implementing Angular Bootstrap UI into an Angular 1.3.0 application

Currently utilizing angular.js version 1.3.0, I have added the angular bootstrap ui to my index.html as shown below: <script src="lib/onsen/js/angular/angular.js"></script> <script src="https://code.angularjs.org/1.3.1/i18n/angular-locale_e ...

Overlapping dynamic content causing CSS nested scrollbars to clash at full width of 100%

Displayed below is a layout with two nested divs, both featuring automatic vertical scrolling. Is there a CSS technique available to show the inner scrollbar while maintaining the inner div at 100% width? https://i.stack.imgur.com/HSKHH.png div { ba ...

What are the steps to incorporating HTML code into JavaScript?

Can I insert HTML elements into the view using JavaScript? I am hoping to achieve something like this: <script> <% for @m in @messages %> <h1>i</h1> <% end %> </script> I need it to work seamlessly with Ruby. Not s ...

unable to view icons from Summernote inline

I am currently using the Summernote editor, but I am experiencing some issues with the icons. Here is the image of the problem: https://i.sstatic.net/fRm0B.png My goal is to have all the icons aligned in a single line. Below is the code I am using: $(&a ...

Animations within Angular components are being triggered even after the parent component has been removed from

When a child component has an animation transition using query on mat-table rows, hiding the parent component will now trigger the child animation. To see this in action, check out this reproduction scenario: https://codesandbox.io/s/intelligent-jasper-hz ...

Show an image in JPEG format using JavaScript within an img tag

Suppose http://example.com/image returns unique image data in response headers and the image itself. Each request to http://example.com/image generates a different image that is not related to the request itself. Besides the image, additional information s ...

Range slider position not being updated after user interaction

I am working on a webpage with an embedded video and a range slider that serves as a progress bar. Using Javascript, I update the value of the range slider as the video plays, allowing users to navigate through the video content. However, I have encounter ...

Attempting to integrate a chatroom name entered by the user using a combination of Ajax and Python

Despite reading numerous textbooks on computer science, I have been struggling with sending ajax form data to Python and checking it in a dictionary before parsing it into a JSON object. The concept of dictionaries with key-value pairs is clear; however, a ...

ReactJS did not get the expected function type for the onClick event listener, instead receiving an object type

I am encountering an issue where I expected the onClick event listener to be a function but instead got an object type error. Can someone offer guidance on how to resolve this problem? Below is a snippet of my code: render_detail_options = () => { ...

Angular 6 issue: Bootstrap 4 carousel indicators not responsive to clicks

I am currently working on incorporating a Bootstrap 4 carousel into my application, but I seem to be encountering issues with the indicators. Ideally, clicking on any of them should navigate you to the corresponding photo, similar to this example: https:// ...

Guide on creating event hooks within VUE 2.0 component connections

I have successfully created two dynamic components. Now, I am looking to trigger the "logThat(someObj)" method of component-two using events: $emit/$on with the arguments being passed as shown in this code snippet: Vue.component('component-one', ...

The issue with the placement of the Bootstrap navbar-brand

My regular bootstrap navbar is presenting a problem where the item "navbar-brand" appears higher than the other items in the navbar, which seems illogical. This issue does not occur on the official bootstrap page and persists even when tested on jsfiddle. ...

Seeking guidance for Ajax file uploads

I am currently working on integrating an Ajax file uploader into my project. You can find more information about it here: According to the documentation: var uploader = new qq.FileUploader({ // pass the dom node (ex. $(selector)[0] for jQuery users) ...

`Connected circles forming a series in d3`

I am currently working on developing an application where the circles are positioned such that they touch each other's edges. One of the challenges I am facing is with the calculation for the cx function. .attr("cx", function(d, i) { return (i * 5 ...

Utilizing an external JavaScript file for developing applications on Facebook

I am looking to incorporate external JavaScript into my Facebook application development. Specifically, I am hoping to utilize the Ajax tab feature in my application. ...

Getting the ID name from a select tag with JavaScript - A quick guide!

Can you help me retrieve the id name using JavaScript when a selection is made in a select tag? I have tried running this code, but it only alerts undefined. For instance, if I select bbb in the select tag, I should be alerted with 2 Any suggestions on ...

HTML modal windows are a great way to show

I have a table in an HTML document that is populated with information from JSON. Within one of the cells, I'd like to insert a link that will open a modal window. The current setup functions correctly; however, I would like the modal window to displ ...