The color of the SVG is not visible in the PNG rendition

I have applied a style to an svg image and successfully changed the fill color using a random colors function in JavaScript. However, when I convert the svg to a png format after making these color changes, the PNG file retains the original colors instead of the updated ones.

<style type="text/css">
:root{
    --back:#662D91;
    --shadow:0.28;
    --highlight:#F3B4AE;
    --stomach:#EA8A82;
    --lightHigh:#FEE9E5;
    --lasso:#9B5D12;
    --gloves:#29A6DE;--glovesStroke:#000674;--gloves2:#29A6DE;--gloves3:#1C7FC9;--gloves4:#1D7DC6;--gloves5:#1C7DC4;
    --hatBelow:#DB8556;
    --hatBelow2:#8A3C13;
    --hatInner:#8C4017;
    --hatInner2:#934A24;
    --hatInner3:#9D5C3A;
    --stripe:#8A7454;
    --stripeEnd:#382000;

}
    .st0{fill:var(--back);}
    .st1{opacity:var(--shadow);}
    .st2{fill:var(--highlight);}
    .st3{fill:var(--stomach);}
    .st4{fill:var(--lightHigh);}

    (other CSS styles omitted for brevity)
</style>

This is the style element within my svg that I am modifying with the following code:

  root.style.setProperty('--back',colors[0]);

The 'colors' variable contains an array of randomly generated colors created by a script embedded within the svg. Can someone please assist me with resolving this issue?

Here is how I am converting the svg to png:

<script>
var svgString = new XMLSerializer().serializeToString(document.querySelector('svg'));
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var DOMURL = self.URL||self.webkitURL||self;
var img = new Image();
var svg = new Blob([svgString],{type: "image/svg+xml;charset=utf-8"});
var url = DOMURL.createObjectURL(svg);
img.onload = function(){
ctx.drawImage(img,0,0);
var png = canvas.toDataURL("image/png");
document.querySelector('#png-container').innerHTML = '<img src="'+png+'"/>';
DOMURL.revokeObjectURL(png);
};
img.src = url;
</script>

Answer №1

Upon further reflection, it became clear why the original approach didn't work as expected. The svg blob is limited to only include contents within the svg tag itself, meaning any CSS variables set on the html tag outside of it are not recognized. The styles defined with :root are scoped within the SVG, causing a disconnect when removed from the HTML context, leading :root to reference the svg tag instead.

The reason for this behavior remains ambiguous, but in cases involving canvas, CSS variables set on ancestor elements of the svg tag tend to be disregarded. To rectify this issue, one can apply inline styles directly to either the svg tag or its child elements.

Below is an adjusted version with a solution implemented. Disregard any modifications made to the JS code; it replicates the same functionality while setting the CSS variable on the svg tag rather than the html tag.

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>SVG thingy</title>
  </head>
  <body>
    <svg
      viewBox="0 0 10 10"
      xmlns="http://www.w3.org/2000/svg"
    >
      <style>
        :root {
          --color: red;
        }

        circle {
          fill: var(--color);
        }
      </style>

      <circle
        cx="5"
        cy="5"
        r="4"
      />
    </svg>

    <canvas></canvas>

    <div id="png-container"></div>

    <script>
      const root = document.documentElement; // html tag
      // root.style.setProperty('--color', 'black'); // Doesn't work

      const svgElement = document.querySelector('svg');
      svgElement.style.setProperty('--color', 'black'); // Works
      
      const svgString = new XMLSerializer().serializeToString(document.querySelector('svg'));
      const svgBlob = new Blob([svgElement.outerHTML], { type: 'image/svg+xml;charset=utf-8' });
      const url = URL.createObjectURL(svgBlob);
      
      const canvasElement = document.querySelector('canvas');
      const ctx = canvasElement.getContext('2d');
      
      const img = new Image();
      img.src = url;
      img.onload = () => {
        ctx.drawImage(img, 0, 0);
        const png = canvasElement.toDataURL('image/png');
        document.querySelector('#png-container').innerHTML = '<img src="' + png + '"/>';
        URL.revokeObjectURL(png);
      };
    </script>
  </body>
</html>

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

Using Thymeleaf to display <TR> elements according to specific conditions

Is there a cleaner way to show content only if one object is not null? No annotations found in this block of code. Here is the template: <div th:if="${currentSkills != null}"> <tr ><!-- Data File --> <td class="col_id"> ...

Activate fullscreen mode in Krpano on desktop by clicking a button

Is there a way to activate fullscreen mode upon clicking a button? I believe I should use the code: krpano.set(fullscreen,true); Currently, I have an image within a slideshow that includes a play button overlay. Once the button is clicked, the slideshow ...

The replacer argument of the JSON.stringify method doesn't seem to work properly when dealing with nested objects

My dilemma is sending a simplified version of an object to the server. { "fullName": "Don Corleone", "actor": { "actorId": 2, "name": "Marlon", "surname": "Brando", "description": "Marlon Brando is widely considered the greatest movie actor of a ...

Using JSP to send variables from an external Javascript file

After creating a timer function, I am looking to display the results on a different page. The setup involves a JSP file calling functions from a separate JS file in order to output the information to another screen: Instructions in the JSP file: <butt ...

Choose a date range from the date picker

I am currently attempting to combine two dates using a rangepicker. Below is the command used to select the date: Cypress.Commands.add('setDatePickerDate', (selector, date) => { const monthsShort = [ 'janv.', 'févr.& ...

Using Event Delegation in Practice

I am facing an issue with loading 2 <span> elements from separate ajax scripts onto a webpage upon selection from a dropdown box. Here is a snippet of my code: <span id='room_rate'>1,000</span> // content loaded by one ajax scri ...

Tips for sending an Ajax request to a separate URL on the same server

When making an ajax request to my server, I use the following code: var data = ''; $.ajax({ type: 'GET', url: 'api/getnews/home/post/'+title, data: data, datatype: 'json', success: f ...

Wrapping is disabled for all elements within the container div that contains three additional div elements

I am trying to prevent one of the three divs inside a fixed top navbar container from sliding underneath another, causing the navbar to become taller. The code below is using Bootstrap and the issue is with the navbar-header div sliding underneath the he ...

Renaming the month in Material-UI React

Using DatePicker from Material Ui, I am trying to change the name of the month. How can this be achieved? For instance, I need to change August to Avqust or March to Mart enter image description here This is my code: <LocalizationProvider ...

Capturing Screenshots with Ionic Framework

I am currently working on an Ionic application that utilizes geolocation via the Google API. However, I am facing a challenge with implementing a feature where a button in the upper right corner should take a screenshot and trigger a popover with options t ...

Enhance the appearance of the standard black rectangle displaying the messages "No video source" or "No video permissions"

Is there a way to change the styling of the video element that appears as a black rectangle with a strikethrough play button when the user is prompted for permission on Safari? Does it have a specific ID, class, or tag that can be targeted? I'm curre ...

Assistance with jQuery in Javascript is needed

Currently, I am in search of an effective vertical text scroller. My desired scroller would move vertically in a continuous manner, ensuring there is never any empty space while waiting for the next text to appear. I am open to using either JavaScript or ...

There seems to be a hiccup in the distribution build of Angular grunt, as it is unable to locate the

While testing the build, everything runs smoothly. However, when attempting to build the distribution, an error is encountered: An error occurred: Cannot find module '/Users/matt.sich/Documents/angularProjects/firstProject/node_modules/grunt-usemin/l ...

Razzle fails to initiate the server

After creating my React project with Razzle.js and downloading it from a repository, I encountered an issue when trying to run it. Upon running yarn start, the screen gets stuck at a message saying the source is compiled and server is running on localhost: ...

"Enhance Your Highchart Experience by Adding Hyperlinks to Every Segment of Your Stacked Bar

I am seeking to assign a specific link to each segment of a stacked 100% bar chart. Check out this demo of a stacked bar chart: Here's what I am trying to accomplish: Please visit , input data in the left table, and submit it. After submission, you ...

Navigating through each element of an array individually by using the onClick function in React

I'm currently working on a project that involves creating a button to cycle through different themes when pressed. The goal is for the button to display each theme in sequence and loop back to the beginning after reaching the last one. I've imple ...

Encountering this issue: Unable to access the property 'length' of an undefined variable

I'm currently developing an app using nuxt, vuetify 2, and typescript. Within the app, I have radio buttons (referred to as b1 and b2) and text fields (referred to as t1, t2, t3). When a user clicks on b1, it displays t1 and t3. On the other hand, w ...

An error notification received from the command "jspm install jquery"

As I follow the tutorial on the jspm.io site, everything goes smoothly until I reach step 3. When I try to execute jspm install jquery, an error message pops up. The error reads: warn Error on getOverride for jspm:github, retrying (2). ReferenceError: ui ...

Creating a material texture with file api in three.js is a straightforward process

I have a vision to create a cutting-edge model browser that allows users to handpick models and textures themselves. In order to achieve this, I am utilizing the File API for smooth file handling. My approach involves using two separate file inputs for rec ...

Implementing a confirmation dialog for POST requests in Flask

My first experience with Flask involves adding a confirmation dialog to a form, but only under specific conditions. Unfortunately, I'm unable to achieve this on the client side. While I was successful in implementing it for GET requests, POST requests ...