I have a rectangle in my SVG, I have one graphic like aircraft and i would like to use mask and move it on random orbit. I'm looking for the sollution for this.
EDIT:
I would like to get a javascript which makes like the black paths as mask in SVG. Wanna be move and make a copy of the element.
Here it is my svg i would like to move the plane and copy after moving:
<svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" height="500px" viewBox="0 0 500 500" width="500px" version="1.1" y="0px" x="0px" xmlns:xlink="http://www.w3.org/1999/xlink" enable-background="new 0 0 500 500">
<g id="_x32_">
<path d="M250.2,59.002c11.001,0,20.176,9.165,20.176,20.777v122.24l171.12,95.954v42.779l-171.12-49.501v89.227l40.337,29.946v35.446l-60.52-20.18-60.502,20.166v-35.45l40.341-29.946v-89.227l-171.14,49.51v-42.779l171.14-95.954v-122.24c0-11.612,9.15-20.777,20.16-20.777z"/>
<path stroke="#000" stroke-width="0.2" d="M31.356,500.29c-17.26,0-31.256-13.995-31.256-31.261v-437.67c0-17.265,13.996-31.261,31.256-31.261h437.68c17.266,0,31.261,13.996,31.261,31.263v437.67c0,17.266-13.995,31.261-31.261,31.261h-437.67z" fill="none"/>
</g>
</svg>
I'm not sure I understand exactly what you want. But here is a little demo that hopefully should help you get started at least.
// Get references to the various elements in the SVG
var svg = document.getElementById("Layer_1");
var blackpath = svg.getElementById("blackpath");
var redplane = svg.getElementById("redplane");
// Add an event listener to the SVG that captures mouse move events
svg.addEventListener("mousemove", function(evt) {
// Convert the mouse position from screen coords to SVG coords.
var pt = svg.createSVGPoint();
pt.x = evt.clientX;
pt.y = evt.clientY;
pt = pt.matrixTransform(svg.getScreenCTM().inverse());
// Move the red plane to the mouse mosition
redplane.setAttribute("x", pt.x);
redplane.setAttribute("y", pt.y);
// Create a <use> element to add a cloned "copy" of the plane to the "blackpath" group.
var useElement = document.createElementNS("http://www.w3.org/2000/svg", "use");
useElement.setAttributeNS("http://www.w3.org/1999/xlink", "href", "#plane");
// Position the clone at the mouse coords
useElement.setAttribute("x", pt.x);
useElement.setAttribute("y", pt.y);
// Add it to the blackpath group
blackpath.appendChild(useElement);
});
<svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" height="500px" viewBox="0 0 500 500" width="500px" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<path id="plane"
d="M250.2,59.002c11.001,0,20.176,9.165,20.176,20.777v122.24l171.12,95.954v42.779l-171.12-49.501v89.227l40.337,29.946v35.446l-60.52-20.18-60.502,20.166v-35.45l40.341-29.946v-89.227l-171.14,49.51v-42.779l171.14-95.954v-122.24c0-11.612,9.15-20.777,20.16-20.777z" transform="scale(0.2, 0.2) translate(-250, -250)"/>
</defs>
<rect width="500" height="500" fill="#407085"/>
<g id="blackpath" fill="black"></g>
<use id="redplane" xlink:href="#plane" fill="#f30000" x="-100" y="-100"/>
</svg>
Related
I am trying to make a play and stop button. I don't know how to morph the triangle shape (it is a path) into the square shape (it is a path) when it has been clicked. Only showing one shape at a time. Can anyone help?
<svg class="playStop" 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"
viewBox="0 0 971 530" style="enable-background:new 0 0 971 530;" xml:space="preserve">
<style type="text/css">
.st0{fill:none;
stroke:#000000;
stroke-width:4;
stroke-miterlimit:10;}
</style>
<path id="playTriangle" class="st0" d="M432,290.7V187.8c0-11.4,9.2-20.7,20.6-20.8c3.2,0,6.3,0.7,9.2,2.2l86.9,43.3l16.2,8.1c10.2,5,14.5,17.5,9.4,27.7c-2,4.1-5.3,7.5-9.4,9.5l-13.4,6.7l-89.8,44.8c-10.2,5-22.6,0.8-27.6-9.5C432.7,297,432,293.9,432,290.7z"/>
<path id="stopSquare" class="st0" d="M458.6,167h91.3c14.7,0,26.6,11.9,26.6,26.6v91.3c0,14.7-11.9,26.6-26.6,26.6h-91.3c-14.7,0-26.6-11.9-26.6-26.6v-91.3C432,178.9,443.9,167,458.6,167z"/>
</svg>
I think one way is to define your two paths in defs and then use a use xlink:href="#shapeName" with an onclick handler that toggles that attribute or the corresponding DOM property, if supported..
A use element object with fully implemented SVG DOM has a href property with a baseVal property that can be read and set, so inside browsers as far as I have tested (with Firefox, Chrome, IE and Edge on Window) we can simply toggle that property, see https://jsfiddle.net/4x0gnkob/ for an online sample.
.st0{fill:none;
stroke:#000000;
stroke-width:4;
stroke-miterlimit:10;}
<svg class="playStop" 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"
viewBox="0 0 971 530" style="enable-background:new 0 0 971 530;" xml:space="preserve">
<defs>
<path id="playTriangle" class="st0" d="M432,290.7V187.8c0-11.4,9.2-20.7,20.6-20.8c3.2,0,6.3,0.7,9.2,2.2l86.9,43.3l16.2,8.1c10.2,5,14.5,17.5,9.4,27.7c-2,4.1-5.3,7.5-9.4,9.5l-13.4,6.7l-89.8,44.8c-10.2,5-22.6,0.8-27.6-9.5C432.7,297,432,293.9,432,290.7z"/>
<path id="stopSquare" class="st0" d="M458.6,167h91.3c14.7,0,26.6,11.9,26.6,26.6v91.3c0,14.7-11.9,26.6-26.6,26.6h-91.3c-14.7,0-26.6-11.9-26.6-26.6v-91.3C432,178.9,443.9,167,458.6,167z"/>
</defs>
<use xlink:href="#playTriangle" pointer-events="all" onclick="this.href.baseVal = this.href.baseVal == '#playTriangle' ? '#stopSquare' : '#playTriangle';"></use>
</svg>
An alternative is to toggle the DOM attribute, it seems a bit complicated in an HTML5 environment as I thought I could solve it with setAttributeNS and getAttributeNS in one line, after some testing it seems that within HTML5 getAttribute('xlink:href') works better, so the full code tries to test which function returns a value.
function toggleLink(element, value1, value2) {
var xlinkNS = 'http://www.w3.org/1999/xlink';
var linkName = 'xlink:href';
var oldValue = element.getAttributeNS(xlinkNS, linkName) || element.getAttribute(linkName);
if (element.hasAttributeNS(xlinkNS, 'href')) {
element.setAttributeNS(xlinkNS, linkName, oldValue == value1 ? value2 : value1)
}
else {
element.setAttribute(linkName, oldValue == value1 ? value2 : value1);
}
}
.st0{fill:none;
stroke:#000000;
stroke-width:4;
stroke-miterlimit:10;}
<svg class="playStop" 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"
viewBox="0 0 971 530" style="enable-background:new 0 0 971 530;" xml:space="preserve">
<defs>
<path id="playTriangle" class="st0" d="M432,290.7V187.8c0-11.4,9.2-20.7,20.6-20.8c3.2,0,6.3,0.7,9.2,2.2l86.9,43.3l16.2,8.1c10.2,5,14.5,17.5,9.4,27.7c-2,4.1-5.3,7.5-9.4,9.5l-13.4,6.7l-89.8,44.8c-10.2,5-22.6,0.8-27.6-9.5C432.7,297,432,293.9,432,290.7z"/>
<path id="stopSquare" class="st0" d="M458.6,167h91.3c14.7,0,26.6,11.9,26.6,26.6v91.3c0,14.7-11.9,26.6-26.6,26.6h-91.3c-14.7,0-26.6-11.9-26.6-26.6v-91.3C432,178.9,443.9,167,458.6,167z"/>
</defs>
<use xlink:href="#playTriangle" pointer-events="all" onclick="toggleLink(this, '#stopSquare', '#playTriangle')"></use>
</svg>
Online at https://jsfiddle.net/w36k21uz/1/.
You cannot do all the things just like that, you can either use SMIL, which is to become deprecated, or use a dedicated animation engine. I developed KUTE.js with a SVG Plugin that does most of the things you probably need for SVG.
A quick demo (should work in Firefox only due to some Stackoverflow XSS issue):
<div style="width: 220px">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 600">
<path id="rectangle" fill="indigo" d="M38.01,5.653h526.531c17.905,0,32.422,14.516,32.422,32.422v526.531
c0,17.905-14.517,32.422-32.422,32.422H38.01c-17.906,0-32.422-14.517-32.422-32.422V38.075C5.588,20.169,20.104,5.653,38.01,5.653z"></path>
<path id="star" style="visibility:hidden" d="M301.113,12.011l99.25,179.996l201.864,38.778L461.706,380.808
l25.508,203.958l-186.101-87.287L115.01,584.766l25.507-203.958L0,230.785l201.86-38.778L301.113,12.011"></path>
</svg>
</div>
<script id="core" src="https://cdn.jsdelivr.net/kute.js/1.5.5/kute.min.js"></script>
<script id="svg" src="https://cdn.jsdelivr.net/kute.js/1.5.5/kute-svg.min.js"></script>
<script>
var tween = KUTE.to('#rectangle', { path: '#star' }, {duration: 1500, yoyo: true, repeat: 1}).start();
document.addEventListener('click', function(){
!tween.playing && tween.start();
}, false);
</script>
So, I added some custom SVG icons to my web app using <img src="/svg.svg">.
I then decided that I wanted to add a toggleClass() to show a clicked state. This led me to a little jQuery snippet which converts an IMG to a full blown svg:
jQuery('img.svg').each(function(){
var $img = jQuery(this);
var imgID = $img.attr('id');
var imgClass = $img.attr('class');
var imgURL = $img.attr('src');
jQuery.get(imgURL, function(data) {
// Get the SVG tag, ignore the rest
var $svg = jQuery(data).find('svg');
// Add replaced image's ID to the new SVG
if(typeof imgID !== 'undefined') {
$svg = $svg.attr('id', imgID);
}
// Add replaced image's classes to the new SVG
if(typeof imgClass !== 'undefined') {
$svg = $svg.attr('class', imgClass+' replaced-svg');
}
// Remove any invalid XML tags as per http://validator.w3.org
$svg = $svg.removeAttr('xmlns:a');
// Replace image with new SVG
$img.replaceWith($svg);
}, 'xml');
});
The result is that I end up getting a rather complicated SVG object, with a structure like this:
Parent: SVG
G
Path/Polygon
What I want, is to the target the entire SVG with a click event and to change the fill.
Template.tabsOne.events({
'click .replaced-svg': function(){
$(this).attr('fill', 'blue);
}
})
Unfortunately, I've tried several variations of the click handler and my svg refuses to change its fill. Any suggestions?
EDIT: here's one example:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Capa_1" x="0px" y="0px" width="209.217px" height="209.216px" viewBox="0 0 209.217 209.216" style="enable-background:new 0 0 209.217 209.216;" xml:space="preserve" class="svg custom-icon replaced-svg">
<g>
<polygon points="104.605,124.953 54.991,124.953 54.991,84.259 104.605,84.259 154.217,84.259 154.217,124.953 "></polygon>
<rect y="84.259" width="44.24" height="40.694"></rect>
<rect x="164.968" y="84.259" width="44.243" height="40.694"></rect>
<polygon points="209.217,73.509 159.593,73.509 109.98,73.509 109.98,22.174 209.217,22.174 "></polygon>
<polygon points="0,22.174 99.229,22.174 99.229,73.509 49.615,73.509 0,73.509 "></polygon>
<polygon points="0,135.704 49.615,135.704 99.229,135.704 99.229,187.042 0,187.042 "></polygon>
<polygon points="209.217,187.042 109.98,187.042 109.98,135.704 159.593,135.704 209.217,135.704 "></polygon>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>
Here's another one:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Layer_1" x="0px" y="0px" width="512px" height="640px" viewBox="0 0 512 640" enable-background="new 0 0 512 640" xml:space="preserve" class="black svg custom-icon replaced-svg">
<path d="M165.438,474.562c49.922,49.922,131.031,49.922,180.969,0c49.906-49.922,49.906-131.047,0-180.961L165.438,474.562z M448,0.32L64,0C28.641,0,0,28.641,0,64v512c0,35.359,28.641,64,64,64h384c35.359,0,64-28.641,64-64V64 C512,28.641,483.359,0.32,448,0.32z M192,64c17.602,0,32,14.398,32,32s-14.398,32-32,32s-32-14.398-32-32S174.398,64,192,64z M96,64 c17.602,0,32,14.398,32,32s-14.398,32-32,32s-32-14.398-32-32S78.398,64,96,64z M256,576c-106.078,0-192-85.922-192-192 s85.922-192,192-192s192,85.922,192,192S362.078,576,256,576z" fill="#000000"></path>
</svg>
Something like this (you need to change the fill attribute on the <path> element):
$(document).ready(function(){
$('svg').click(function(e){
$(this).find('path').attr('fill', '#cc0000');
});
});
See this fiddle for a running example
So in your example, this change should do it:
Template.tabsOne.events({
'click .replaced-svg': function(){
$(this).find('path').attr('fill', 'blue');
}
})
I am stuck at resizing an svg animation to a different percentages of the page.
I have created a circle that increases its size and then goes back to normal with this:
<svg id="mySVG" xmlns="http://www.w3.org/2000/svg" version="1.1">
<circle id="myCircle" cx="600" cy="250" r="70" fill="yellow" stroke="green" stroke-width="5">
<animate attributeName="r" values="70; 140; 210; 140; 70" dur="10s" repeatCount="indefinite"/>
</circle>
</svg>
Then, when I change the área size of the svg, the circle does not change its size nor the position within this area.
I have tried to scale the animation with CSS giving size to the body in pixels and then assign an area to the SVG in percentages:
body{
width: 1440px;
heigth: 990px
}
#mySVG{
width: 100%;
}
Also, I tried to change size with javascript:
function resize(){
var svg = document.getElementById("mySVG");
svg.style.width = window.innerWidht;
svg.style.height = window.innerHeight;
}
None of them worked… wondering what is the best method to scale SVG animations not only with this circle but with SVG animations in general.
Thank’s in advanced.
You have to use a viewbox to define the co-ordinate space. E.G.
<svg id="mySVG" xmlns="http://www.w3.org/2000/svg" version="1.1"
viewbox="0 0 1200 1200">
The viewBox attribute allows to specify that a given set of graphics
stretch to fit a particular container element.
The value of the viewBox attribute is a list of four numbers min-x,
min-y, width and height, separated by whitespace and/or a comma, which
specify a rectangle in user space which should be mapped to the bounds
of the viewport established by the given element, taking into account
attribute preserveAspectRatio.
<svg id="mySVG" xmlns="http://www.w3.org/2000/svg" version="1.1" viewbox="0 0 1200 1200">
<circle id="myCircle" cx="600" cy="250" r="70" fill="yellow" stroke="green" stroke-width="5">
<animate attributeName="r" values="70; 140; 210; 140; 70" dur="10s" repeatCount="indefinite" />
</circle>
</svg>
Useful SVG Resource Article # CSS-Tricks.com
MDN Link
I would like to convert an svg path animation, to a pure javascript one.
SVG code:
<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="340px" height="333px" viewBox="0 0 340 333" enable-background="new 0 0 340 333" xml:space="preserve">
<path class="path" fill="#FFFFFF" stroke="#000000" stroke-width="4" stroke-miterlimit="10" d="M66.039,133.545c0,0-21-57,18-67s49-4,65,8
s30,41,53,27s66,4,58,32s-5,44,18,57s22,46,0,45s-54-40-68-16s-40,88-83,48s11-61-11-80s-79-7-70-41
C46.039,146.545,53.039,128.545,66.039,133.545z"/>
</svg>
CSS code:
.path {
stroke-dasharray: 10 10; /* 10px fill, 10px gap */
-webkit-animation: dash 10s linear normal infinite;
}
#-webkit-keyframes dash {
from {
stroke-dashoffset: 1000;
}
to {
stroke-dashoffset: 0;
}
}
Here is the Fiddle
I'm not sure why you need pure javascript, also this answer may not fit your needs as it actually does create inline CSS. But here it is, mostly taken from : https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-dashoffset
function dashOffset() {
var path = document.querySelector('.path');
var length = "1000";
// Clear any previous transition
path.style.transition = path.style.WebkitTransition = 'none';
// Set up the starting positions
path.style.strokeDasharray = "10 10";
path.style.strokeDashoffset = "1000";
// Trigger a layout so styles are calculated & the browser
// picks up the starting position before animating
path.getBoundingClientRect();
// Define our transition
path.style.transition = path.style.WebkitTransition = 'stroke-dashoffset 10s linear';
//listener to restart our loop
path.addEventListener('transitionend', dashOffset, false);
// Go!
path.style.strokeDashoffset = '0';
}
dashOffset();
<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="340px" height="333px" viewBox="0 0 340 333" enable-background="new 0 0 340 333" xml:space="preserve">
<path class="path" fill="#FFFFFF" stroke="#000000" stroke-width="4" stroke-miterlimit="10" d="M66.039,133.545c0,0-21-57,18-67s49-4,65,8
s30,41,53,27s66,4,58,32s-5,44,18,57s22,46,0,45s-54-40-68-16s-40,88-83,48s11-61-11-80s-79-7-70-41
C46.039,146.545,53.039,128.545,66.039,133.545z" />
</svg>
There is also the requestAnimationFrame way :
function anim(){
var path = document.querySelector('.path');
path.style.strokeDasharray = "10 10";
path.style.strokeDashoffset--;
requestAnimationFrame(anim);
}
requestAnimationFrame(anim);
function anim(){
var path = document.querySelector('.path');
path.style.strokeDasharray = "10 10";
path.style.strokeDashoffset--;
requestAnimationFrame(anim);
}
requestAnimationFrame(anim);
<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="340px" height="333px" viewBox="0 0 340 333" enable-background="new 0 0 340 333" xml:space="preserve">
<path class="path" fill="#FFFFFF" stroke="#000000" stroke-width="4" stroke-miterlimit="10" d="M66.039,133.545c0,0-21-57,18-67s49-4,65,8
s30,41,53,27s66,4,58,32s-5,44,18,57s22,46,0,45s-54-40-68-16s-40,88-83,48s11-61-11-80s-79-7-70-41
C46.039,146.545,53.039,128.545,66.039,133.545z" />
</svg>
Note that you may be able to reproduce it with the pure SVG animateMotion element.
There are a few javascript SVG libraries you could look into. I'm partial to Raphael (www.raphaeljs.com).
It would be something like this:
var paper = Raphael('canvas', 600, 600);
paper.path("M66.039,133.545c0,0-21-57,18-67s49-4,65,8s30,41,53,27s66,4,58,32s- 5,44,18,57s22,46,0,45s-54-40-68-16s-40,88-83,48s11-61-11-80s-79-7-70-41C46.039,146.545,53.039,128.545,66.039,133.545z")
.attr({fill:"#FFFFFF", stroke: "#000000", "stroke-width": "4", "stroke-miterlimit": "10"})
fiddle: http://jsfiddle.net/xLekbar4/
(Note: I added a div to the html as a container for the raphael "canvas", and changed the css to apply to 'path' elements, instead of elements with class '.path')
I strongly recommend you give a try to the Raphael.js library.
Using it you could easily reproduce what you want.
Additionally there's this very useful tool to convert your SVG file into Raphael.js reusable code : http://www.readysetraphael.com/
So your SVG file will become :
var rsr = Raphael('rsr', '340', '333');
var path_a = rsr.path("M66.039,133.545c0,0-21-57,18-67s49-4,65,8s30,41,53,27s66,4,58,32s-5,44,18,57s22,46,0,45s-54-40-68-16s-40,88-83,48s11-61-11-80s-79-7-70-41C46.039,146.545,53.039,128.545,66.039,133.545z");
path_a.attr({
class: 'path',
fill: '#FFFFFF',
stroke: '#000000',
"stroke-width": '4',
"stroke-miterlimit": '10',
'stroke-opacity': '1'
}).data('id', 'path_a');
var rsrGroups = [];
Then you just have to add a <div id="rsr"></div> to your document and also replace the CSS selector .path to path.
Et voilà !
Check this Fiddle to see the it in action :
http://jsfiddle.net/47nkqgmn/
Overall, I have a rectangular SVG image separated into two halves which I would like to add an image to on click, however, when I import the SVG it creates only one PathGroup rather than two- Does anybody know how I can achieve two distinct PathGroups? I believe this is the first step in achieving my overall goal.
Here's how I'm loading the SVG:
fabric.loadSVGFromURL('./img/rect_w_two_halves.svg', function(objects, options){
loadedObject = fabric.util.groupSVGElements(objects, options);
loadedObject.set({
left:0,
top:0,
scaleY:.50,
scaleX:.50
});
canvas.add(loadedObject);
canvas.renderAll();
});
Here's how the image looks like:
Here's the SVG:
<svg version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="320px"
height="568px" viewBox="0 0 320 568" enable-background="new 0 0 320 568" xml:space="preserve">
<g id="Layer_2">
<line fill="none" stroke="#FFFFFF" stroke-width="15" stroke-miterlimit="10" x1="253.978" y1="284" x2="66.022" y2="284"/>
<path fill="none" stroke="#FFFFFF" stroke-width="15" stroke-miterlimit="10" d="M253.04,448.055
c0,10.338-8.381,18.719-18.719,18.719H85.68c-10.338,0-18.72-8.381-18.72-18.719V119.945c0-10.338,8.382-18.719,18.72-18.719
h148.642c10.338,0,18.719,8.381,18.719,18.719V448.055L253.04,448.055z"/>
</g></svg>
Thanks in advance as I've been really stuck on this issue.
You can add objects from SVG without grouping by passing every element into canvas.add method:
var canvas = new fabric.Canvas('mycanvas');
fabric.loadSVGFromURL(url);
function callback(objects, options) {
canvas.add.apply(canvas, objects);
canvas.renderAll();
}
There's a demo on Fabric.js website, you can find that part at Load SVG tab, "load without grouping" button