SVG Path Overlay and Animate Out Another Path - javascript

I have an SVG of a dashed gray line. What I want to do is overlay that on top of a green SVG dashed line, and animate out the gray to reveal the green. Sorta like a meter moving from right to left.
I saw this example of how to make a dash line:
http://jsfiddle.net/ehan4/2/
and was able to do it but my line is already dashed.
I ended up doing this:
<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"
viewBox="0 0 666.9 123.8" enable-background="new 0 0 666.9 123.8" xml:space="preserve">
<path opacity="0.4" stroke-width="3" fill="none" stroke="#66CD00" stroke-linecap="round" stroke-miterlimit="5" stroke-dasharray="1,6" d="
M656.2,118.5c0,0-320.4-251-645.9-0.7" />
<path id="top" opacity="0.4" fill="none" stroke="#AEAEAE" stroke-linecap="round" stroke-miterlimit="5" stroke-dasharray="1,6" d="
M656.2,118.5c0,0-320.4-251-645.9-0.7"/>
</svg>
var path = document.querySelector('#top');
var length = path.getTotalLength();
// Clear any previous transition
path.style.transition = path.style.WebkitTransition =
'none';
// Set up the starting positions
path.style.strokeDasharray = 1 + ' ' + 6;
path.style.strokeDashoffset = length;
// 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 20s linear';
// Go!
path.style.strokeDashoffset = '0';
https://jsfiddle.net/ps5yLyab/
How can I overlay the two dash lines and animate out the gray?

You can do it with a clip path.
First we add a clipPath to the SVG.
<defs>
<clipPath id="myclip">
<rect id="cliprect" x="100%" y="0%" width="100%" height="100%"/>
</clipPath>
</defs>
This clip path is sized the same size as the SVG (width and height 100%) and starts with its x postion at the far right of the SVG (100%). So at the start it is not revealing anything.
Then every 10mS we reduce it's x coord by 1% (ie 100% -> 99% -> 98% etc). until it reached zero.
var cliprect = document.getElementById("cliprect");
var offsetX = 100;
var speed = 10;
function clipAdjust()
{
cliprect.setAttribute("x", offsetX+"%");
offsetX -= 1;
if (offsetX >= 0) {
window.setTimeout(clipAdjust, speed);
}
}
window.setTimeout(clipAdjust, speed);
Working demo below:
var path = document.querySelector('#top');
var length = path.getTotalLength();
// Clear any previous transition
path.style.transition = path.style.WebkitTransition =
'none';
// Set up the starting positions
path.style.strokeDasharray = 1 + ' ' + 6;
path.style.strokeDashoffset = length;
// 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 20s linear';
// Go!
path.style.strokeDashoffset = '0';
var cliprect = document.getElementById("cliprect");
var offsetX = 100;
var speed = 10;
function clipAdjust()
{
cliprect.setAttribute("x", offsetX+"%");
offsetX -= 1;
if (offsetX >= 0) {
window.setTimeout(clipAdjust, speed);
}
}
window.setTimeout(clipAdjust, speed);
<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"
viewBox="0 0 666.9 123.8" enable-background="new 0 0 666.9 123.8" xml:space="preserve">
<defs>
<clipPath id="myclip">
<rect id="cliprect" x="100%" y="0%" width="100%" height="100%"/>
</clipPath>
</defs>
<path opacity="0.4" fill="none" stroke="#AEAEAE" stroke-linecap="round"
stroke-miterlimit="5" stroke-dasharray="1,6" stroke-width="2"
d="M656.2,118.5c0,0-320.4-251-645.9-0.7"/>
<g clip-path="url(#myclip)">
<path stroke-width="3" fill="none" stroke="white"
stroke-linecap="round" stroke-miterlimit="5"
d="M656.2,118.5c0,0-320.4-251-645.9-0.7" />
<path id="top" opacity="0.4" stroke-width="3" fill="none" stroke="#66CD00"
stroke-linecap="round" stroke-miterlimit="5" stroke-dasharray="6,6"
d="M656.2,118.5c0,0-320.4-251-645.9-0.7" />
</g>
</svg>

Related

Scripted SVG animation no-longer working in some browsers

I am trying to work out why the code below no-longer works in Firefox or Chrome.
The files were last modified over ten years ago.
The static svg dispays, but the script does not run. To my considerable surprise, it does work as it should in Edge, as does a more complicated diagram with interactive elements.
There is probably some obscure setting I need to doctor in Firefox, but I don't know where to look. I don't know when I last tried one of these files, but I would be fairly sure they still worked a couple of years ago.
The code is probably full of daftnesses, as I have done very little javascript, and I probably should now be using requestanimationframe, but that is not the point - it has worked, and still does in Edge.
(Question edited to remove link to irrelevant SMIL version of the animation.)
This is the html file:
<html>
<head>
<title>
SVG slider-crank animated by script
</title>
</head>
<body onload="main()">
<script type="text/javascript">
<!--
var svgdoc = null;
var crank = null;
var crosshead = null;
var conrod = null;
var pi = Math.PI;
function main()
{
var timer = null;
var angle = 0;
var diagram = document.getElementById('svg');
if (diagram && diagram.contentDocument)
{
svgdoc = diagram.contentDocument;
}
else
{
try
{
svgdoc = diagram.getSVGDocument();
}
catch(exception)
{
alert("Unable to get SVG document");
}
}
crank = svgdoc.getElementById('ShowCrank');
crosshead = svgdoc.getElementById('ShowCrosshead');
conrod = svgdoc.getElementById('ShowConRod');
timer = setInterval(function(){(angle = rotation(angle))}, 25);
}
function rotation(angle)
{
var step = 3;
var theta = angle * pi / 180;
var alpha = Math.asin(Math.sin(theta) / 5);
var offset = 100 * (Math.cos(theta) -1) - 500 * (Math.cos(alpha) - 1);
crank.setAttributeNS(null, 'transform', ("rotate(" + angle + ", 800, 300)"));
crosshead.setAttributeNS(null, 'transform', ("translate(" + offset + ", 0)"));
conrod.setAttributeNS(null, 'transform', ("translate(" + offset + ", 0) rotate(" + (alpha * 180 / pi) + ", 400, 300)"));
angle = angle < 360 - step ? angle + step : 0;
return angle;
}
-->
</script>
<object id="svg" type="image/svg+xml" data="Slider_Crank.svg" width="1200" height="800">
<param name="src" value="Slider_Crank.svg">
</object>
</body>
</html>
This is the svg file:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1"
baseProfile="full"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:ev="http://www.w3.org/2001/xml-events"
width="1200"
height="800">
<title> Slider-Crank </title>
<defs>
<rect
id="Slidebar"
stroke-width="1"
stroke="black"
fill="silver"
fill-opacity="1"
x="0"
y="-12"
width="300"
height="24"
/>
<g id="Crosshead" stroke-width="1" stroke="black" fill-opacity="1">
<rect
fill="gold"
x="-50"
y="-25"
width="100"
height="50"
/>
<circle cx="0" cy="0" r="15" fill="white"/>
</g>
<g id="Crank" stroke-width="1" stroke="black" fill-opacity="1">
<path fill="silver"
d="M 99.959 40.000
A 40 40 0 0 0 99.959, -40.000
A 450 450 0 0 1 9.950, -49.000
A 50 50 0 1 0 9.950, 49.000
A 450 450 0 0 1 99.959, 40.000
z"/>
<circle cx="100" cy="0" r="25" fill="white"/>
<circle cx="0" cy="0" r="30" fill="lightgrey"/>
</g>
<g id="ConRod" stroke-width="1" stroke="black" fill-opacity="0.7">
<path fill="silver"
d="M 12.387 21.715
A 30 30 0 0 1 27.551 17.776
L 453.475 22.035
A 30 30 0 0 1 473.243 29.733
A 40 40 0 0 1 473.243 -29.733
A 30 30 0 0 1 453.475 -22.035
L 27.551 -17.776
A 30 30 0 0 1 12.387 -21.715
A 25 25 0 0 1 12.387 21.715
z"/>
<circle cx="0" cy="0" r="25" fill="silver"/>
<circle cx="0" cy="0" r="15" fill="white"/>
<circle cx="500" cy="0" r="40" fill="silver"/>
<circle cx="500" cy="0" r="25" fill="white"/>
</g>
</defs>
<use id="ShowTopSlidebar" xlink:href="#Slidebar" x="150" y="263"/>
<use id="ShowBottomSlidebar" xlink:href="#Slidebar" x="150" y="337"/>
<use id="ShowCrosshead" xlink:href="#Crosshead" x="400" y="300"/>
<use id="ShowCrank" xlink:href="#Crank" x="800" y="300"/>
<use id="ShowConRod" xlink:href="#ConRod" x="400" y="300"/>
</svg>
Thanks to Robert Longson: Firefox about:config setting 'security.fileuri.strict_origin_policy'

How to change the href of this SVG sprite using vanilla JavaScript?

I am using an SVG sprite sheet and I am trying to change the href of the svg using vanilla javascript, but after researching a solution, have run into a brick wall.
html
let scores, roundScore, activePlayer, dice, diceSvg, diceImg, diceHrefString;
scores = [0,0];
roundScore = 0;
activePlayer = 0;
document.querySelector(`#p${activePlayer}c-score`).textContent = dice;
diceSvg = document.getElementById("dice-icon");
diceSvg.style.display = "none";
document.getElementById("roll-dice").addEventListener("click",function(){
dice = Math.floor(Math.random() * 6) + 1;
diceImg = document.querySelector(".dice-icon");
diceHrefString = `dice_sprite_sheet.svg#dice-${dice}`;
if(dice !== 0){
diceImg.setAttributeNS("xlink:","href",diceHrefString);
}else{
diceImg.setAttributeNS("xlink:","href","dice");
}
diceSvg.style.display = "block";
});
<svg class="dice-icon" id="dice-icon">
<use xlink:href="dice_sprite_sheet.svg#dice"></use>
</svg>
As I've commented: you need to use the svg xlink namespace: http://www.w3.org/1999/xlink. When you change the value of the xlink:href dynamically this is how you do it: theUse.setAttributeNS(SVG_XLINK, 'xlink:href', '#theId');
This is an example:
const SVG_XLINK = "http://www.w3.org/1999/xlink";
theUse.setAttributeNS(SVG_XLINK, 'xlink:href', '#spade');
svg{border:1px solid}
<svg class="dice-icon" id="dice-icon" viewBox="0 0 20 20" width="200" height="200">
<use id="theUse" xlink:href="#heart"></use>
</svg>
<svg width="0" height="0" display="none">
<title>symbols defs</title>
<defs>
<symbol viewBox="0 0 20 20" id="spade" style="overflow: visible">
<title>Spade</title>
<path d="M9,15C9,20 0,21 0,16S6,9 10,0C14,9 20,11 20,16 S11,20 11,15Q11,20 13,20H7Q9,20 9,15Z"/>
</symbol>
<symbol viewBox="0 0 20 20" id="heart" style="overflow: visible">
<title>heart</title>
<path d="M10,6 Q10,0 15,0T20,6Q20,10 15,14 T10,20Q10,18 5,14T0,6Q0,0 5,0T10,6Z"/>
</symbol>
</defs>
</svg>
I hope it helps.

Moving image on scroll through svg path

I want to move object through svg path on scroll=) I was trying to add parts of path on scroll into path, but it still doesn't work. Help!!!=)
https://jsfiddle.net/YuriiBielozertsev/Ltx9ed0L/
<?xml version="1.0"?>
<svg viewBox="0 0 120 120" xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Draw the outline of the motion path in grey, along with 2 small circles at key points -->
<path d="M10,110 A120,120 -45 0,1 110 10 A120,120 -45 0,1 10,110" stroke="green" stroke-width="2" fill="none" id="theMotionPath"/>
<circle cx="10" cy="110" r="3" fill="#000"/>
<circle cx="110" cy="10" r="3" fill="#000"/>
<!-- Red circle which will be moved along the motion path. -->
<circle cx="0" cy="" r="5" fill="red">
<!-- Define the motion path animation -->
<animateMotion dur="6s" repeatCount="indefinite">
<mpath xlink:href="#theMotionPath"/>
</animateMotion>
</circle>
</svg>
Something like this?
How this works:
When we get a scroll event we:
Calculate how far down the page we are
Convert this percentage to a position on the path using the <path> element functions getTotalLength() and getPointAtLength().
Reposition the dot so that it appears at this point.
function positionTheDot() {
// What percentage down the page are we?
var scrollPercentage = (document.documentElement.scrollTop + document.body.scrollTop) / (document.documentElement.scrollHeight - document.documentElement.clientHeight);
// Get path length
var path = document.getElementById("theMotionPath");
var pathLen = path.getTotalLength();
// Get the position of a point at <scrollPercentage> along the path.
var pt = path.getPointAtLength(scrollPercentage * pathLen);
// Position the red dot at this point
var dot = document.getElementById("dot");
dot.setAttribute("transform", "translate("+ pt.x + "," + pt.y + ")");
};
// Update dot position when we get a scroll event.
window.addEventListener("scroll", positionTheDot);
// Set the initial position of the dot.
positionTheDot();
.verylong {
height: 2000px;
}
svg {
position: fixed;
width: 200px;
height: 200px;
}
<svg viewBox="0 0 120 120" xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Draw the outline of the motion path in grey, along with 2 small circles at key points -->
<path d="M10,110 A120,120 -45 0,1 110 10 A120,120 -45 0,1 10,110" stroke="green" stroke-width="2" fill="none" id="theMotionPath"/>
<circle cx="10" cy="110" r="3" fill="#000"/>
<circle cx="110" cy="10" r="3" fill="#000"/>
<!-- Red circle which will be moved along the motion path. -->
<circle cx="0" cy="0" r="5" fill="red" id="dot"/>
</svg>
<div class="verylong">
</div>

SVG animation reduces width of separate vector in file

I've been messing around with SVG path animations. My SVG has 2 layers in it; a grey egg and an orange egg. The orange egg animates over the top of the grey egg, this part works fine. However, both paths technically have the same width, but when I animate the orange egg, the grey egg's path looks like it's reduced by 50%.
Below is an image and the code.
var path = document.querySelector('#egg-orange path');
var length = path.getTotalLength();
var percent = length/100;
var desiredPercent = 50;
var currentPercent = percent * (100 - desiredPercent); // 50%
// Clear any previous transition
path.style.transition = path.style.WebkitTransition =
'none';
// Set up the starting positions
path.style.strokeDasharray = length + ' ' + length;
path.style.strokeDashoffset = length;
// 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 2s ease-in-out';
// Go!
path.style.strokeDashoffset = currentPercent;
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 104.7 144.3" enable-background="new 0 0 104.7 144.3" xml:space="preserve">
<g id="egg-grey">
<path fill="#FFFFFF" stroke="#414042" stroke-width="10" stroke-miterlimit="10" d="M99.3,92.2c0,25.7-20.8,46.5-46.5,46.5
S6.3,117.8,6.3,92.2S27.2,5.7,52.8,5.7S99.3,66.5,99.3,92.2z"/>
</g>
<g id="egg-orange">
<path fill="#FFFFFF" stroke="#F15A29" stroke-width="10" stroke-miterlimit="10" d="M99.3,92.2c0,25.7-20.8,46.5-46.5,46.5
S6.3,117.8,6.3,92.2S27.2,5.7,52.8,5.7S99.3,66.5,99.3,92.2z"/>
</g>
</svg>
I found out that the issue was because of the white fill on the orange egg. All i needed to do was add fill-opacity="0" and hey presto, all sorted!
<g id="egg-orange">
<path fill="#fff" fill-opacity="0" stroke="#F15A29" stroke-width="10" stroke-miterlimit="10" d="M99.3,92.2c0,25.7-20.8,46.5-46.5,46.5
S6.3,117.8,6.3,92.2S27.2,5.7,52.8,5.7S99.3,66.5,99.3,92.2z"/>
</g>
EDIT:
As Paul mentioned below, you can just set fill to none and not need to touch opacity.
<g id="egg-orange">
<path fill="none" stroke="#F15A29" stroke-width="10" stroke-miterlimit="10" d="M99.3,92.2c0,25.7-20.8,46.5-46.5,46.5
S6.3,117.8,6.3,92.2S27.2,5.7,52.8,5.7S99.3,66.5,99.3,92.2z"/>
</g>

How to fill svg when scrolling

I have svg line:
<svg class="filling" width="500" height="10" version="1.1" xmlns="http://www.w3.org/2000/svg">
<path data-over-line="" d="M90,5 L500,5" stroke="#e2e2e2" fill="transparent" stroke-width="4" style="stroke-dashoffset: 0px;"></path>
</svg>
I need when scroll the page it is gradually filled with a different color. How to do it?
I am not sure what shape you ultimately want for your scrollbar, but here is a simple solution. We draw a blue line on top of your grey line to indicate scroll progress. The length of the line is determined by calculating how far done the page we have scrolled.
If you ultimately want to have the scrollbar be a shape other than a line or a rectangle, you will need to take a different approach.
SVG (modified a little):
<svg class="filling" width="500" height="10" version="1.1" xmlns="http://www.w3.org/2000/svg">
<line x1="90" y1="5" x2="500" y2="5" stroke="#e2e2e2" fill="transparent" stroke-width="4" />
<line x1="90" y1="5" x2="90" y2="5" stroke="blue" fill="transparent" stroke-width="4" id="scrollprogress" />
</svg>
JS:
window.onscroll = function (event) {
var offset = window.pageYOffset;
var wheight = window.innerHeight;
var html = document.documentElement;
var docheight = Math.max(document.body.scrollHeight, document.body.offsetHeight,
html.clientHeight, html.scrollHeight, html.offsetHeight);
var progress = offset / (docheight - wheight);
// Give the line a CSS gradient based on scroll position
document.getElementById("scrollprogress").setAttribute("x2", 90 + progress * 410);
}
Demo fiddle

Categories

Resources