Executing OpenLayers synchronously using promise/await within a serverless Vue application

I am working on writing a for loop that updates the parameters of an OpenLayers map during each iteration. Once the map is fully rendered, I need to extract the context of the map canvas and add it to a GIF object. It is important that these actions occur synchronously to ensure proper rendering of the map and layers before adding the context. Currently, I have been using a setInterval workaround, but after reading through this informative post, I understand that utilizing async/await/Promises would be a better approach. My main concern is how to wrap my functions in a Promise to guarantee sequential execution while still maintaining access to the Vue app context (this).

The structure of my for loop would resemble:

for(let i = 0 ; i < this.dateArraySurface10.length - 1 ; i++)
{
    waterfall([
        this.setTimeSurface10(),
        this.map.renderSync(),
        this.myCallback(),
    ],    
    function(err){
        console.log("Waterfall error : ",err);
    });
}

The functions used in the loop are as follows:

setTimeSurface10: function () {
    if (this.currentTimeSurface10 === null) {
        this.currentTimeSurface10 = this.startTimeSurface10;
    } else if (this.currentTimeSurface10 >= this.endTimeSurface10) {
        this.currentTimeSurface10 = this.startTimeSurface10;
    } else {
        this.currentTimeSurface10 = new Date(
            this.currentTimeSurface10.setMinutes(this.currentTimeSurface10.getMinutes() + 60)
        );
    }
    this.surface10.getSource().updateParams({ TIME: this.currentTimeSurface10.toISOString().split(".")[0] + "Z" });
},
myCallback: function () {
    const mapCanvas = document.createElement('canvas');
    const divElement = document.querySelector(".map");
    mapCanvas.width = divElement.offsetWidth;//size[0];
    mapCanvas.height = divElement.offsetHeight;//size[1];
    const mapContext = mapCanvas.getContext('2d');
    Array.prototype.forEach.call(
        document.querySelectorAll('.ol-layer canvas'),
        function (canvas) {
            if (canvas.width > 0) {
                const opacity = canvas.parentNode.style.opacity;
                mapContext.globalAlpha = opacity === '' ? 1 : Number(opacity);
                const transform = canvas.style.transform;
                const matrix = transform
                                        .match(/^matrix\(([^\(]*)\)$/)[1]
                                        .split(',')
                                        .map(Number);
                CanvasRenderingContext2D.prototype.setTransform.apply(mapContext,matrix);
                mapContext.drawImage(canvas, 0, 0);
            }
        }
    );
    this.gif.addFrame(mapCanvas, {copy:true, delay: 200});
}

Answer №1

Special thanks to the assistance from Mr. Johnson at Leaflet (whom I highly recommend supporting on Github Sponsor) for providing a solution that may interest some readers.

async convertMapToCanvasList() {
    for(let i = 0 ; i < this.surfaceArray.length - 1 ; i++)
    {
        this.configureSurface();
        await new Promise(resolve => this.map.once('rendercomplete', resolve));
        this.handleCallback();
    }
    this.gif.on('processed', function(blob) {
        window.open(URL.createObjectURL(blob));
    });
    this.gif.generate();
},
handleCallback: function () {
    const mapCanvas = document.createElement('canvas');
    const containerElement = document.querySelector(".container-map");
    mapCanvas.width = containerElement.offsetWidth;
    mapCanvas.height = containerElement.offsetHeight;
    const context = mapCanvas.getContext('2d');
    Array.prototype.forEach.call(
        document.querySelectorAll('.leaflet-layer canvas'),
        function (canvas) {
            if (canvas.width > 0) {
                const opacity = canvas.parentNode.style.opacity;
                context.globalAlpha = opacity === '' ? 1 : Number(opacity);
                const transform = canvas.style.transform;
                const matrix = transform
                                        .match(/^matrix\(([^\(]*)\)$/)[1]
                                        .split(',')
                                        .map(Number);
                CanvasRenderingContext2D.prototype.setTransform.apply(context,matrix);
                context.drawImage(canvas, 0, 0);
            }
        }
    );
    this.gif.addFrame(mapCanvas, {copy:true, delay: 200});
},

The method above illustrates how making the entire process asynchronous and incorporating an await promise for the rendercomplete event guarantees that the loop pauses and executes the callback function to add the rendered context as a frame to the GIF object.

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

Tips for adding additional text to c3.js Regions

Is there a way to add text to c3.js regions? I've set up three specific regions in my chart and I'd like to attach unique text labels to each of them. My attempts with d3.js have not been successful. var rectOffset = (( d3.select(this).attr("x") ...

Searching for partial nodes

I came across a helpful tutorial that explains how to perform a partial search. My goal is to have it so that when someone enters the text geor, it can locate a user named george. db.stores.find({storeName : {$regex : /Geor/}}).pretty() However, I am str ...

Troubleshooting issue with jQuery animate not correctly scrolling

I am experiencing an issue with my jQuery code that is supposed to scroll a smaller container element within a larger container element when a button is clicked. Despite testing with an alert and verifying that the code is working, the scrolling functional ...

Connecting to another page based on data list selection

I have created a datalist with multiple options and now I want to redirect to another page when one of the options is selected. Here is my initial attempt where I tried to directly add a hyperlink to the option label, but it didn't work as expected. ...

There seems to be a hiccup in the JavaScript Console. It could potentially impact the functionality

Hey there, I'm encountering a strange issue in my IE 11 console. A JavaScript Console error has occurred. This may impact functionality. Whenever I try to run a for loop to create a list of elements within a ul tag 4000 times, the process stops at ...

Dynamically extract key values from JSON data and display them on an HTML page with checkboxes for selection. Generate a new JSON object containing

I am facing the challenge of parsing an unknown JSON with uncertain key-value pairs. As I do not have prior knowledge of the keys to access, my goal is to traverse through every key in the JSON and display all keys and their corresponding values on the scr ...

Discovering identical objects by property and combining them with the help of JavaScript or UnderscoreJS

Below is an array that I have: var somevalue = [{ code: 1, name: 'a1' }, { code: 2, name: 'b1' }, { code: 1, name: 'a2' }, { code: 1, name: 'a3' }, { code: 2, name ...

Trouble encountered with card flip style login form in Vue.js, as the card is not maintaining its position properly during transition animations

Need help styling a login/signup component in Vue.js where flipping between the two cards isn't working smoothly. The transition is causing one card to move down and right while the other comes in from the bottom right. It's hard to explain the i ...

Retrieve the nearest identifier text from the tables

I have a table on my webpage with some data: <tbody id="carga"> <tr> <td>1</td> <td id="nombre">esteban</td> <td id="apellido">aguirre</td> <td>N/A</td> <td>N/A</td ...

Deleting multiple rows with checkboxes in Laravel 5.5 using Vue.js and Axios

I am currently working on implementing a feature that allows the deletion of multiple items using checkboxes. My tech stack includes Laravel 5.5, Vue.js, and Bulma's Buefy components along with Axios for handling HTTP requests. Here is my Vue.js Comp ...

What are the steps to transforming a regular expression into a dynamic format?

I've developed a powerful regex that locates specific text within a lengthy string without spaces. Now I'm attempting to utilize it dynamically to search for various words, but I can't seem to make it function as intended. Check out my rege ...

Issues with finding your way

Whenever I am in the History.js file and click on a product list item to navigate to another page for more details and contact the seller, the issue arises. When I click on an item in History.js, nothing happens on that page. However, when I switch to Home ...

Error: Laravel mix compilation - unable to locate class

After upgrading from Laravel 5.3 to 5.4, I am currently in the process of transitioning to webpack. Although it compiles without errors, whenever I try to load the page, I always encounter: app.a711192….js:125 Uncaught ReferenceError: Layout is not def ...

Ensure that your JQuery code only runs after Angular has completed its rendering

As a newcomer to Angular JS, I may have a question that seems silly. Despite seeing it discussed in several SO questions, I still couldn't figure it out. My goal seems simple, yet I've had a tough time achieving it. I'm attempting to execut ...

What is the process for creating a button that can sort an array and count its elements?

I am having trouble creating a code that can sort products into alphabetical order and then count the number of items in the list within the same program. I have managed to write separate programs that achieve each of these tasks individually, but when I ...

The controller is providing a null response following an ajax Post request

I am having trouble with my ajax Post request targeting the edit action method in my controller. The issue is that none of the values are being populated, they all come back as null. What should be happening is that when the '.save-user' button ...

Developing distinct state values for assigned objects

I developed a star rating component using Material UI components that is based on a mapped object. However, I am facing an issue where all the star ratings show the same value when clicked. How can I ensure that each star section displays its own value bas ...

Struggling to spot my error (codewars, javascript, level 8)

Can You Translate?! After receiving a message on WhatsApp from an unfamiliar number, you wonder if it's from the person with a foreign accent you met last night. Your task is to write a simple function that checks for various translations of the word ...

Guide to creating a new window without a menu bar for an onclick function in electronJS

After trying to remove the menu bar from the main window using win.setMenu(null) in the main.js file, I encountered a new issue. When opening a new window (referred to as the "add items window"), I struggled to find a way to hide the menu bar in it as well ...

Utilizing AJAX and javascript for extracting information from websites through screen scraping

Is it possible to scrape a screen using AJAX and JavaScript? I'm interested in scraping the following link: I tried the technique mentioned on w3schools.com, but encountered an "access denied" message. Can anyone help me understand why this error is ...