Moving image on scroll through svg path - javascript

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>

Related

Splitting the color of a curved text along a path in svg

I'm using SVG in HTML to draw a bended word along a path. Now that I managed to do draw the text, I need to split the word in 2 colors along the path that the word sits on. You can see the effect I'm trying to make in the image. Does anyone know how can I split the word in such a way? (I'm not sure if this matters, but the word is constantly bended, stretched and moved by the user, by modifying the "d" attribute of the path.)
var path = document.getElementById("Path");
var textPath = document.getElementById("TextPath");
document.onmousemove = function(e){
path.setAttribute("d", `M 100 100 q ${e.x-100} ${e.y-100} 230 0`);
textPath.setAttribute("textLength", path.getTotalLength() + "px")
}
svg {
width: 500px;
height: 500px;
}
<svg>
<path id="Path" d="M 100 100 q 50 -100 230 0" stroke="#000000" stroke-width="1" fill="none"></path>
<text id="Text" fill="#000000" font-size="64px">
<textPath startOffset="0%" id="TextPath" alignment-baseline="middle" href="#Path" startOffset="0%" startOffset="0%">Example</textPath>
</text>
</svg>
Here's a simpler version of what I have now. What I want to happen, is to color everything above the curve with one color and everything below with another.
One way of doing it: you use the text twice: once filled with color A and once filled with color B. Next you clip the second text with the path.
<svg viewBox="0 0 260 200">
<defs>
<path id="pth" d="M70,150 C10,40 240,40 180,150" stroke="red" fill="none" />
<text id="txt" font-size="45" text-anchor="middle" dominant-baseline="central">
<textPath font-size="35" startOffset="50%" href="#pth">
SSSSSSSSSSSS
</textPath>
</text>
<clipPath id="cp">
<use href="#pth" />
</clipPath>
</defs>
<use href="#txt" fill="blue" />
<use href="#txt" fill="orange" clip-path="url(#cp)" />
</svg>

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'

CSS JS animate image along path and make dashes afterwards

I would like to animate an image on a path and show the route of the object (e.g a plane flying over a map). It should look like on this image:
But the dashes should apply after the object has reached the position, so the dashes were shown after the object.
I have tried multiple times, but I can do only once. Dash animation or plane on path . Does someone knows a solution.
animate a mask over the dashed path
move the plane along the same path
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
version="1.1" height="200" width="400">
<defs>
<path id="basePath" d="M 50,150 A 280 500 0 0 1 350,150" />
<mask id="mask">
<use xlink:href="#basePath" stroke-width="3" stroke="white"
stroke-dasharray="1000,0" fill="none">
<animate attributeName="stroke-dasharray" from="0,348.5" to="348.5,0"
begin="0s" dur="5s" fill="freeze" />
</use>
</mask>
</defs>
<circle r="4" cx="50" cy="150" fill="grey" />
<circle r="4" cx="350" cy="150" fill="grey" />
<use xlink:href="#basePath" stroke-width="2" stroke-dasharray="10"
stroke="grey" fill="none" mask="url(#mask)"/>
<path d="M 27,3 H 21 L 13,15 H 9 L 12,3 H 5 L 3,7 H -1 L 1,0 -1,-7 H 3 L 5,-3 H 12 L 9,-15 H 13 L 21,-3 H 27 C 33,-3 33,3 27,3 Z"
fill="white" stroke="black" stroke-width="1.5">
<animateMotion rotate="auto" begin="0s" dur="5s" fill="freeze">
<mpath xlink:href="#basePath"/>
</animateMotion>
</path>
</svg>
The main thing to do is to calculate the length of the path, so you can set the stroke-dasharray values for the mask animation such that they keep pace with the animated plane. You can get that length in Javascript with
document.querySelector('#basePath').getTotalLength()

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