I am trying to programmatically create inline svg images of a row of shields.
My shield is a simple path:
<path fill="red" d="M0 0 L0 15 q0 25 20 35 q20 -10 20 -35 L40 0z"></path>
Here is my script:
const element = document.querySelector('main')
for (let i = 0; i < 10; i) {
element.appendChild(document.createElementNS('http:http://www.w3.org/2000/svg', 'svg'))
element.lastChild.setAttribute('width', 400)
element.lastChild.setAttribute('height', 400)
// Code to add path inside svg, removed it and still didn't work
element.lastChild.appendChild(document.createElementNS('http:http://www.w3.org/2000/svg', 'path'))
element.lastChild.lastChild.setAttribute('fill', 'red')
element.lastChild.lastChild.setAttribute('d', 'M0 0 L0 15 q0 25 20 35 q20 -10 20 -35 L40 0z')
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<style>
main {
display: flex;
}
svg {
background-color: blue;
}
</style>
<main>
<svg>
<path fill="red" d="M0 0 L0 15 q0 25 20 35 q20 -10 20 -35 L40 0z"></path>
</svg>
</main>
</body>
</html>
Copyable code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<style>
main {
display: flex;
}
svg {
background-color: blue;
}
</style>
<main>
<svg>
<path fill="red" d="M0 0 L0 15 q0 25 20 35 q20 -10 20 -35 L40 0z"></path>
</svg>
</main>
<script>
const element = document.querySelector('main')
for(let i = 0; i < 10; i) {
element.appendChild(document.createElementNS('http:http://www.w3.org/2000/svg', 'svg'))
element.lastChild.setAttribute('width', 400)
element.lastChild.setAttribute('height', 400)
// Code to add path inside svg, removed it and still didn't work
element.lastChild.appendChild(document.createElementNS('http:http://www.w3.org/2000/svg', 'path'))
element.lastChild.lastChild.setAttribute('fill', 'red')
element.lastChild.lastChild.setAttribute('d', 'M0 0 L0 15 q0 25 20 35 q20 -10 20 -35 L40 0z')
}
</script>
</body>
</html>
The first svg is being properly rendered, but my auto generated svgs are not being rendered.
How do I programmatically create inline svg images of a row of shields?
Thanks in advance!
I've looked at:
- JavaScript inline SVG not rendering [duplicate]: The answer given is to use
createElementNS
, which I'm already using. - Inline-SVG not rendering when generated by JS: Answer talks about external svg.
- Inline SVG in CSS: Answers talk about data uris to embed SVG. Not what I'm doing.
- img src SVG changing the styles with CSS: Answers talk about external svgs.
CodePudding user response:
I can see that you are trying to create multiple SVGs, but I think it makes sense to just have on SVG and then insert all the paths in that.
I have created an array with the different sheilds (they could have more properties, here only color). And for each of them create a path. The position is controlled by the index.
const svg01 = document.querySelector('#svg01');
const shields = ['red', 'green', 'orange', 'red', 'green', 'orange', 'red', 'green', 'orange', 'red'];
shields.forEach((color,i) => {
let shield = document.createElementNS('http://www.w3.org/2000/svg', 'path');
shield.setAttribute('fill', color);
shield.setAttribute('d', 'M0 0 L0 15 q0 25 20 35 q20 -10 20 -35 L40 0z');
shield.setAttribute('transform', `translate(${i * 100 20} 0)`);
svg01.appendChild(shield);
});
svg {
background-color: blue;
}
<main>
<svg id="svg01" viewBox="0 0 1000 1000" xmlns="http://www.w3.org/2000/svg">
</svg>
</main>
CodePudding user response:
SVG created as HTML tag in the DOM gets the correct namespace, no need to specify it
to prevent more NameSpacing issues, you can add SVG content as innerHTML
I used svg-path-editor to convert your Shield to relative notation,
so you don't need atranslate
to position itWrapped in a native JS Web Component
<svg-shields>
, so you don't have to worry about required DOM elements
customElements.define("svg-shields", class extends HTMLElement {
connectedCallback() {
let colors = this.getAttribute("colors").split(",");
this.innerHTML =
`<svg viewBox="0 0 ${colors.length*100} 100">`
colors.map((fill, idx) => {
return `<path fill="${fill}"
d="M${ idx*100 20 } 0 l0 15q0 25 20 35 20-10 20-35l0-15z"/>`
}).join("\n")
`</svg>`;
}
});
<svg-shields colors="red,green,orange,red,green,orange,red,green,orange,red">
</svg-shields>
<svg-shields colors="red,yellow,blue"></svg-shields>