Strive to discover the ideal solution for capturing a screenshot of an OpenLayers map using html2canvas. Currently, the map elements are losing their CSS classes and images are not

Seeking advice on the best solution for working with html2canvas and css. I'm trying to take a screenshot of a map that includes various elements, but after capturing the image, all the css classes are lost and the images are not rendered properly.

Some approaches I've attempted include reloading the map div using javascript/jquery, reloading stylesheets, and moving css classes from "myFile.css" to the html document.

However, these methods have proven to be ineffective for my needs.

One promising method involves moving the cssText to the style attribute of elements, which worked well. However, manually extracting and rewriting all elements and their children from the div seems inefficient and not ideal.

Answer №1

The issue arose from using SVG images, requiring the use of XMLSerializer(). It seems that html2canvas may encounter difficulties with PrimeFaces layouts at times, and problems with CSS can be resolved by importNode. Here is a solution that worked for me:

// Make sure to include all necessary JS libraries and files in the HTML page

//targetElem - ID of the map element, such as $('#map')
function screenshotMap(targetElem) {

var nodesToRecover = [];
var svgElem = targetElem.find('svg');
var serializer = new XMLSerializer();

//screenshotAreaId - ID of the north layoutUnit where the screen capture will be displayed
var oldNode = document.getElementById("screenshotAreaId");

//Convert all SVG elements to canvas, storing them in an array for later conversion back to SVG
svgElem.each(function (index, node) {

    var parentNode = node.parentNode;
    //Skip nested SVGs within parent SVGs, as canvg will handle the parent SVG
    if(parentNode.tagName != 'DIV'){
    return true;
    }
    var canvas = document.createElement('canvas');
    var svg = parentNode.querySelector('svg');
    var svgString = serializer.serializeToString(svg);

    //Using the canvg library
    canvg(canvas, svgString);

    nodesToRecover.push({
        parent: parentNode,
        child: node
    });

    parentNode.removeChild(node);
    parentNode.appendChild(canvas);
});

//Using the html2canvas library to create a screenshot of the map and download it
html2canvas(targetElem, {
    onrendered: function (canvas) {
        var img = canvas.toDataURL('image/png').replace("image/png",  "image/octet-stream");
        window.location.href = img;

        //Removing the canvas and converting back to SVG
        var canvasElem = targetElem.find('canvas');
        canvasElem.each(function (index, node) {
            var parentNode = node.parentNode;
            parentNode.removeChild(node);
            parentNode.appendChild(nodesToRecover[index].child);
        });

        //Updating the layoutUnit if there are CSS issues
        var newNode = document.importNode(oldNode, true);
        document.getElementById("layout").appendChild(newNode);
    }
});
}

You can find the canvg library here: https://github.com/gabelerner/canvg

You can find the html2canvas library here:

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

When manipulating an array in JavaScript, the final count is wrong and there is an unexpected object

When I click this button, the addToCart function is invoked which dispatches an action to the reducer to add an item to the cart. The goal is to store only one instance of a specific item and increment the amount if the same item is added again. case &apo ...

Unlocking the potential of data inputted in a JQuery Autocomplete form

Seeking assistance with extracting data from a form to utilize for additional purposes <form onsubmit="return false;"> Enter a School: <input id="schoolsearch" type="text" /> <INPUT TYPE=SUBMIT VALUE="GO"> </form> I am struggling ...

Angular and JS do not have the functionality to toggle the split button

I have a question that seems similar to others I've seen, but I haven't found a solution yet. Can someone please review my code? In the component, I have {{$ctrl.init}} and {{$ctrl.people}} assigned. I am sure this assignment is correct because ...

Having trouble troubleshooting the jQuery button

When I click this button, it triggers an ajax call that updates the score_up value. I can't seem to figure out what's wrong. I attempted using Firebug, but it doesn't detect the JavaScript. Any help would be appreciated! Here is the jQuery ...

AngularJS - Showcase a dynamic list of information according to the value chosen

Seeking assistance from anyone willing. I have data in JSON format structured like this { state1: [ member1, member2], state2: [ member3,member4...], ... } There is a dropdown that displays the states listed in the JSON data. When a state is selected, I ...

Unable to pass several parameters to a Component

I'm attempting to send three URL parameters to a React Component. This is my approach: App.js: <Route path="/details/:id(/:query)(/:type)" handler={DishDetails}/> DishDetails.js: class DishDetails extends Component { constructor(props) { ...

What could be causing the issue with object-fit not functioning properly within a container with a max

My goal is to insert a video into a container that has a width of 100% and automatically adjusts its height while maintaining the aspect ratio, but with a maximum height set. I want the video to completely fill the container even if some parts are cropped ...

`Arranging Widget Boxes in a Vertical Layout`

I am currently displaying each record with two boxes for Afternoon and Night horizontally: https://i.stack.imgur.com/JMKug.png This is the code structure I am using to achieve this layout: <div id="record_box"> <div class="row" style="paddi ...

Position the Material-UI AppBar and Tab on the far right of the screen

I am trying to achieve a specific layout where the Links for "Homepage Login Settings and etc.." are placed at the right edge of the AppBar, while keeping the "Website" aligned to the left edge of the screen. Here is what I have: https://i.sstatic.net/Wvo ...

Having difficulty adjusting the width of the CSS menu bar to fit the entire page

I found a useful CSS menu tutorial online that seems to work well, but unfortunately, it doesn't stretch the full width of the page. You can check out the tutorial here: Even after trying to set the width to 100%, the menu still falls short of extend ...

Error message: Uncaught TypeError - Unable to retrieve data using POST method in react with node and express servers

I am currently working on creating a Login / Register form using react for the client-side and node / express / (mongo) for the backend. The backend functionality is working smoothly as expected, with successful storage of credentials in the database upon ...

There seems to be an issue with the Url.Action method as it

I'm working with this script: $(function() { $.support.cors = true; jQuery.support.cors = true; $.ajax({ crossDomain: true, type: 'GET', url: 'http://example.com/WCFRESTService.svc/GetCategories&apos ...

Functionality limited to Firefox browser

I'm having some trouble with my website development in HTML5 and CSS3. Specifically, I am struggling to get my processing sketch to work on browsers other than Firefox. Below is the code I am working with: <!DOCTYPE html> <html> ...

The function $.ajax may not be available, but rest assured that the jquery library is functioning properly

Upon checking the console, I noticed the following: Here is the AJAX code snippet in use: $("#accept").click(function(){ id = $("#idInput").val(); password = $("#passwordInput").val(); alert(id) alert(password) $.aja ...

npm-bundle encounters an issue with Error: ENOENT when it cannot find the file or directory specified as 'package.json'

npm-bundle is throwing an error that says Error: ENOENT: no such file or directory, open 'package.json' in my NodeJs project. It works fine if I manually create test.js and package.json, then run npm install followed by npm-bundle. However, when ...

Is the accuracy of Chrome's inspect device not up to par?

I'm currently testing how the page appears on a 1366x768 laptop. When inspected in the device, it looks perfect: However, on the actual laptop screen, it's completely off: It's so frustrating because I mainly work on a large screen and ca ...

Utilizing prerender.io with lazy loading in Angular 2: A comprehensive guide

As Angular Universal is not expected to be included in the CLI for some time, I've had to resort to using prerender.io in order to ensure proper SEO functionality. However, my tests have shown that there are issues with lazy loaded modules causing SEO ...

Flexbox: Arrange header and footer in a sidebar layout using flexbox styling

In my content layout, I have structured the sections as header, content, and footer. While I want to maintain this order for small devices, I am looking to shift the header and footer to the sidebar on desktop. I have already implemented this using floats ...

Is it possible to create an input field exclusively for tags using only CSS?

I am currently facing some limitations with a website I am managing. Unfortunately, I do not have the ability to incorporate additional libraries such as custom jQuery or JavaScript scripts. My goal is to customize an input field for tags so that when us ...

"Is it possible to selectively load only a few images on a website that contains numerous

My website displays numerous images hosted on a server. Each page contains a maximum of 100 images, each within its own div element. At any given moment, only one div is visible due to the CSS "display" property, while the others are hidden using display:n ...