Add a prefix to mutliple elements from the parent attribute - javascript

I'm trying to figure out how to add a unique prefix to ID's and other reference links.
I have multiple identical SVGs on a page. These SVGs serve as a wrapper (they're devices - laptop, phone, etc.) which have image link that is inserted into the SVG after load. The problem is, the ID's for these svgs are identical so they all conflict with each other. What I'm trying to do (but am open to better solutions) is to insert a unique ID to each id,xlink:href, url(#, etc. but pass over the <image> href attribute and fill and stroke attributes.
EDIT: I added/tweaked the code provided by #Temani, which got me closer to my desired result, however, I'm now getting all the ID's added to each SVG element. Formatted the code to be executable.
Desired output:
<div class="device" data-screen="[[IMAGE TO USE]]" data-name"[[UNIQUE ID]]">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="635" height="420" viewBox="0 0 635 420">
<defs>
<path id="[[UNIQUE ID]]-path-1"/>
<rect id="[[UNIQUE ID]]-path-3" />
<pattern id="[[UNIQUE ID]]-pattern-4">
<use transform="scale(13.1875)" xlink:href="#[[UNIQUE ID]]-image-5"/>
</pattern>
<image id="[[UNIQUE ID]]-image-5" href="[[IMAGE LINK THAT IS INSERTED AFTER LOAD]]"/>
</defs>
<g fill="none" fill-rule="evenodd">
<rect fill="#fff" stroke="#2D8EFF" />
<g >
<mask id="[[UNIQUE ID]]-mask-2" fill="#fff">
<use xlink:href="#[[UNIQUE ID]]-path-1"/>
</mask>
<g mask="url(#[[UNIQUE ID]]-mask-2)">
<mask id="mask-6" fill="#fff">
<use xlink:href="#[[UNIQUE ID]]-path-3"/>
</mask>
</g>
</g>
</g>
</svg>
</div>
Right now - both ID's (first and second) gets added to each SVG element. I also
$('.device').each(function() {
//we get the needed id using $(this) that refer to actual device
var id = $(this).data('name');
//we check all the element with ID
$(this).find("path, rect, pattern, image, mask").each(function() {
//now (this) refer to the actual element
if($(this).attr("id"))
$(this).attr("id", id+"-"+$(this).attr("id"));
});
//we update the <use>
$(this).find("use").each(function() {
//now (this) refer to the actual element
$(this).attr("xlink:href","#"+id+"-"+$(this).attr("xlink:href").substring(1));
});
// Also, hoping to combine g[mask], u[fill], etc into 1 function.
// Basically any attribute that starts with "url(#"
$(this).find("g[mask^='url']").each(function() {
$(this).attr("mask","url(#"+id+"-"+$(this).attr("mask").substring(5));
});
$(this).find("use[fill^='url']").each(function() {
$(this).attr("fill","url(#"+id+"-"+$(this).attr("fill").substring(5));
});
$(this).find("use[filter^='url']").each(function() {
$(this).attr("filter","url(#"+id+"-"+$(this).attr("filter").substring(5));
});
// grab data-screen value
var data = $(this).data('screen');
// replace this with the link inside svg
if (data != '') {
$(this).find("svg defs image").attr("href", data).attr("xlink:href", data);
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="device" data-name="first" data-screen="image-1.png">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
<defs>
<rect id="w-circle-stroke-a" width="24" height="24"/>
<path id="w-circle-stroke-b" d="M12,2 C17.52,2 22,6.48 22,12 C22,17.52 17.52,22 12,22 C6.48,22 2,17.52 2,12 C2,6.48 6.48,2 12,2 Z M12,3.81818182 C7.48415409,3.81818182 3.81818182,7.48415409 3.81818182,12 C3.81818182,16.5158459 7.48415409,20.1818182 12,20.1818182 C16.5158459,20.1818182 20.1818182,16.5158459 20.1818182,12 C20.1818182,7.48415409 16.5158459,3.81818182 12,3.81818182 Z M10.5553177,13.4773237 L15.155405,8.80967806 C15.5597962,8.4027095 16.222261,8.39598875 16.6350615,8.79466684 C16.6382917,8.79778661 16.6600317,8.81952282 16.7002813,8.85987545 C17.0999062,9.26113743 17.0999062,9.90402237 16.7002813,10.3052843 L10.5553177,16.5 L7.29971874,13.2228714 C6.90252847,12.8240541 6.8997633,12.1859262 7.29348277,11.7837778 L7.33224151,11.7441893 C7.73340831,11.3344341 8.39555055,11.3228774 8.8111776,11.7183766 C8.81566955,11.722651 9.39704957,12.3089667 10.5553177,13.4773237 Z"/>
<image id="image-5" href="image-to-be-inserted.jpg"/>
</defs>
<g fill="none" fill-rule="evenodd">
<mask id="w-circle-stroke-c" fill="#fff">
<use xlink:href="#w-circle-stroke-b"/>
</mask>
<g fill="#2D8EFF" mask="url(#w-circle-stroke-c)">
<rect width="24" height="24"/>
</g>
<use fill="url(#pattern-4)" xlink:href="#path-3"/>
<use fill="#000" filter="url(#filter-10)" xlink:href="#path-9"/>
</g>
</svg>
</div>
<div class="device" data-name="second" data-screen="image-1.png">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
<defs>
<rect id="w-circle-stroke-a" width="24" height="24"/>
<path id="w-circle-stroke-b" d="M12,2 C17.52,2 22,6.48 22,12 C22,17.52 17.52,22 12,22 C6.48,22 2,17.52 2,12 C2,6.48 6.48,2 12,2 Z M12,3.81818182 C7.48415409,3.81818182 3.81818182,7.48415409 3.81818182,12 C3.81818182,16.5158459 7.48415409,20.1818182 12,20.1818182 C16.5158459,20.1818182 20.1818182,16.5158459 20.1818182,12 C20.1818182,7.48415409 16.5158459,3.81818182 12,3.81818182 Z M10.5553177,13.4773237 L15.155405,8.80967806 C15.5597962,8.4027095 16.222261,8.39598875 16.6350615,8.79466684 C16.6382917,8.79778661 16.6600317,8.81952282 16.7002813,8.85987545 C17.0999062,9.26113743 17.0999062,9.90402237 16.7002813,10.3052843 L10.5553177,16.5 L7.29971874,13.2228714 C6.90252847,12.8240541 6.8997633,12.1859262 7.29348277,11.7837778 L7.33224151,11.7441893 C7.73340831,11.3344341 8.39555055,11.3228774 8.8111776,11.7183766 C8.81566955,11.722651 9.39704957,12.3089667 10.5553177,13.4773237 Z"/>
<image id="image-5" href="image-to-be-inserted.jpg"/>
</defs>
<g fill="none" fill-rule="evenodd">
<mask id="w-circle-stroke-c" fill="#fff">
<use xlink:href="#w-circle-stroke-b"/>
</mask>
<g fill="#2D8EFF" mask="url(#w-circle-stroke-c)">
<rect width="24" height="24"/>
</g>
<use fill="url(#pattern-4)" xlink:href="#path-3"/>
<use fill="#000" filter="url(#filter-10)" xlink:href="#path-9"/>
</g>
</svg>
</div>

The issue is that you don't have to use $('.device') when inside and you need to refer to $(this) and since you have 2 each() nested you need to pay attention to the scope of this.
$('.device').each(function() {
//we get the needed id using $(this) that refer to actual device
var id = $(this).data('name');
//we check all the element with ID
$(this).find("path, rect, pattern, image, mask").each(function() {
//now (this) refer to the actual element
if($(this).attr("id"))
$(this).attr("id", id+"-"+$(this).attr("id"));
});
//we update the <use>
$(this).find("use").each(function() {
//now (this) refer to the actual element
$(this).attr("xlink:href","#"+id+"-"+$(this).attr("xlink:href").substring(1));
});
// grab data-screen value
var data = $(this).data('screen');
// replace this with the link inside svg
if (data != '') {
$(this).find("svg defs image").attr("href", data).attr("xlink:href", data);
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="device" data-screen="[[IMAGE TO USE]]" data-name="[[UNIQUE ID]]">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="635" height="420" viewBox="0 0 635 420">
<defs>
<path id="path-1"/>
<rect id="path-3" />
<pattern id="pattern-4">
<use transform="scale(13.1875)" xlink:href="#image-5"/>
</pattern>
<image id="image-5" href="[[IMAGE LINK THAT IS INSERTED AFTER LOAD]]"/>
</defs>
<g fill="none" fill-rule="evenodd">
<rect fill="#fff" stroke="#2D8EFF" />
<g >
<mask id="mask-2" fill="#fff">
<use xlink:href="#path-1"/>
</mask>
<g mask="url(#mask-2)">
<mask id="mask-6" fill="#fff">
<use xlink:href="#path-3"/>
</mask>
</g>
</g>
</g>
</svg>
</div>

Related

<use> - SVG: Stroke of Circle overriding stroke of use element

Stroke of both <use> element ignored here. The stroke color of <circle> is set blue which is appearing on both <use> element too. Why?
I want different strock color of all of 3 these element. but it is not working.
<svg width="300" class="svg-elem" viewBox="0 0 30 10" xmlns="http://www.w3.org/2000/svg">  
<circle id="myCircle" cx="5" cy="5" r="4" stroke="blue"/>
 
<use class="circle1" href="#myCircle" x="10" stroke="grey" fill="blue"/>
 
<use href="#myCircle" x="20" fill="white" stroke="red"/>
</svg>
Because circle still overriding the <use>.
You can consider using CSS variable to control stroke color like below.
<svg width="300" class="svg-elem" viewBox="0 0 30 10" xmlns="http://www.w3.org/2000/svg">
<circle id="myCircle" cx="5" cy="5" r="4" style="stroke:var(--stroke, blue)"/>
<use class="circle1" href="#myCircle" x="10" style="--stroke:gray;" fill="blue"/>
<use href="#myCircle" x="20" fill="white" style="--stroke:red;"/>
</svg>

How to rotate SVG inside mask?

I have an SVG mask that I would like to rotate the elements inside. However, when I attempted it, it looks like the entire mask is being rotated.
I tried at this SO post, but the fiddle wasn't working (the image wasn't showing anymore).
This is what it originally looks like
What happened
What I wanted to happen
I wanted only the "liquid" element to be rotated, but somehow the liquid element is being rotated the wrong way.
This is the SVG (with mask element):
<svg width="200px" height="200px" viewBox="0 0 200 200">
<defs>
<rect id="path-1" x="75" y="65" width="50" height="100" rx="5"></rect>
</defs>
<g id="bottle" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<rect id="bottle-lid" stroke="#916548" stroke-width="5" x="82.5" y="52.5" width="35" height="15" rx="5"></rect>
<rect id="bottle-holder" stroke="#916548" stroke-width="5" x="117.5" y="55.5" width="30" height="7" rx="3.5"></rect>
<mask id="mask-2" fill="white">
<use xlink:href="#path-1"></use>
</mask>
<g id="Mask"></g>
<rect id="bottle-liquid" fill="#3498DB" mask="url(#mask-2)" x="40" y="80" width="120" height="120"></rect>
<rect id="bottle-outline" stroke="#916548" stroke-width="5" mask="url(#mask-2)" x="77.5" y="67.5" width="45" height="95" rx="5"></rect>
</g>
</svg>
And this is the JS (I am using a GSAP library)
const liquid = document.querySelector("#bottle-liquid")
const tl = new TimelineMax()
tl.to(liquid, 1, {
rotation: 20
})
How can I rotate just the a certain element inside a masked SVG?
I've made a few changes to your SVG, the most important: I've putted the bottle-liquid inside a g element and I'm applying the mask to the g element and the transform to the bottle-liquid. I hope it helps.
<svg width="200px" height="200px" viewBox="0 0 200 200">
<defs>
<rect id="path-1" x="75" y="65" width="50" height="100" rx="5"></rect>
<mask id="mask-2" fill="white">
<use xlink:href="#bottle-outline"></use>
</mask>
</defs>
<g id="bottle" stroke-width="5" stroke="#916548" fill="none" fill-rule="evenodd">
<rect id="bottle-lid" x="82.5" y="52.5" width="35" height="15" rx="5"></rect>
<rect id="bottle-holder" x="117.5" y="55.5" width="30" height="7" rx="3.5"></rect>
<g mask="url(#mask-2)">
<rect id="bottle-liquid" stroke="none" fill="#3498DB" x="40" y="80" width="120" height="120" transform="rotate(20 100 140)"></rect>
</g>
<rect id="bottle-outline" x="77.5" y="67.5" width="45" height="95" rx="5"></rect>
</g>
</svg>

Cannot add event listener to nested SVG element

I'm having trouble adding and firing an event listener with javascript on this svg element. Js is at the bottom of the code block. I can set the target ID to a variable no problem. It's attaching an event listener and doing "something" on click/hover that seems to be the issue. The end goal is to show the box when hovering over the dot by adjusting the opacity.
var dot15 = document.getElementById('Dot_15');
var box15 = document.getElementById('Info_Box_15');
dot15.addEventListener('mouseover', function() {
box15.style.opacity = "1";
});
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="777.6px" height="491px" viewBox="607.3 235.5 777.6 491" style="enable-background:new 607.3 235.5 777.6 491;" xml:space="preserve">
<style type="text/css">
.st0{fill:#00A76F;}
.st1{fill:#FFFFFF;}
.st2{font-family:'BarlowCondensed-SemiBold';}
.st3{font-size:14px;}
.st4{font-family:'BarlowCondensed-Medium';}
.st5{font-size:12px;}
.st6{opacity:0.15;fill:#454544;}
#Info_Box_15 {opacity:0}
</style>
<g id="Info_Box_15">
<polygon class="st0" points="1156.7,556.4 1149,548.4 1073,548.4 1073,501.4 1156.7,501.4 "/>
<text transform="matrix(1 0 0 1 1076.6688 516.0011)"><tspan x="0" y="0" class="st1 st2 st3">Gasden</tspan><tspan x="0" y="14" class="st1 st4 st5">Gasden, Alabama</tspan><tspan x="0" y="28" class="st1 st4 st5">89,000 sq. ft.</tspan>
</text>
</g>
<g id="Dot_15" transform="translate(608.399428608477,176.3959312419786)" cursor="pointer">
<path class="st0" d="M548.3,389.1L548.3,389.1c1.9,0,3.5-1.5,3.5-3.5v0c0-1.9-1.5-3.5-3.5-3.5h0c-1.9,0-3.5,1.5-3.5,3.5v0
C544.9,387.5,546.4,389.1,548.3,389.1z"/>
</g>
<g id="Site_x5F_3_x5F_Blue_x5F_Valley">
<g id="Info_box_3">
<polygon class="st0" points="1018.2,467.3 1010.5,459.4 934.5,459.4 934.5,412.3 1018.2,412.3 "/>
<text transform="matrix(1 0 0 1 938.1677 426.9739)"><tspan x="0" y="0" class="st1 st2 st3">BLUE VALLEY</tspan><tspan x="0" y="14" class="st1 st4 st5">Kansas City, KS</tspan><tspan x="0" y="28" class="st1 st4 st5">83,224 sq. ft.</tspan></text>
</g>
<g id="Dot_3" transform="translate(608.399428608477,176.3959312419786)">
<path class="st0" d="M409.8,300L409.8,300c1.9,0,3.5-1.5,3.5-3.5v0c0-1.9-1.5-3.5-3.5-3.5h0c-1.9,0-3.5,1.5-3.5,3.5v0
C406.4,298.5,407.9,300,409.8,300z"/>
</g>
</g>

How i can style SVG <use> elements on hover?

I'm beginner in SVG. I'm trying to change style of multiple <use> elements on hover at a specific <use> element with css, but I can't, because <use> elements using Shadow DOM.
I have the following <defs>:
<defs>
<filter id="Sjax0b81q1" filterUnits="userSpaceOnUse">...</filter>
<circle cx="0" cy="0" r="40" id="action-circle" style="cursor: move; fill: #fff;" filter="url('#Sjax0b81q1')" class="el action-el"></circle>
<g id="condition-rhombus" style="cursor: move; fill: #fff;" class="el condition-el" transform="matrix(1,0,0,1,0,0)">
<circle cx="0" cy="0" r="40" fill="none"></circle>
<path d="M -35 0, L 0 -35, L 35 0, L 0 35 L -35 0" style="stroke-linecap: round; stroke: white;" filter="url('#Sjax0b81q1')" class="condition-rhombus"></path>
</g>
<g id="svg-plus-button">
<circle cx="0" cy="40" r="10" id="svg-plus-circle" fill="none" style="fill-opacity: 1;" class="svg-plus-circle"></circle>
<path d="M956.8,408.....408.5z" id="svg-plus-sign" fill="none" transform="matrix(0.008,0,0,0.008,-4,36)" style="pointer-events: none;" class="svg-plus-sign"></path>
</g>
<rect x="-20" y="-20" width="40" height="40" id="rect-active-layer" fill="none" style="pointer-events: visible;" class="rect-active-layer"></rect>
<path d="M252.967.....2v1Z" id="api-svg" class="cls-1"></path>
</defs>
And I have a group of elements that contains several <use> elements:
<g id="action-group-2" class="external action-group" transform="matrix(1,0,0,1,420,180)">
<g class="internal action-group">
<rect x="-40" y="-40" width="80" height="80" fill="none"></rect>
</g>
<use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#action-circle"></use>
<use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#svg-plus-button" id="useSjax0b81q1k"></use>
<use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#rect-active-layer"></use>
<use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#api-svg"></use>
</g>
For example, I need to change the <path> fill in element with id #api-svg, when I hover on the #action-circle.
How can I do this? Maybe there is another way to render and styling reusable elements on hover.
Define the path to have fill="inherit", then you should be able to set fill="whatever" on the <use> element's styles and it will work.
use:hover {
fill: red;
}
<svg>
<defs>
<circle id="test" fill="inherit" cy="10" r="10" />
</defs>
<use xlink:href="#test" transform="translate(10,0)" />
<use xlink:href="#test" transform="translate(30,0)" />
<use xlink:href="#test" transform="translate(50,0)" />
<text y="40">Hover over the circles!</text>
</svg>
There's nothing overly complex here. Just change the 'use' element, rather than anything in the defs area (unless you want it to affect everything that references it).
You can either style the use element via normal css, via a css selector, e.g it's id is possibly simplest.
Or you can set the fill svg attribute on the svg 'use' element you are handling.
You shouldn't need fill inherit or anything unless I'm missing something.

svg!! change text on load

Just wanted to ask is there any way of changing the svg text on load.
Standard SVG examples work just fine.
$(document).ready(function(){
document.getElementById('mySVGText').textContent = 'new_value';
});
it works on this svg
<svg version="1.1"
baseProfile="full"
xmlns="http://www.w3.org/2000/svg" id="mySVG">
<rect width="100%" height="100%" fill="red" />
<circle cx="150" cy="100" r="80" fill="green" />
<text id="mySVGText" name="textName" x="150" y="125" font-size="60" text-anchor="middle" fill="white">SVG</text>
</svg>
but seems like this svg doesnt allow me to getElementById and change the text:
<svg version="1.1"
id="Capa_1"
xmlns="http://www.w3.org/2000/svg"
x="0px" y="0px"
viewBox="0 0 489 489"
style="enable-background:new 0 0 489 489;"
xml:space="preserve"
>
<text id="mySVGText" name="textName" x="160" y="400" font-size="280" text-anchor="middle" fill="blue">SVG</text>
<g>
<path style="fill:white" d="M440.1,422.7l-28-315.3c-0.6-7-6.5-12.3-13.4-12.3h-57.6C340.3,42.5,297.3,0,244.5,0s-95.8,42.5-96.6,95.1H90.3
c-7,0-12.8,5.3-13.4,12.3l-28,315.3c0,0.4-0.1,0.8-0.1,1.2c0,35.9,32.9,65.1,73.4,65.1h244.6c40.5,0,73.4-29.2,73.4-65.1
C440.2,423.5,440.2,423.1,440.1,422.7z M244.5,27c37.9,0,68.8,30.4,69.6,68.1H174.9C175.7,57.4,206.6,27,244.5,27z M366.8,462
H122.2c-25.4,0-46-16.8-46.4-37.5l26.8-302.3h45.2v41c0,7.5,6,13.5,13.5,13.5s13.5-6,13.5-13.5v-41h139.3v41
c0,7.5,6,13.5,13.5,13.5s13.5-6,13.5-13.5v-41h45.2l26.9,302.3C412.8,445.2,392.1,462,366.8,462z"/>
</g>
</svg>
Any help would be appreciated.
So that this doesn't show up as unanswered:
The problem was that there were two elements with the id mySVGText on the page. document.getElementById assumes that each id on the page is unique, so it can have unexpected behavior when they aren't.

Categories

Resources