在运行时以编程方式更改 SVG 类
Programmatically change SVG classes during runtime
-我想多次将 相同的 SVG
绘制到 canvas
上,但每次我都想以编程方式更改特定 类 里面 SVG
.
例如下面这张房子的图片:
这个房子的 SVG 有以下 类:
<style>
.window-class {
fill: lime;
}
.door-class {
fill: blue;
}
.house-class {
fill: tan;
}
.roof-class {
fill: red;
}
</style>
如何以编程方式访问这些特定样式-类以便我可以为我绘制的每个新房子更改它们的颜色值?
我正在构建 SVG
,方法是创建一个 Image 对象,然后使用以下代码将该图像绘制到 canvas
上:
// 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;
通常情况下,我可以通过以下方式获得我想要更改的特定 类 谁的颜色:
let nodeList = document.getElementsByClassName("window-class");
然后我会遍历那个 nodeList
并且在我发现每个元素都用这个 window-class
设置样式时,我会这样做:
element.style.fill = -whatever-the-next-color-would-be-;
但是由于我是按照上面显示的方式创建我的图像,所以我不确定如何获得其 SVG
的特定 类。
有什么想法吗?
================================
更新:
指出多次绘制image/SVG的代码没有包含,所以这里是:
// 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();
所以当我现在 运行 时,控制台显示 nodeList
是空的:
nodeList LENGTH = 0
所以基本上这个语句是行不通的:
let nodeList = document.getElementsByClassName(currentClassName);
以下是产生您想要的结果的一种方法。
- 下面的方法将 HTML 中的
<svg>
元素用作模板。该模板被克隆、应用颜色、转换为图像并放置到每个有颜色的房子的 canvas 中。
- 注意:SVG 的结构发生了变化。
class
属性替换为自定义 data-
属性 data-part
,用于通过普通 CSS 选择器应用填充样式。
- 每个房子的坐标位置在一个数组中 space 分隔
x y
坐标。该数组还表示要绘制多少个房子
- 房子 'parts' 的颜色包含在列出房子 'part' 及其相应颜色的对象中(颜色的数量应与房子的数量相匹配)
- 所有
<canvas>
CSS 已移至样式表。
我会让你处理 canvas 上的图像大小。
const canvas = document.querySelector('canvas');
const context = canvas.getContext("2d");
const housePositions = ["0 10", "85 10", "170 10"];
const parts = {
House: ["fuchsia", "gold", "lightblue"],
Window: ["yellow", "pink", "lightgreen"],
Roof: ["maroon", "crimson", "darkred"],
Door: ["darkBlue", "purple", "darkslategray"]
};
function addHouse(colorIndex, x, y) {
let clonedSvgElement = document.querySelector('svg').cloneNode(true);
Object.keys(parts)
.forEach(part => {
clonedSvgElement.querySelectorAll(`[data-part=${part}]`)
.forEach(item => {
item.style.fill = parts[part][colorIndex];
});
const blob = new Blob([clonedSvgElement.outerHTML], { type: 'image/svg+xml;charset=utf-8' });
const blobURL = URL.createObjectURL(blob);
const image = new Image();
image.onload = () => {
context.drawImage(image, x, y, 130, 110);
URL.revokeObjectURL(this.src);
};
image.src = blobURL;
});
}
housePositions.forEach((coordString, index) => {
const [x, y] = coordString.split(' ');
addHouse(index, x, y);
});
canvas {
position: absolute;
left: 10px;
top: 10px;
width: 150px;
height: 80px;
border: 1px solid;
background-color: lightblue;
}
svg {
display: none;
}
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="index.css">
<title>Document</title>
<script defer src="index.js"></script>
</head>
<body>
<canvas></canvas>
<svg id="HOUSE" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" width="140" height="140" viewBox="0 0 240.26 311.24"><defs></defs><g id="House"><rect data-part="House" x="30.08" y="131.74" width="173.07" height="179"/><path d="M270,242V420H98V242H270m1-1H97V421H271V241Z" transform="translate(-67.39 -109.76)"/></g><polygon data-part="Roof" points="1.11 131.74 239.11 131.74 117.11 0.74 1.11 131.74"/><rect data-part="Window" x="145.11" y="160.74" width="30" height="42"/><rect data-part="Window" x="58.61" y="160.74" width="30" height="42"/><rect data-part="Door" x="92.11" y="228.74" width="52" height="82"/></svg>
</body>
</html>
要操纵房子的 DOM,SVG 必须位于 DOM 中。所以我将 SVG 包裹在 <div>
中并隐藏了 div。我已经把它放在屏幕外了,但我可以用其他几种方式隐藏 div。
一旦你这样做了,你的下一个问题是你正在改变元素的 fill
,但是这将被你的 SVG 中的 CSS 覆盖。所以你必须删除那些 CSS 样式。
第三,您正在创建 canvas 个对象,但没有将它们附加到 DOM。
您还收到错误消息,因为 canvasX
未初始化。加上 CSS 长度 必须 有单位。所以你需要newCanvas.style.left = canvasX + "px"
等等
您还错误地查找了您的元素。 getElementsByClassName(".hose-class")
找不到任何东西。它需要 getElementsByClassName(".hose-class")
.
最后,我重写了元素查找和颜色分配代码。我已将每个配色方案捆绑到一个配色方案对象数组中。它使 类 到颜色的映射变得更加简单。
// GLOBAL VARIABLES:
const TOTAL_IMAGES = 3; // could be 30, or 300
const canvasWidth = 250;
const canvasHeight = 320;
var canvasX = 0, canvasY = 0;
// COLOR VARIABLES:
var colorCounter = 0;
let houseColorSchemes = [ {".house-class": "fuchsia",
".door-class": "darkblue",
".window-class": "yellow",
".roof-class": "maroon"},
{".house-class": "gold",
".door-class": "purple",
".window-class": "pink",
".roof-class": "crimson"},
{".house-class": "lightblue",
".door-class": "darkslategray",
".window-class": "lightgreen",
".roof-class": "darkred"} ];
// CLASS-NAMES
let classNamesToPaintArray = [".house-class", ".door-class", ".window-class", ".roof-class"];
// SVG template
let houseSVG = document.getElementById("HOUSE");
function designOneHouse(theCanvas) {
console.log("\n\n==========================\n=");
console.log("= =>>In 'designOneHouse()'!\n");
let context = theCanvas.getContext("2d");
// 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!)
//
let colorScheme = houseColorSchemes[colorCounter];
classNamesToPaintArray.forEach(className => {
let elements = houseSVG.querySelectorAll(className);
elements.forEach(element => element.style.fill = colorScheme[className]);
});
var imageData = houseSVG.outerHTML;
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 () {
context.drawImage(img, 0, 0);
DOMURL.revokeObjectURL(url);
}
img.src = url;
// Iterate the ColorCounter - making sure we don't overflow the ColorsArrays:
colorCounter++;
if(colorCounter == houseColorSchemes.length) {
colorCounter = 0;
}
}
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 + "px"; //"100px";
newCanvas.style.top = canvasY + "px"; //"100px";
document.body.appendChild(newCanvas);
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();
#house-template {
position: absolute;
left: -1000px;
}
<div id="house-template">
<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>
.roof-class, .window-class, .door-class {stroke: #000;stroke-miterlimit: 10;}
</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>
</div>
-我想多次将 相同的 SVG
绘制到 canvas
上,但每次我都想以编程方式更改特定 类 里面 SVG
.
例如下面这张房子的图片:
这个房子的 SVG 有以下 类:
<style>
.window-class {
fill: lime;
}
.door-class {
fill: blue;
}
.house-class {
fill: tan;
}
.roof-class {
fill: red;
}
</style>
如何以编程方式访问这些特定样式-类以便我可以为我绘制的每个新房子更改它们的颜色值?
我正在构建 SVG
,方法是创建一个 Image 对象,然后使用以下代码将该图像绘制到 canvas
上:
// 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;
通常情况下,我可以通过以下方式获得我想要更改的特定 类 谁的颜色:
let nodeList = document.getElementsByClassName("window-class");
然后我会遍历那个 nodeList
并且在我发现每个元素都用这个 window-class
设置样式时,我会这样做:
element.style.fill = -whatever-the-next-color-would-be-;
但是由于我是按照上面显示的方式创建我的图像,所以我不确定如何获得其 SVG
的特定 类。
有什么想法吗?
================================
更新:
指出多次绘制image/SVG的代码没有包含,所以这里是:
// 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();
所以当我现在 运行 时,控制台显示 nodeList
是空的:
nodeList LENGTH = 0
所以基本上这个语句是行不通的:
let nodeList = document.getElementsByClassName(currentClassName);
以下是产生您想要的结果的一种方法。
- 下面的方法将 HTML 中的
<svg>
元素用作模板。该模板被克隆、应用颜色、转换为图像并放置到每个有颜色的房子的 canvas 中。- 注意:SVG 的结构发生了变化。
class
属性替换为自定义data-
属性data-part
,用于通过普通 CSS 选择器应用填充样式。
- 注意:SVG 的结构发生了变化。
- 每个房子的坐标位置在一个数组中 space 分隔
x y
坐标。该数组还表示要绘制多少个房子 - 房子 'parts' 的颜色包含在列出房子 'part' 及其相应颜色的对象中(颜色的数量应与房子的数量相匹配)
- 所有
<canvas>
CSS 已移至样式表。
我会让你处理 canvas 上的图像大小。
const canvas = document.querySelector('canvas');
const context = canvas.getContext("2d");
const housePositions = ["0 10", "85 10", "170 10"];
const parts = {
House: ["fuchsia", "gold", "lightblue"],
Window: ["yellow", "pink", "lightgreen"],
Roof: ["maroon", "crimson", "darkred"],
Door: ["darkBlue", "purple", "darkslategray"]
};
function addHouse(colorIndex, x, y) {
let clonedSvgElement = document.querySelector('svg').cloneNode(true);
Object.keys(parts)
.forEach(part => {
clonedSvgElement.querySelectorAll(`[data-part=${part}]`)
.forEach(item => {
item.style.fill = parts[part][colorIndex];
});
const blob = new Blob([clonedSvgElement.outerHTML], { type: 'image/svg+xml;charset=utf-8' });
const blobURL = URL.createObjectURL(blob);
const image = new Image();
image.onload = () => {
context.drawImage(image, x, y, 130, 110);
URL.revokeObjectURL(this.src);
};
image.src = blobURL;
});
}
housePositions.forEach((coordString, index) => {
const [x, y] = coordString.split(' ');
addHouse(index, x, y);
});
canvas {
position: absolute;
left: 10px;
top: 10px;
width: 150px;
height: 80px;
border: 1px solid;
background-color: lightblue;
}
svg {
display: none;
}
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="index.css">
<title>Document</title>
<script defer src="index.js"></script>
</head>
<body>
<canvas></canvas>
<svg id="HOUSE" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" width="140" height="140" viewBox="0 0 240.26 311.24"><defs></defs><g id="House"><rect data-part="House" x="30.08" y="131.74" width="173.07" height="179"/><path d="M270,242V420H98V242H270m1-1H97V421H271V241Z" transform="translate(-67.39 -109.76)"/></g><polygon data-part="Roof" points="1.11 131.74 239.11 131.74 117.11 0.74 1.11 131.74"/><rect data-part="Window" x="145.11" y="160.74" width="30" height="42"/><rect data-part="Window" x="58.61" y="160.74" width="30" height="42"/><rect data-part="Door" x="92.11" y="228.74" width="52" height="82"/></svg>
</body>
</html>
要操纵房子的 DOM,SVG 必须位于 DOM 中。所以我将 SVG 包裹在 <div>
中并隐藏了 div。我已经把它放在屏幕外了,但我可以用其他几种方式隐藏 div。
一旦你这样做了,你的下一个问题是你正在改变元素的 fill
,但是这将被你的 SVG 中的 CSS 覆盖。所以你必须删除那些 CSS 样式。
第三,您正在创建 canvas 个对象,但没有将它们附加到 DOM。
您还收到错误消息,因为 canvasX
未初始化。加上 CSS 长度 必须 有单位。所以你需要newCanvas.style.left = canvasX + "px"
等等
您还错误地查找了您的元素。 getElementsByClassName(".hose-class")
找不到任何东西。它需要 getElementsByClassName(".hose-class")
.
最后,我重写了元素查找和颜色分配代码。我已将每个配色方案捆绑到一个配色方案对象数组中。它使 类 到颜色的映射变得更加简单。
// GLOBAL VARIABLES:
const TOTAL_IMAGES = 3; // could be 30, or 300
const canvasWidth = 250;
const canvasHeight = 320;
var canvasX = 0, canvasY = 0;
// COLOR VARIABLES:
var colorCounter = 0;
let houseColorSchemes = [ {".house-class": "fuchsia",
".door-class": "darkblue",
".window-class": "yellow",
".roof-class": "maroon"},
{".house-class": "gold",
".door-class": "purple",
".window-class": "pink",
".roof-class": "crimson"},
{".house-class": "lightblue",
".door-class": "darkslategray",
".window-class": "lightgreen",
".roof-class": "darkred"} ];
// CLASS-NAMES
let classNamesToPaintArray = [".house-class", ".door-class", ".window-class", ".roof-class"];
// SVG template
let houseSVG = document.getElementById("HOUSE");
function designOneHouse(theCanvas) {
console.log("\n\n==========================\n=");
console.log("= =>>In 'designOneHouse()'!\n");
let context = theCanvas.getContext("2d");
// 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!)
//
let colorScheme = houseColorSchemes[colorCounter];
classNamesToPaintArray.forEach(className => {
let elements = houseSVG.querySelectorAll(className);
elements.forEach(element => element.style.fill = colorScheme[className]);
});
var imageData = houseSVG.outerHTML;
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 () {
context.drawImage(img, 0, 0);
DOMURL.revokeObjectURL(url);
}
img.src = url;
// Iterate the ColorCounter - making sure we don't overflow the ColorsArrays:
colorCounter++;
if(colorCounter == houseColorSchemes.length) {
colorCounter = 0;
}
}
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 + "px"; //"100px";
newCanvas.style.top = canvasY + "px"; //"100px";
document.body.appendChild(newCanvas);
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();
#house-template {
position: absolute;
left: -1000px;
}
<div id="house-template">
<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>
.roof-class, .window-class, .door-class {stroke: #000;stroke-miterlimit: 10;}
</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>
</div>