在運行時以編程方式更改 SVG 類

西拉布33

-我想畫一樣 SVGcanvas多次,但我想以編程每次更改內的特定類的顏色SVG

例如下面這張房子的圖片:

在此處輸入圖片說明

這所房子的 SVG 具有以下類:

<style>

  .window-class {
    fill: lime;
  }

  .door-class {
    fill: blue;
  }

  .house-class {
    fill: tan;
  }

  .roof-class {
    fill: red;
  }

</style>

我如何以編程方式訪問這些特定的樣式類,以便我可以為我繪製的每個新房子更改它們的顏色值?

SVG通過創建一個 Image 對象,然後canvas使用以下代碼將該圖像繪製到 a 上來構建 :

    // 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,在我發現帶有 this 樣式的每個元素上window-class,我會這樣做:

        element.style.fill = -whatever-the-next-color-would-be-;

但是由於我是按照上面顯示的方式創建圖像的,所以我不確定如何獲得它的SVG.

有什麼想法嗎?

==============================

更新:

有人指出多次繪製圖像/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);
保羅·勒博

要操作房子的 DOM,SVG 必須在 DOM 中。所以我將 SVG 包裹在 a 中<div>並隱藏了 div。我已經把它放在屏幕外,但我可以用其他幾種方式隱藏 div。

一旦你這樣做了,你的下一個問題是你正在改變fill元素的 ,但這將被你的 SVG 中的 CSS 覆蓋。所以你必須刪除那些 CSS 樣式。

第三,您正在創建畫布對象,但沒有將它們附加到 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>

Este artigo é coletado da Internet.

Se houver alguma infração, entre em [email protected] Delete.

editar em
0

deixe-me dizer algumas palavras

0comentários
loginDepois de participar da revisão

Artigos relacionados

在 javascript 中以編程方式創建類聲明?

使用 $lt 運算符將整數類型編號與字符串類型編號進行比較時出現問題

元編程 - 類冪函數

為什麼在只導入類時運行類定義之外的代碼?

從 EF 核心的類/對像以編程方式創建 MemberInitExpression

R 編程:將列數據類型從字符(帶 $)更改為數字

以編程方式運行 SQL 腳本

SVG 中嵌套類的 CSS 選擇器

將一個類切換到具有特定類的多個 SVG 路徑

調用具有僅在運行時已知的特定類型的泛型方法並返回該類型?

如何以編程方式重命名 .Java 文件中的字段、參數、類名和方法名?

是否可以在運行時以編程方式使用 C# 複製基於權限的 webconfig 文件?

函數 remove(atOffsets:) 只在運行時抱怨錯誤類型

當我收到錯誤“由更新版本的 Java 運行時(類文件版本 55.0)編譯...”時,如何將 JRE 或 JDK 設置為 IntelliJ 的 Java 11

臨時轉換列數據類型以對時態列數據類型運行新查詢 - MySQL

重構類以在 React 中運行組件

在 C++ 中的類中使用類時收到警告

編譯時類型未解析的 F# 類型錯誤

將類型記錄為編譯時常量

在擴展類型的構造函數末尾自動執行抽象父類型的類型綁定過程

編程類項目。我一直收到同樣的錯誤

當另一個類存在時更改偽元素

javascript 面向對象編程中 super() 構造函數和子類方法的執行順序是什麼?

在頁面級別更改 css 類

以編程方式更改狀態時可以為 NSSwitch 設置動畫嗎?

在類上使用代理,同時保持對現有屬性和類類型的訪問

當派生類只添加非虛函數時,將基類轉換為派生類

將 CSV 行導入類

複製另一種對像類型的 TypeScript 類型,但根據其原始類型條件更改屬性類型

TOP lista

quentelabel

Arquivo