HTML SVG menggunakan kembali grup <g> dengan <use> dan mengubah atribut elemen dalam satu per satu untuk setiap instance
Jadi saya ingin menggunakan kembali bentuk svg yang dikelompokkan dan mengubah satu atribut dari salah satu elemen di dalam grup secara individual untuk setiap contoh. Contoh sederhana berikut membuat lingkaran kedua dengan persegi panjang di dalamnya. Sekarang saya ingin mengubah atribut "lebar" dari persegi panjang "persegi-saya" satu per satu untuk setiap bentuk dengan javascript. Menggunakan id "my-rect" akan mengubah lebar kedua persegi panjang, tapi saya hanya ingin mengubah satu.
Tujuan saya (jika pendekatan saya tidak masuk akal): Saya harus menggambar beberapa bentuk ini dan satu-satunya hal yang berbeda adalah posisi dan lebar persegi panjang.
<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>
Jawaban
Dengan sedikit tipu daya, itu mungkin. Anda harus memanfaatkan warisan CSS untuk mendapatkan beberapa nilai properti di dalam elemen bayangan. Dalam kasus ini, itu akan menjadi variabel khusus yang akan digunakan untuk menskalakan dan memosisikan persegi panjang.
Markup harus ditulis ulang sedikit untuk ini. Pertama, Anda menulis grup Anda di dalam sebuah <defs>
elemen, menjadikannya template untuk digunakan kembali, tetapi tidak dirender dengan sendirinya. Kedua, persegi panjang ditempatkan di dalam <svg overflow="visible">
elemen bersarang . Memberi elemen ini koordinat x / y dan membiarkannya di 0 untuk <rect>
elemen membuatnya lebih mudah untuk melacak di mana sisi kiri persegi panjang akan berakhir setelah operasi transformasi.
Sekarang perubahan lebar persegi dicapai dengan scaleX()
transformasi plus a translate()
untuk posisinya. Ini harus dalam sintaks transformasi CSS . Menggunakan transform
atribut tidak akan berhasil (belum). Oleh karena itu, kita juga membutuhkan transform-origin
properti, diatur ke sisi kiri <svg>
elemen penutup .
Alih-alih menulis nilai konkret untuk penskalaan, nilai tersebut dinyatakan sebagai variabel dengan nilai default 1 var(--scale, 1)
:; sama untuk nilai posisi. Nilai untuk variabel diatur dalam style
atribut untuk setiap <use>
elemen secara terpisah: style="--scale:2;--posX:20px; --posY:-10px"
. Perhatikan kebutuhan px
unit penulisan !
#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 berkata:
Jika Elemen Kustom Komponen Web diperluas ke namespace SVG,
penggunaan ulang yang lebih rumit dapat dilakukan
Yang benar, Anda belum bisa membuat elemen SVG kustom .
Tapi Anda bisa membuat Elemen Kustom yang menghasilkan 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>
Elemen Khusus untuk SVG adalah solusi modern untuk banyak peretasan SVG oldskool
Memperbarui
Jika OP menginginkan satu SVG dengan lingkaran, kita dapat menggunakan shadowDOM dan fakta bahwa elemen di dalam lightDOM tidak ditampilkan. Kami bahkan dapat menggunakan elemen yang tidak ditentukan <rect>
(dalam namespace HTML) sehingga kami dapat dengan mudah memasukkannya ke dalam string 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)
Jawaban StackOverflow terkait: Elemen Kustom dan SVG
Ini tidak mungkin. The use
elemen menciptakan closed shadow root, yang berarti isinya tidak dapat diakses untuk JS. Meskipun Anda dapat menyetel atribut instance dari elemen yang digunakan kembali secara individual (jika belum ditetapkan pada elemen asli), Anda tidak akan dapat memengaruhi elemen yang merupakan turunan dari elemen yang digunakan kembali.
Pendekatan alternatif akan menggunakan kembali elemen persegi panjang dan lingkaran secara langsung, dan menempatkannya dalam grup baru.
The getAttribute
Metode tidak bekerja untuk saya tapi ini bekerja:
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>';
}
});
Penggunaan :
<source-link href="//google.com"></source-link>
Sumber: D