HTML SVG riutilizza un gruppo <g> con <use> e modifica gli attributi degli elementi interni individualmente per ogni istanza
Quindi mi piacerebbe riutilizzare una forma svg raggruppata e modificare un attributo di uno degli elementi all'interno del gruppo individualmente per ogni istanza. L'esempio semplificato seguente crea un secondo cerchio con un rettangolo all'interno. Ora voglio cambiare l'attributo "width" del rettangolo "my-rect" individualmente per ciascuna delle forme con javascript. L'uso dell'id "my-rect" cambierà la larghezza di entrambi i rettangoli, ma voglio cambiarne solo uno.
Il mio obiettivo (se il mio approccio non ha senso): devo disegnare più di queste forme e l'unica cosa che differisce è la posizione e la larghezza del rettangolo.
<svg height="1000" width="1000">
<a transform="translate(110,110)">
<g id="my-group">
<g>
<circle r="100" fill="#0000BF" stroke="black" stroke-width="2" fill-opacity="0.8"></circle>
</g>
<g>
<rect id="my-rect" y="-50" height="100" x="-50" width="50">
</rect>
</g>
</g>
</a>
<use xlink:href="#my-group" x="340" y="110"/>
</svg>
Risposte
Con un po' di trucco, è possibile. Devi sfruttare l'ereditarietà CSS per ottenere un valore di proprietà all'interno di un elemento shadow. In questo caso, saranno le variabili personalizzate che verranno utilizzate per ridimensionare e posizionare il rettangolo.
Il markup deve essere riscritto un po' per questo. Innanzitutto, scrivi il tuo gruppo all'interno di un <defs>
elemento, rendendolo un modello per il riutilizzo, ma non reso da solo. In secondo luogo, il rettangolo viene posizionato all'interno di un <svg overflow="visible">
elemento nidificato. Dare a questo elemento le coordinate x/y e lasciarle a 0 per l' <rect>
elemento rende più facile tracciare dove finirà il lato sinistro del rettangolo dopo un'operazione di trasformazione.
Ora il cambio di larghezza del rect si ottiene con una scaleX()
trasformazione più a translate()
per la posizione. Questo deve essere nella sintassi di trasformazione CSS . L'uso di un transform
attributo non funzionerebbe (ancora). Pertanto, abbiamo anche bisogno di una transform-origin
proprietà, impostata sul lato sinistro <svg>
dell'elemento contenitore.
Invece di scrivere un valore concreto per il ridimensionamento, il valore viene espresso come una variabile con il valore predefinito 1: var(--scale, 1)
; lo stesso per i valori posizionali. Il valore per la variabile è impostato in un style
attributo per ciascun <use>
elemento separatamente: style="--scale:2;--posX:20px; --posY:-10px"
. Si noti la necessità di scrivere px
unità!
#my-rect {
transform-origin: left top;
transform: translate(var(--posX, 0), var(--posY, 0)) scaleX(var(--scale, 1));
}
<svg height="1000" width="1000">
<defs>
<g id="my-group">
<g>
<circle r="100" fill="#0000BF" stroke="black" stroke-width="2" fill-opacity="0.8"></circle>
</g>
<svg x="-50" y="-50" overflow="visible">
<rect id="my-rect" height="100" width="50">
</rect>
</svg>
</g>
</defs>
<use xlink:href="#my-group" x="110" y="110" style="--scale:1"/>
<use xlink:href="#my-group" x="340" y="110" style="--scale:2;--posX:20px; --posY:-10px"/>
</svg>
Sean ha detto:
Se gli elementi personalizzati di Web Components vengono espansi nello spazio dei nomi SVG,
sarà possibile un riutilizzo più complesso
Il che è vero, non puoi (ancora) creare elementi SVG personalizzati .
Ma puoi creare un elemento personalizzato che genera SVG:
customElements.define("rect-in-circle", class extends HTMLElement{
connectedCallback(){
const a = x => this.getAttribute(x);
this.innerHTML=`<svg viewBox="-100 -100 100 100">`+
`<g transform="translate(-50 -50)">`+
`<circle r="50" fill="#123456AB"/>`+
`<rect y="${a("y")}" height="${a("height")}"`+
`x="${a("x")}" width="${a("width" )}"/>`+
`</g></svg>`
}
});
svg{
width:100px;
height:100px;
background:grey;
fill:green;
}
<rect-in-circle x=-10 y=-10 width=20 height=20></rect-in-circle>
<rect-in-circle x=-40 y=-20 width=10 height=40></rect-in-circle>
<rect-in-circle x= 10 y= 20 width=30 height= 5></rect-in-circle>
Gli elementi personalizzati per SVG sono una soluzione moderna a molti hack SVG oldskool
Aggiornare
Se OP vuole un SVG con cerchi, possiamo usare shadowDOM e il fatto che gli elementi all'interno di lightDOM non vengono visualizzati. Possiamo persino utilizzare elementi non definiti <rect>
(nello spazio dei nomi HTML) in modo da poterli facilmente inserire nella stringa SVG.
<script>
customElements.define("rects-in-circles", class extends HTMLElement {
connectedCallback() {
setTimeout(() => {
const rects = [...this.children];
const width = rects.length * 100;
this.attachShadow({
mode: "open"
}).innerHTML = `<svg viewBox='0 0 ${width} 100'>` +
rects.map((rect, idx) => `<g transform='translate(${50+100*idx} 50)'>` +
`<circle r='50' fill='green'/>` +
rect.outerHTML +
`</g>`) + "</svg>";
})
}
});
</script>
<rects-in-circles>
<rect x=-10 y=-10 width=20 height=20></rect>
<rect x=-40 y=-20 width=10 height=40></rect>
<rect x=10 y=20 width=30 height=5></rect>
<rect x=-40 y=-40 width=50 height=50></rect>
</rects-in-circles>
(my)
Risposte StackOverflow correlate: elementi personalizzati e SVG
Questo non è possibile. L' use
elemento crea un closed shadow root, il che significa che i suoi contenuti sono inaccessibili a JS. Mentre puoi impostare gli attributi delle istanze dell'elemento riutilizzato individualmente (se non sono stati impostati sull'elemento originale) non sarai in grado di influenzare gli elementi che sono figli dell'elemento riutilizzato.
Un approccio alternativo consisterebbe nel riutilizzare direttamente gli elementi rettangolo e cerchio e inserirli in un nuovo gruppo.
Il getAttribute
metodo non ha funzionato per me, ma questo ha funzionato:
customElements.define("source-link", class extends HTMLElement {
static get observedAttributes() {
return ['href'];
}
get href() {
return this.getAttribute('href');
}
set href(val) {
if (val) {
this.setAttribute('href', val);
} else {
this.removeAttribute('href');
}
}
connectedCallback(){
this.innerHTML= '<a href="' + this.href + '" target="_blank" title="source"><svg fill="#37f" viewBox="0 0 512 512" width="16"><g><path d="M488.727,0H302.545c-12.853,0-23.273,10.42-23.273,23.273c0,12.853,10.42,23.273,23.273,23.273h129.997L192.999,286.09 c-9.089,9.089-9.089,23.823,0,32.912c4.543,4.544,10.499,6.816,16.455,6.816c5.956,0,11.913-2.271,16.457-6.817L465.455,79.458 v129.997c0,12.853,10.42,23.273,23.273,23.273c12.853,0,23.273-10.42,23.273-23.273V23.273C512,10.42,501.58,0,488.727,0z"/></g><g><path d="M395.636,232.727c-12.853,0-23.273,10.42-23.273,23.273v209.455H46.545V139.636H256c12.853,0,23.273-10.42,23.273-23.273 S268.853,93.091,256,93.091H23.273C10.42,93.091,0,103.511,0,116.364v372.364C0,501.58,10.42,512,23.273,512h372.364 c12.853,0,23.273-10.42,23.273-23.273V256C418.909,243.147,408.489,232.727,395.636,232.727z"/></g></svg></a>';
}
});
Utilizzo :
<source-link href="//google.com"></source-link>
Fonte:D