Fluctuation of images while adjusting size on canvas

I've noticed a troublesome flickering effect in my simple JS animation that changes the size of an image to 3 decimal places. This flickering seems to occur only on specific parts of the image, with some images causing it more than others.

As an animator, I am looking for solutions to eliminate this visual issue, particularly within the realm of JavaScript animations

To see the flickering effect firsthand, you can view the animation on JSFiddle showcasing it on buildings: http://jsfiddle.net/qerwsn07/

function draw() {
    debug.innerHTML = 'Scale: '+scale;
    if(!dir){ 
        scale += 0.001; 
        if(scale > 1.09){ 
            dir = true;
        }
    } else if(dir) {
        scale -= 0.001;
        if(scale < 1){
            dir = false;   
        }
    }
    ctx.clearRect(0, 0, element.width, element.height);
    ctx.save()
    ctx.translate(element.width/2 - (camera.x / 500),element.height/2 - (camera.y / 500));      
    var x       =  - ((img.width * scale) / 2);
    var y       =  - ((img.height* scale) / 2);
    var width   = img.width * scale;
    var height  = img.height*scale;

    ctx.drawImage(img,x,y,img.width*scale,img.height*scale);
    ctx.restore();
    requestAnimationFrame(draw);
}
draw();

Is there any way to effectively reduce or completely remove this flickering effect?

Answer №1

Even though I can't visually see it on my current machine, I understand the issue you're facing and there are two ways to address it.

The root of the problem lies in pixel sampling. When an image is resized, there is a disparity between the screen pixels and the pixels in the image. Zooming out results in more pixels in the image than can be displayed, while zooming in causes one pixel to spread across multiple pixels.

The simplest solution is using nearest pixel sampling. The hardware determines where each device display pixel falls on the scaled image and selects the nearest pixel from the image.

Another common approach is bilinear interpolation. This method involves using the closest 4 pixels when zooming in and calculating the color by averaging the colors of neighboring pixels. When zooming out, it averages the pixels under the display pixel. While this method reduces flicker significantly, it may not eliminate it completely.

The canvas allows you to choose between nearest pixel sampling and the smoothing mode of the hardware, with the specific method depending on the hardware configuration.

To enable the smoothing method, set the imageSmoothingEnabled property of the 2D context to true.

ctx.imageSmoothingEnabled = true;

To disable it:

ctx.imageSmoothingEnabled = false;

By default, this option is usually set to "true" for the canvas, so toggling it may not immediately resolve your issue.

If you're using a PC, your graphics driver might come with a utility for adjusting rendering performance. These utilities are typically found in the Windows control panel and offer settings for optimizing performance or quality. If the performance setting surpasses the canvas smoothing option, it will prioritize speed over appearance. Switching to the best quality setting could potentially mitigate the flickering issue.

Some drivers provide granular control over individual graphics options, including pixel filtering preferences. If necessary, configure these settings to align with your preferences. It's possible to assign pixel filtering specifically to the browser application to ensure consistent rendering.

If all settings seem correct but flickering persists, alternative methods can be employed to minimize the problem.

Image blurring:

To counteract flickering during zoom-out actions, consider implementing a modified Mip-mapping technique. Create a slightly blurred copy of the image in memory and render that version when zoomed out. Transition between the blurred and original images subtly to prevent abrupt visual shifts. Utilize ctx.globalAlpha to fade between the images smoothly.

Mip mapping:

This strategy involves generating multiple copies of the image at decreasing resolutions. By strategically selecting which two images to display based on the zoom level, a seamless transition can be achieved using opacity adjustments.

Flickering artifacts may persist despite these efforts due to inherent limitations in scaling algorithms. Each method has its pros and cons, and for optimal quality, beginning with an image resolution twice that of the largest anticipated zoom level is advisable. Efficient sampling techniques are crucial for impeccable rendering, often necessitating GPU utilization through frameworks like WebGL.

Additional test for browser smoothing:

A diagnostic snippet has been included to assess whether browser smoothing settings are being overridden by the graphics driver on your system. One pattern features smoothing disabled, while the other uses enabled smoothing. If both patterns appear identical, external factors may be overpowering the browser's intended behavior.

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

Leveraging server-side functionality with JavaScript

Recently, I have been enhancing my ASP.NET project by incorporating more JavaScript and AJAX functionality. In the process, I have adjusted parts of my HTML to be generated using JavaScript. However, this modification has made it challenging for me to acce ...

Creating a custom icon and static placeholder in a bootstrap dropdown list

I am just starting out in the world of web development and I have been experimenting with creating a dropdown list that includes a static, slightly faded placeholder, along with a custom icon. My goal is to have the selected item's text displayed on t ...

Update the state in the componentDidMount lifecycle method

Embarking on a project using React to hone my skills, but encountered an error while trying to populate an array with data from a JSON file in the ComponentDidMount() hook. It seems this issue stemmed from a previous error: cannot read property 0 of undef ...

Having trouble getting the onClick event to trigger in React?

I have a button in my navbar that triggers a submenu (list of items) to display when clicked. Each item is a separate child component and I want them to trigger an event when clicked. However, the onClick event listener does not seem to be working. Other m ...

The error encountered with react createRef was caused by a faulty implementation

Here is the revised question post completing the answer In this particular code snippet, I have encountered an issue where my file browser opens correctly upon submission, however, the updated state is not reflected when I click the final submit button. ...

Elevate with Ease: Tailwind's Height Transition

I've been attempting to implement a transition effect using TailwindCSS, but I haven't found an updated version with the latest features. Here's the code snippet: <div id="fadeInElement" className={visible ? " w-2/3 px-5 t ...

Executing Query Order with AJAX for PHP and MySQL

Currently facing a bit of a perplexing situation. I have implemented a form on my website that allows users to input information into a database... Form <form id="insertbill"> Total <input type="text" id="total" name="total" /><br /&g ...

Using JavaScript to access the $_POST and $_FILES variables following an AJAX form submission

My current project involves using AJAX to submit a form and display a pre-selected image. When a user selects an image from their local drive, it triggers the "onchange" event for the file-type input field, which then initiates the AJAX routine. The proces ...

Preventing document.getElementById from throwing errors when the element is null

Is there a way to handle null values returned by document.getElementById in JavaScript without adding if statements or checks to the code? I'm looking for a solution that allows the execution of subsequent JavaScript calls even after encountering a nu ...

JS | How can we make an element with style=visibility:hidden become visible?

HTML: <div id="msg-text"><p><b id="msg" name="msg" style="visibility:hidden; color:#3399ff;">This is a hidden message</b></p></div> JS: $('#url').on('change keyup paste', function() { $('# ...

Update an array of objects by incorporating additional properties from another array, even if the two arrays are of different lengths. When the iteration of the array is complete, it should

Is there a way to merge two arrays of objects with different keys? I want to combine the keys of the second array with those of the first one. How can I accomplish this task? $scope.links = [ { name: 'JRD', status: 'active ...

Simultaneously shifting focus to carousel display and transitioning between items

I'm currently working with a carousel widget in the Hugo framework and have a basic HTML question. I'd like to create a hyperlink that not only changes the item of the carousel but also focuses on it. Here is my current code snippet: <a href ...

The draggable functionality is malfunctioning once the image is enlarged with Jquery

When it comes to creating a viewport function using jquery.viewport, I'm faced with the challenge of integrating it with jQuery UI slider and a custom zoom function for images. I've also utilized a plugin to enhance the viewport functionality. T ...

Permanent Solution for HTML Textbox Value Modification

https://i.sstatic.net/nB58K.pngI'm currently working on a GPS project where I am attempting to capture the altitude (above sea level) value in textbox1 and convert it into a ground level value displayed in textbox2. In this scenario, the GPS Altitude ...

Update nested child object in React without changing the original state

Exploring the realms of react and redux, I stumbled upon an intriguing challenge - an object nested within an array of child objects, complete with their own arrays. const initialState = { sum: 0, denomGroups: [ { coins: [ ...

the scroll feature is malfunctioning within the AngularJS div container

In the process of developing a platform, I have integrated Angular.js as the framework. However, when adding my custom HTML code to the homepage, it seems to be causing issues with the existing codebase. Can someone please review the code and point out any ...

Monaco Editor: Module 'monaco-editor' is missing despite being successfully installed

During the development of my desktop application with electron, I encountered an issue with installing Monaco Editor. After using npm install monaco-editor, running the application resulted in a message saying Cannot find module 'monaco-editor'. ...

The resolution of Angular 8 resolver remains unresolved

I tried using console.log in both the constructor and ngOnInit() of Resolver but for some reason, they are not being logged. resolve:{serverResolver:ServerResolverDynamicDataService}}, console.log("ServerResolverDynamicDataService constructor"); console ...

Searching for a specific row of data by ID in a massive CSV file using Node.js

Can someone recommend an npm package that is ideal for iterating over a csv file, locating a specific value, and updating/appending to that particular row? I don't have any code to display at the moment as I'm in the process of testing different ...

What is the correct method for sending data through a POST request to a PHP script?

UPDATE: I made a mistake while trying to debug the issue. Instead of correctly debugging the AJAX POST request, I was double-clicking the .php file in the Network tab and assuming it was sending the same headers as the actual ajax POST request. This led me ...