-I want to draw the same SVG
onto a canvas
multiple times, but each time I want to PROGRAMMATICALLY change the colors of specific classes within that SVG
.
For example take this house image below:
The SVG for this House has the following classes:
<style>
.window-class {
fill: lime;
}
.door-class {
fill: blue;
}
.house-class {
fill: tan;
}
.roof-class {
fill: red;
}
</style>
How do I programmatically access these specific Style-Classes so I can change their color values for each new house that I draw?
I’m constructing the SVG
by creating an Image object and then drawing that image onto a canvas
using the following code:
// 1. Create the CANVAS and the CONTEXT:
var theCanvas = document.getElementById("theCanvas");
var theContext = theCanvas.getContext("2d");
theContext.fillStyle = "lightblue";
theContext.fillRect(0, 0, theCanvas.width, theCanvas.height);
// 2. Define the SVG data:
var imageData = '<svg id="HOUSE" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" width="240.26" height="311.24" viewBox="0 0 240.26 311.24"><defs><style>.house-class {fill: tan;}.roof-class {fill: red;}.roof-class, .window-class, .door-class {stroke: #000;stroke-miterlimit: 10;}.window-class {fill: lime;}.door-class {fill: blue;}</style></defs><g id="House"><rect class="house-class" x="30.08" y="131.74" width="173.07" height="179"/><path d="M270,242V420H98V242H270m1-1H97V421H271V241Z" transform="translate(-67.39 -109.76)"/></g><polygon id="Roof" class="roof-class" points="1.11 131.74 239.11 131.74 117.11 0.74 1.11 131.74"/><rect id="Window2" class="window-class" x="145.11" y="160.74" width="30" height="42"/><rect id="Window1" class="window-class" x="58.61" y="160.74" width="30" height="42"/><rect id="Door" class="door-class" x="92.11" y="228.74" width="52" height="82"/></svg>';
var DOMURL = window.URL || window.webkitURL || window;
var img = new Image();
var svg = new Blob([imageData], { type: 'image/svg+xml;charset=utf-8' });
var url = DOMURL.createObjectURL(svg);
img.onload = function () {
theContext.drawImage(img, 0, 0);
DOMURL.revokeObjectURL(url);
}
img.src = url;
Ordinarily I'd be able to get at the specific Classes who's colors I want to change by using this:
let nodeList = document.getElementsByClassName("window-class");
And then I would iterate through that nodeList
and at each element I find that is styled with this window-class
, I would do:
element.style.fill = -whatever-the-next-color-would-be-;
But since I'm creating my image in the manner I showed above, I'm not sure how I can get at specific classes of its SVG
.
Any thoughts?
==============================
UPDATE:
It was pointed out that the code for drawing the image/SVG multiple times wasn't included, so here it is:
// GLOBAL VARIABLES:
const TOTAL_IMAGES = 3; // could be 30, or 300
const canvasWidth = 250;
const canvasHeight = 320;
var canvasX, canvasY = 0;
// COLOR VARIABLES:
var colorCounter = 0;
let houseColorsArray = ["fuchsia", "gold", "lighblue"]; // Will have lots more colors for all of these
let windowColorsArray = ["yellow", "pink", "lightgreen"];
let roofColorsArray = ["maroon", "crimson", "darkred"];
let doorColorsArray = ["darkBlue", "purple", "darkslategray"];
// CLASS-NAMES
let classNamesToPaintArray = [".house-class", ".door-class", ".window-class", ".roof-class"];
function designOneHouse(theCanvas) {
console.log("\n\n==========================\n=");
console.log("= =>>In 'designOneHouse()'!\n");
// 1. Create a Color-Scheme:
let houseColor = houseColorsArray[colorCounter];
let doorColor = doorColorsArray[colorCounter];
let windowColor = windowColorsArray[colorCounter];
let roofColor = roofColorsArray[colorCounter];
console.log(" ->Current 'houseColor' = ", houseColor);
console.log(" ->Current 'doorColor' = ", doorColor);
console.log(" ->Current 'windowColor' = ", windowColor);
console.log(" ->Current 'roofColor' = ", roofColor);
let context = theCanvas.getContext("2d");
// Iterate the ColorCounter - making sure we don't overflow the ColorsArrays:
colorCounter++;
if(colorCounter == houseColorsArray.length) {
colorCounter = 0;
}
// Now GET-AT and PAINT the Individual SVG Components.
// STRATEGY:
// 1. Iterate through the Array containing all the CLASS-NAMES who's color I want to change.
// 2. For each of these classes, I'll need to iterate through all the HTML elements that are OF that class type
// (there may be like 10 elements that are all styled by the same Style; I want all of them to be updated!)
//
for(classNameCounter = 0; classNameCounter < classNamesToPaintArray.length; classNameCounter++) {
let currentClassName = classNamesToPaintArray[classNameCounter];
console.log("currentClassName = " + currentClassName);
let nodeList = document.getElementsByClassName(currentClassName);
console.log("nodeList = " + nodeList);
console.log("nodeList LENGTH = " + nodeList.length);
for(var counter = 0; counter < nodeList.length; counter++) {
console.log("\n\n===>>IN FOR LOOP -- Node-COUNTER = " + counter);
let currentNode = nodeList[counter];
console.dir(" > 'childNodes[0]' of 'currentNode' = ");
console.dir(currentNode.childNodes[0]);
let elements = document.querySelectorAll(".door-class");
// Change the text of multiple elements with a loop
elements.forEach(element => {
element.style.fill = "pink";
});
}
}
}
function makeCanvasGrid() {
console.log("\n\n====>In 'makeCanvasGrid()'!\n");
for(var canvasCounter = 0; canvasCounter < TOTAL_IMAGES; canvasCounter++) {
console.log("\n >FOR LOOP - canvasCounter = " + canvasCounter);
// 1. Create a new Canvas Object:
let newCanvas = document.createElement("canvas");
newCanvas.setAttribute("width", canvasWidth);
newCanvas.setAttribute("height", canvasHeight);
newCanvas.setAttribute("id", "newCanvas" + canvasCounter);
// Log-out just to verify the "id" property was set correctly:
console.log(" >newCanvas.id = " + newCanvas.id);
// 2. Place the Canvas at (x,y) (top, left) coordinates:
newCanvas.style.position = "absolute";
newCanvas.style.left = canvasX; //"100px";
newCanvas.style.top = canvasY; //"100px";
designOneHouse(newCanvas);
// Check the current Canvas' (X, Y) coords, and if needed, reset X to 0 and SKIP to the next "ROW" of Canvasses:
if(canvasCounter > 0 && canvasCounter % 3 == 0) {
console.log(" >>NEXT ROW PLEASE!!!! canvasCount = ", canvasCounter);
canvasX = 0;
canvasY += canvasHeight + 20;
}
else {
canvasX += canvasWidth + 10;
}
}
}
makeCanvasGrid();
SO when I run this right now, the console shows me the nodeList
is empty:
nodeList LENGTH = 0
So basically this statement isn't working:
let nodeList = document.getElementsByClassName(currentClassName);