Manipulating svg through viewBox - javascript

I have started working on svg and I am stuck. I want to put dropdown icon at the end of the a particular li.
The code for this is given below:
<svg width="16" height="16" viewBox="0 0 16 16" fill="none">
<mask id="dropdown-mask" maskUnits="userSpaceOnUse" x="4" y="5" width="8" height="6">
</mask>
<g mask="url(#dropdown-mask)">
<rect width="16" height="16" fill="black" fill-opacity="0.54"/>
</g>

Related

Drawing using SVG icon path [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
I am new to SVGs. I wanna make an icon like the below image. How can I achieve this with svg path?
Icon image
Draw a traiangle and a circle.
<svg width="100" height="100" viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.5;">
<g transform="matrix(1,0,0,1,0,-0.377897)">
<circle cx="49.509" cy="63.179" r="22.737" style="fill:none;stroke:black;stroke-width:1.8px;"/>
<g transform="matrix(0.837287,0,0,0.838403,6.90389,6.94193)">
<path d="M50.885,9.42L69.326,39.219L32.444,39.219L50.885,9.42Z" style="fill:none;stroke:black;stroke-width:2.15px;"/>
</g>
</g>
</svg>
Update.
<svg width="100" height="100" viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.5;">
<g transform="matrix(1,0,0,1,0,-0.377897)">
<g transform="matrix(1,0,0,1,0.490673,0)">
<circle cx="49.509" cy="63.179" r="22.737" style="fill:none;stroke:black;stroke-width:1.8px;"/>
</g>
<g transform="matrix(0.837287,0,0,0.838403,7.39456,13.5265)">
<path d="M50.885,9.42L69.326,39.219C69.326,39.219 61.595,32.108 51.566,31.949C40.814,31.778 32.444,39.219 32.444,39.219L50.885,9.42Z" style="fill:none;stroke:black;stroke-width:2.15px;"/>
</g>
</g>
</svg>
Using SVGs is a very interesting way to display vector images on your website. You might want to refer to these docs before you get into the serious stuff: Mozilla / W3
<svg width="800" height="600" xmlns="http://www.w3.org/2000/svg">
<g>
<title>BG</title>
<rect fill="#fff" id="canvas_background" height="602" width="802" y="-1" x="-1"/>
<g display="none" overflow="visible" y="0" x="0" height="100%" width="100%" id="canvasGrid">
<rect fill="url(#gridpattern)" stroke-width="0" y="0" x="0" height="100%" width="100%"/>
</g>
</g>
<g>
<title>SVG-01</title>
<ellipse ry="56" rx="56" id="svg_1" cy="268" cx="400" stroke-width="1.5" stroke="#000" fill="#fff"/>
<path id="svg_2" d="m366.72932,213.48481l33.27077,-58.22384l33.27077,58.22384l-66.54153,0z" stroke-width="1.5" stroke="#000" fill="#fff"/>
</g>
</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>

Add a prefix to mutliple elements from the parent attribute

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>

Animate bar visible only on circle - svg

How to make this animated green bar visible only on circle?
<svg version="1.1" baseProfile="tiny" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
x="0px" y="0px" width="38px" height="38px" viewBox="0 0 38 38" xml:space="preserve">
<rect id="bar" y="10.962" fill="#02FF74" width="38" height="14.667">
Link to CodePen
With a clipPath you can create a mask.
you have a to create a <circle> inside a <defs> tag( it doesn't render element inside it and make it accessible )
you have to create a clipPath thate takes sizes and position from the circle using <use xlink:href="#circleID"...
you should add the attribute clipPath="url(#clipPathID)" to any element or group of element you want to mask.
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="200px" height="200px" viewBox="0 0 38 38" enable-background="new 0 0 37.833 37.833" xml:space="preserve">
<g>
<defs>
<circle id="SVGID_1_" cx="19" cy="19" r="19"/>
</defs>
<clipPath id="SVGID_2_">
<use xlink:href="#SVGID_1_" overflow="visible"/>
</clipPath>
<rect id="bar" y="10.962" clip-path="url(#SVGID_2_)" fill="#02FF74" width="38" height="14.667">
<animate fill="freeze" from="40" to="-15" restart="always" dur="2s" attributeName="y" calcMode="linear" additive="replace" accumulate="none" repeatCount="indefinite">
</animate>
</rect>
<g clip-path="url(#SVGID_2_)">
<path d="M19,4.191c8.166,0,14.809,6.643,14.809,14.809S27.166,33.809,19,33.809S4.191,27.165,4.191,19S10.834,4.191,19,4.191
M19,0C8.508,0,0,8.507,0,19s8.508,19,19,19c10.493,0,19-8.507,19-19S29.493,0,19,0L19,0z"/>
<g>
<path d="M19,13.691c2.928,0,5.309,2.381,5.309,5.309S21.928,24.309,19,24.309S13.691,21.927,13.691,19S16.072,13.691,19,13.691
M19,9.5c-5.246,0-9.5,4.253-9.5,9.5s4.254,9.5,9.5,9.5s9.5-4.253,9.5-9.5S24.246,9.5,19,9.5L19,9.5z"/
</g>
</g>
</g>
</svg>
Just edited to show the animated element just inside the black fill of your circles. The process is the same of the previous example, but now The shape of the mask path has been created copying the d=".." attribute value from both black circles:
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="200" height="200" viewBox="0 0 38 38" enable-background="new 0 0 37.833 37.833" xml:space="preserve">
<g>
<g>
<path d="M19,4.191c8.167,0,14.809,6.643,14.809,14.809c0,8.167-6.643,14.809-14.809,14.809c-8.166,0-14.809-6.645-14.809-14.809
C4.191,10.835,10.834,4.191,19,4.191 M19,0C8.508,0,0,8.507,0,19c0,10.493,8.508,19,19,19c10.493,0,19-8.508,19-19
C38,8.507,29.493,0,19,0L19,0z"/>
<g>
<path d="M19,13.691c2.928,0,5.309,2.381,5.309,5.309c0,2.928-2.381,5.309-5.309,5.309S13.691,21.926,13.691,19
C13.691,16.073,16.072,13.691,19,13.691 M19,9.5c-5.246,0-9.5,4.253-9.5,9.5c0,5.247,4.254,9.5,9.5,9.5
c5.247,0,9.5-4.254,9.5-9.5C28.5,13.753,24.247,9.5,19,9.5L19,9.5z"/>
</g>
</g>
<g>
<defs>
<path id="SVGID_1_" d="M19,4.191c8.167,0,14.809,6.643,14.809,14.809c0,8.167-6.643,14.809-14.809,14.809
c-8.166,0-14.809-6.645-14.809-14.809C4.191,10.835,10.834,4.191,19,4.191 M19,0C8.508,0,0,8.507,0,19c0,10.493,8.508,19,19,19
c10.493,0,19-8.508,19-19C38,8.507,29.493,0,19,0L19,0z M19,13.691c2.928,0,5.309,2.381,5.309,5.309
c0,2.928-2.381,5.309-5.309,5.309S13.691,21.926,13.691,19C13.691,16.073,16.072,13.691,19,13.691 M19,9.5
c-5.246,0-9.5,4.253-9.5,9.5c0,5.247,4.254,9.5,9.5,9.5c5.247,0,9.5-4.254,9.5-9.5C28.5,13.753,24.247,9.5,19,9.5L19,9.5z"/>
</defs>
<clipPath id="SVGID_2_">
<use xlink:href="#SVGID_1_" overflow="visible"/>
</clipPath>
<rect id="bar" y="10.962" clip-path="url(#SVGID_2_)" fill="#02FF74" width="38" height="14.667">
<animate fill="freeze" repeatCount="indefinite" accumulate="none" additive="replace" calcMode="linear" attributeName="y" dur="2s" restart="always" to="-15" from="40">
</animate>
</rect>
</g>
</g>
</svg>

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