I was trying to implement fisheye-esque filter in my SVG and found this codepen:
http://codepen.io/johanberonius/pen/RopjYW
It works perfectly fine except I want this effect to be slightly "harder", but I couldn't change displacement map since it generated in js.
var canvas = document.getElementById('canvas'),
barrel = document.getElementById('filter-image'),
width = canvas.width,
height = canvas.height,
ctx = canvas.getContext('2d');
for (var y = 0; y < height; y++) {
for (var x = 0; x < width; x++) {
var dx = x - 128,
dy = y - 128,
l = Math.sqrt(dx * dx + dy * dy),
a = l < 128 ? Math.asin(l/128) : 0,
z = l < 128 ? 255 - Math.cos(a) * 255 : 0,
r = l < 128 ? 128 + (dx / 128) * (z / 255) * 128 : 0,
g = l < 128 ? 128 + (dy / 128) * (z / 255) * 128 : 0,
o = l >= 124 ? Math.max(0, 1 - (l-124)/4) : 1;
ctx.fillStyle = 'rgba('+Math.floor(r)+','+Math.floor(g)+',0,'+o+')';
ctx.fillRect(x,y,1,1);
}
}
barrel.setAttribute('xlink:href', canvas.toDataURL());
var tx = 0,
ty = 0;
requestAnimationFrame(function updateAnimationFrame() {
tx += 0.027;
ty += 0.031;
barrel.setAttribute('x', 128 + Math.sin(tx) * 120);
barrel.setAttribute('y', 128 + Math.cos(ty) * 120);
requestAnimationFrame(updateAnimationFrame);
});
Formula is WAY too advanced for me to hack.
So I was wondering is there any way I can generate these types of maps or maybe someone can help me with a formula.
The displacement map could, at least roughly equivalent, be constructed as a SVG filter itself.
So you would think that you might be able to combine the drawing of the displacement map and its application to the image, in one SVG file. It turns out you can not, as browsers do not implement enable-background.
But, distributed among two files, it works. First, the displacement map:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
version="1.1" height="300" width="300">
<defs>
<filter id="barrel" x="-30%" y="-30%" width="160%" height="160%"
color-interpolation-filters="sRGB">
<feGaussianBlur result="result1" stdDeviation="10" />
<feMorphology operator="erode" radius="5" result="result5" />
<feColorMatrix result="result3" type="matrix"
values="0 0 0 -0.3 0.8 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 " />
<feOffset result="result4" dy="-5" dx="5" />
<feColorMatrix result="result2" in="result5" type="matrix"
values="0 0 0 0 0 0 0 0 -0.3 0.8 0 0 0 0 0 0 0 0 0 1 " />
<feOffset dy="5" dx="-5" />
<feComposite result="result6" k3="1" k2="1" operator="arithmetic" in2="result4" />
</filter>
<clipPath id="cp" clipPathUnits="userSpaceOnUse">
<circle r="100" cx="150" cy="150" />
</clipPath>
</defs>
<circle clip-path="url(#cp)" filter="url(#barrel)"
cy="150" cx="150" r="100" />
</svg>
And secondly, the application to the image:
<svg width="512" height="512" viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<filter id="barrel">
<feImage id="filter-image" xlink:href="circle.svg" result="barrel"
x="64" y="64" width="256" height="256" />
<feDisplacementMap in2="barrel" in="SourceGraphic"
xChannelSelector="R" yChannelSelector="G" scale="64" />
<feComposite operator="in" in2="barrel"/>
</filter>
</defs>
<image xlink:href="https://i.imgsafe.org/3353aef52f.jpg"
x="0" y="0" height="512" width="512"/>
<image xlink:href="https://i.imgsafe.org/3353aef52f.jpg"
x="-16" y="-16" height="512" width="512" filter="url(#barrel)"/>
</svg>
I produced this with the Inkscape Filter editor, which gives a fair grafical interface for manipulating the filter components. You should probably experiment some more. Numbers to play around with probably are:
feGaussianBlur blur radius - the width of the colored border, it would be my first candidate for what you call "sharpness"
feMorphology erode radius should probably always be half the value of the blur radius
feOffset dx/dy displace the red and green components relative to each other
feColorMatrix Those number that are not zero could be variated. Look in the filter editor for an explanation.
Related
I need to create strokes similar in length but of different angles of rotations so instead of having a several redundant lines of codes, I preferred using JavaScript to that as follows;
function stroke(rot) {
var dash=document.createElementNS("http://www.w3.org/2000/svg", "path");
dash.setAttributeNS(null,"id","dash");
dash.setAttributeNS(null,"d","M 180 0 L 200 0");
dash.setAttributeNS(null,"transform","rotate(+"+rot+" 200 200)");
dash.setAttributeNS(null,"fill","none");
dash.setAttributeNS(null, "stroke","black");
dash.setAttributeNS(null, "stroke-width","5");
document.appendChild(dash);
}
for(i=0;i<360;i+=10) stroke(i);
i is the value to which the stroke will be rotated when stroke(i) will be called.
I checked a solution from here to fix my code but
unfortunately this doesn't woks, any solution to this ?
The problem is you trying to append paths into a document, not in SVG element.
const svgTarget = document.getElementById("draw");
function stroke(rot) {
let dash = document.createElementNS("http://www.w3.org/2000/svg", "path");
dash.setAttributeNS(null, "id", "dash");
dash.setAttributeNS(null, "d", "M 180 5 L 200 5");
dash.setAttributeNS(null, "transform", "rotate(+" + rot + " 200 200)");
dash.setAttributeNS(null, "fill", "none");
dash.setAttributeNS(null, "stroke", "black");
dash.setAttributeNS(null, "stroke-width", "5");
svgTarget.appendChild(dash);
}
for (i = 0; i < 360; i += 10) stroke(i);
<svg id="draw" viewBox="0 0 400 400" width="200px" height="200px"></svg>
Since a parsed <svg id="draw"> already is in the correct NameSpace;
you can add content with Strings, no need to add those <path> in the SVG NameSpace (again)
As Robert said, a <circle> with stroke-dasharray gives a better result (drawn paths are straight),
does not require JavaScript and can easily be changed.
https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/pathLength
https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-dasharray
for (i = 0; i < 360; i += 10) {
document.getElementById("draw")
.innerHTML += `<path d="M180 5L200 5"
transform="rotate(${i} 200 200)"
fill="none" stroke="black" stroke-width="5"/>`;
}
<svg id="draw" viewBox="0 0 400 400" height="180px"></svg>
<svg id="circle" viewBox="0 0 400 400" height="180px">
<circle stroke-width="5" r="197.5" fill="none" stroke="red" cx="200" cy="200"
pathLength="72" stroke-dasharray="1"/>
</svg>
Using the answer from this thread I was able to draw a semicircle (arc):
function polarToCartesian(centerX, centerY, radius, angleInDegrees) {
var angleInRadians = (angleInDegrees - 90) * Math.PI / 180.0;
return {
x: centerX + (radius * Math.cos(angleInRadians)),
y: centerY + (radius * Math.sin(angleInRadians))
};
}
function describeArc(x, y, radius, startAngle, endAngle) {
var start = polarToCartesian(x, y, radius, endAngle);
var end = polarToCartesian(x, y, radius, startAngle);
var largeArcFlag = endAngle - startAngle <= 180 ? "0" : "1";
var d = [
"M", start.x, start.y,
"A", radius, radius, 0, largeArcFlag, 0, end.x, end.y
].join(" ");
console.log(d)
return d;
}
window.onload = function() {
document.getElementById("arc1").setAttribute("d", describeArc(100, 100, 50, -90, 90));
};
<svg width="1000" height="1000">
<path id="arc1" fill="red" stroke="#446688" stroke-width="2" />
</svg>
What I'm trying to achieve is to be able to draw an SVG as a path consistent with many arcs (semicircles) and be able to set fill on them.
Something like this:
<svg xmlns="http://www.w3.org/2000/svg">
<path d="M 50 100 A 10 10 0 0 1 100 100 M 100 100 A 10 10 0 0 1 150 100 M 150 100 A 10 10 0 0 1 200 100 M 200 100 A 10 10 0 0 1 250 100" fill="red" stroke="blue" stroke-width="3" />
</svg>
Is there a better way to achieve a simpler path? For now, it looks like this:
<svg xmlns="http://www.w3.org/2000/svg">
<path d="M 50 100 A 10 10 0 0 1 100 100 M 100 100 A 10 10 0 0 1 150 100 M 150 100 A 10 10 0 0 1 200 100 M 200 100 A 10 10 0 0 1 250 100" fill="red" stroke="blue" stroke-width="3" />
</svg>
Or do I have to generate a longer and longer path when there are, let's say, 30 semicircles?
Edit: the IE9+ support is required. Also, those elements will be clickable, draggable and controllable. By controllable I mean that their number and size will change when mouse clicking/moving.
I choose my first approach with a dynamic very long path.
Thanks!
For this I would use lower case commands. For example this is drawing the arc you need: an arc with a radius of 25 and an ending point 50 units ( 2 * 25 ) away from the starting point of the arc.
<svg xmlns="http://www.w3.org/2000/svg">
<path d="M 50 100 a 25 25 0 0 1 50 0" fill="red" stroke="blue" stroke-width="3" />
</svg>
In order to get a path of 4 arcs you need to repeat the arc (a 25 25 0 0 1 50 0) 4 times something like this:
<svg xmlns="http://www.w3.org/2000/svg">
<path d="M 50 100 a 25 25 0 0 1 50 0
a 25 25 0 0 1 50 0
a 25 25 0 0 1 50 0
a 25 25 0 0 1 50 0 " fill="red" stroke="blue" stroke-width="3" />
</svg>
It's easy to see how you can use javascript to generate the d attribute you need:
let d ="M 50 100";
for(let i=0; i<4;i++){d +="a 25 25 0 0 1 50 0 "}
document.querySelector("path").setAttribute("d",d);
<svg xmlns="http://www.w3.org/2000/svg">
<path d="M 50 100" fill="red" stroke="blue" stroke-width="3" />
</svg>
You can use a vanilla JavaScript Web Component (supported in all modern Browsers) to create the SVG
Your Custom Element <svg-arcs repeat="7"></svg-arcs> then creates:
<style>
svg { background: pink }
svg path { stroke-width: 3 }
</style>
<svg-arcs repeat="30"></svg-arcs>
<script>
customElements.define("svg-arcs", class extends HTMLElement {
connectedCallback() {
let repeat = this.getAttribute("repeat") || 5;
let svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
for (let x = 0; x < repeat; x++) {
let path = document.createElementNS("http://www.w3.org/2000/svg", "path");
path.setAttribute("d", `M${3 + 50*x} 100 A 10 10 0 0 1 ${50+50*x} 100`);
path.setAttribute("fill", "red");
path.setAttribute("stroke", "blue");
svg.append(path);
}
svg.setAttribute("viewBox", `0 0 ${50*repeat + 3} 150`);
this.append(svg);
}
})
</script>
For more dynamic control over individual arcs see the Web Component in SO post:
Firefox: shadow-DOM compatibility
You could use a pattern and size your patterned object appropriately. Here is one that accomodates 4 iterations.
Edit & Update:
If you want those arcs to be independently clickable/draggable, then they need to be separately addressable in the DOM. The "use" element might be what you're looking for.
svg {
background: grey;
}
<svg width="800px" height="600px">
<defs>
<path id="arc-template" d="M1.5 50 a 10 10 0 0 1 97 0" fill="red" stroke="blue" stroke-width="3" />
</defs>
<use id="arc1" href="#arc-template" x="50" y="100"/>
<use id="arc2" href="#arc-template" x="150" y="100"/>
<use id="arc3" href="#arc-template" x="250" y="100"/>
<use id="arc4" href="#arc-template" x="350" y="100"/>
</svg>
My goal is to design an arc slider which looks something like that
I have the following structure of the template
<svg width="500" height="300">
<path id="track" stroke="lightgrey" fill="transparent" stroke-width="20" d="
M 50 50
A 90 90 0 0 0 300 50
"/>
<path id="trackFill" fill="cyan" stroke-width="20" d="
M 50 50
A 90 90 0 0 0 [some dynamic value?] [some dynamic value?]
"/>
<circle id="knob" fill="lightblue" cx="[dynamic, initial - 50]" cy="[dynamic, initial - 50]" r="25"/>
</svg>
knob - the control which user is supposed to drag in order to change the value
track - the full arc of the slide
trackFill - the portion of the slider path before the knob
Is it possible to make trackFill cover the portion of the slider before the knob as it is being dragged along the slider curve? If so which APIs or CSS rules will help me to achieve such a result?
Is it something like this you are after?
let svg = document.getElementById("slider");
let trackFill = document.getElementById("trackFill");
let knob = document.getElementById("knob");
let isDragging = false;
let sliderDragOffset = {dx: 0, dy: 0};
let ARC_CENTRE = {x: 175, y: 50};
let ARC_RADIUS = 125;
let sliderValue = 0;
setSliderValue(sliderValue);
function setSliderValue(value)
{
// Limit value to (0..sliderMax)
let sliderMax = track.getTotalLength();
sliderValue = Math.max(0, Math.min(value, sliderMax));
// Calculate new position of knob
let knobRotation = sliderValue * Math.PI / sliderMax;
let knobX = ARC_CENTRE.x - Math.cos(knobRotation) * ARC_RADIUS;
let knobY = ARC_CENTRE.y + Math.sin(knobRotation) * ARC_RADIUS;
// Adjust trackFill dash patter to only draw the portion up to the knob position
trackFill.setAttribute("stroke-dasharray", sliderValue + " " + sliderMax);
// Update the knob position
knob.setAttribute("cx", knobX);
knob.setAttribute("cy", knobY);
}
knob.addEventListener("mousedown", evt => {
isDragging = true;
// Remember where we clicked on knob in order to allow accurate dragging
sliderDragOffset.dx = evt.offsetX - knob.cx.baseVal.value;
sliderDragOffset.dy = evt.offsetY - knob.cy.baseVal.value;
// Attach move event to svg, so that it works if you move outside knob circle
svg.addEventListener("mousemove", knobMove);
// Attach move event to window, so that it works if you move outside svg
window.addEventListener("mouseup", knobRelease);
});
function knobMove(evt)
{
// Calculate adjusted drag position
let x = evt.offsetX + sliderDragOffset.dx;
let y = evt.offsetY + sliderDragOffset.dy;
// Position relative to centre of slider arc
x -= ARC_CENTRE.x;
y -= ARC_CENTRE.y;
// Get angle of drag position relative to slider centre
let angle = Math.atan2(y, -x);
// Positions above arc centre will be negative, so handle them gracefully
// by clamping angle to the nearest end of the arc
angle = (angle < -Math.PI / 2) ? Math.PI : (angle < 0) ? 0 : angle;
// Calculate new slider value from this angle (sliderMaxLength * angle / 180deg)
setSliderValue(angle * track.getTotalLength() / Math.PI);
}
function knobRelease(evt)
{
// Cancel event handlers
svg.removeEventListener("mousemove", knobMove);
window.removeEventListener("mouseup", knobRelease);
isDragging = false;
}
<svg id="slider" width="500" height="300">
<g stroke="lightgrey">
<path id="track" fill="transparent" stroke-width="20" d="
M 50 50
A 125 125 0 0 0 300 50
"/>
</g>
<use id="trackFill" xlink:href="#track" stroke="cyan"/>
<circle id="knob" fill="lightblue" cx="50" cy="50" r="25"/>
</svg>
I've kept this code simple for clarity, but at the expense of some limitations.
It assumes there is only one slider per page. If you need more than that, you will have to keep the slider-specific values (eg sliderValue and, isDragging) separate. You could use data attributes for that. You would also need to switch from accessing the SVG elements via id attributes to another way (eg. class attributes), because id attributes must be unique on the page.
Here is a simple example:
const radius = 50;
const offsetX = 10;
const offsetY = 10;
// 0 <= pos <= 1
const setSliderPos = (svg, pos) => {
const angle = Math.PI * pos;
const x = offsetX + radius - Math.cos(angle) * radius;
const y = offsetY + Math.sin(angle) * radius;
svg.select('.knob').attr('cx', x).attr('cy', y);
svg.select('.first').attr('d', `M ${offsetX},${offsetY} A ${radius},${radius} 0 0 0 ${x},${y}`);
svg.select('.second').attr('d', `M ${x},${y} A ${radius},${radius} 0 0 0 ${offsetX + radius * 2},${offsetY}`);
}
setSliderPos(d3.select('#svg-1'), 0.3);
setSliderPos(d3.select('#svg-2'), 0.6);
setSliderPos(d3.select('#svg-3'), 1);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg id="svg-1" width="150" height="80">
<path class="first" stroke-width="5" stroke="lightblue" fill="none"/>
<path class="second" stroke-width="5" stroke="cyan" fill="none"/>
<circle class="knob" r="10" fill="lightblue"/>
</svg>
<svg id="svg-2" width="150" height="80">
<path class="first" stroke-width="5" stroke="lightblue" fill="none"/>
<path class="second" stroke-width="5" stroke="cyan" fill="none"/>
<circle class="knob" r="10" fill="lightblue"/>
</svg>
<svg id="svg-3" width="150" height="80">
<path class="first" stroke-width="5" stroke="lightblue" fill="none"/>
<path class="second" stroke-width="5" stroke="cyan" fill="none"/>
<circle class="knob" r="10" fill="lightblue"/>
</svg>
To mark the progress you can use stroke-dasharray with a percentage; for example
<g stroke="lightgrey">
<path id="track" fill="transparent" stroke-width="20"
stroke-dasharray="40% 60%"
d="M 50 50 A 125 125 0 0 0 300 50"/>
</g>
This will show 40% of the arc and hide 60% of the arc.
If you need to use two colors, for example the whole arc in grey and the progress in black, you need to use two arcs on top of one another; the one at the bottom would be the one you already have, and the one at the top would have a stroke in black and use stroke-dasharray as shown.
I need to check the response of a user by tracking the mouse movement over a moving object (in this case a circle). If the mouse is not over the circle I need to calculate the offset by comparing the mouse coordinates and the circle coordinates.
But whenever I check the circle values, they are not changing and will stay on their initial value.
Here's a simple example:
function clickCircle() {
var circle = document.getElementById("circle");
console.log('baseVal x: ' + circle.cx.baseVal.value);
console.log('animVal x: ' + circle.cx.animVal.value);
}
<p>Click on the moving circle</p>
<svg width="1200" height="1200">
<circle id="circle" cx="60" cy="60" r="20" fill="green" onclick="clickCircle();">
<animateMotion id="ani" dur="10s" repeatCount="indefinite"
path="M20, 60 C20,
-50 180, 150 180,
60 C180-60 20,
150 20, 60 z" />
</circle>
</svg>
Does anybody have any idea on how to get the coordinates from a moving circle that is being animated with animateMotion?
You could drag in an animation Icon, and track its properties
Or with JavaScript you calculate its center x,y position with:
let {width,height} = circle.getBBox();
let {x,y} = circle.getBoundingClientRect();
x = x + width/2;
y = y + height/2;
Also read: https://schneide.blog/2018/03/05/some-tricks-for-working-with-svg-in-javascript/
note! this code below will forever add circle Nodes!
<style> svg { width: 300px } </style>
<svg viewBox="0 0 300 200">
<rect width="100%" height="100%" fill="lightgreen"></rect>
<text x=10 y="20">Click the circle!</text>
<circle id="circle" cx="40" cy="40" r="40" fill="green"
onclick="clickCircle(event)">
<animateMotion id="ani" dur="10s" repeatCount="indefinite" path="m20 40c0-110 160 90 160 0c0-120-160 90-160 0z" />
</circle>
<text id="position" x="200" y="20">21</text>
</svg>
<script>
function clickCircle(evt) {
point("gold");
}
function point(color) {
let circle = document.getElementById("circle");
let {width,height} = circle.getBBox();
let {x,y} = circle.getBoundingClientRect();
let c = document.createElementNS("http://www.w3.org/2000/svg", "circle");
x = x + width/2;
y = y + height/2;
c.setAttribute("cx", x);
c.setAttribute("cy", y);
c.setAttribute("r", color == "black" ? 3 : 6);
c.setAttribute("fill", color);
circle.parentNode.append(c);
position.innerHTML = `${~~x} , ${~~y}`;
}
setInterval(() => point("black"), 250);
</script>
Or try the JSFiddle: https://jsfiddle.net/dannye/ph705b49/
Dan was Authorware toch heel wat makkelijker...
Alles goed?
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
I want to have a svg dashed line drawn on scroll and got stuck on this for 4hrs.
If it's just a straight line, I can easily animate it by setting stroke-dasharray on css animation, but it doesn't work on a dashed line.
Since there's a background image on body, I cannot use a mask trick either.
I just want to have a simple 45 degree diagonal dashed line (about 100px) drawn on scroll.
Any advice?
In the next example I'm using the wheel event but you can use scroll instead. And I'm cheating. I'm drawing a dashed path over the path I want to animate. You'll see the animated path through the gaps. I hope it helps.
var svg = document.querySelector("svg");
var l = track.getTotalLength();
var dasharray = l;
var dashoffset = l;
theUse.style.strokeDasharray = dasharray;
theUse.style.strokeDashoffset = dashoffset;
document.addEventListener("wheel",
function(e) {
e.preventDefault();
if (dashoffset > 0 && e.deltaY > 0 ||
dashoffset < l && e.deltaY < 0) {
dashoffset -= e.deltaY;
}
if(dashoffset < 0)dashoffset = 0;
if(dashoffset > l)dashoffset = l;
theUse.style.strokeDashoffset = dashoffset;
}, false);
svg{border:1px solid}
<svg id="svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 -23 238 120">
<defs>
<path id="track" fill="none" d="M18.265,6.037c0,0,22.354-2.458,32.585,2.709c13.401,6.768,22.928,25.006,33.864,30.677c10.935,5.67,11.901,9.014,21.216,8.608c10.013-0.435,11.08-5.485,14.862-5.485
c9.801,0,25.631,24.662,36.168,24.115c14.971-0.777,9.135-0.936,22.096-0.531c12.959,0.406,29.501,7.144,41.247,4.309"/>
</defs>
<use xlink:href="#track" id="theUse" stroke="black" />
<use xlink:href="#track" stroke-dasharray="10 10" stroke="white" stroke-width="2" />
UPDATE
Someone commented:
what we are supposed to see .. because I see nothing when running the snippet
When moving the wheel of your mouse you should see something like this:
UPDATE 2
I'm updating again as an answer to another comment:
ok I don't have a wheel, but why not considering the scroll as stated in the question
Next comes a demo where I'm using the scroll event:
var l = thePath.getTotalLength();
var dasharray = l;
track.style.strokeDasharray = dasharray;
var dashoffset = l;
track.style.strokeDashoffset = dashoffset;
wrap.addEventListener("scroll", function() {
// - 10 is because I want to offset slightly the dashoffse
dashoffset =
-10 + l - this.scrollTop * l / (this.scrollHeight - this.clientHeight);
track.style.strokeDashoffset = dashoffset;
});
#wrap,svg{border:1px solid}
#wrap{height:200px; overflow:scroll}
use{fill:none}
<div id="wrap">
<svg id="svg"
width="100" viewBox="0 0 78.571 753.021" >
<defs>
<path id="thePath" d="M46.249,7c0,0-37.5,0-37.5,32.812s20.312,56.25,37.5,75
s23.881,51.525,6.25,73.438c-31.43,39.062,21.875,43.882,18.75,70.378s-35.938,63.997-45.312,90.559s17.08,37.5,23.438,81.25
s-23.438,75-18.75,118.75s45.312,75,26.562,103.125s-51.812,83.438-50.125,100"/>
</defs>
<use xlink:href="#thePath" id="track" stroke="black" />
<use xlink:href="#thePath" stroke-dasharray="10 10" stroke="white" stroke-width="2" />
</svg>
</div>
UPDATE num 3
Got another comment:
You should use a mask instead of a white path for hiding the dashed path, so that everything but the dashes remains transparent. Like here: Animate dashed SVG line
Inspired by this answer Animate dashed SVG line I'm using a mask instead of a white path.
var l = thePath.getTotalLength();
var dasharray = l;
mask.style.strokeDasharray = dasharray;
var dashoffset = l;
mask.style.strokeDashoffset = dashoffset;
wrap.addEventListener("scroll", function() {
dashoffset =
l - this.scrollTop * l / (this.scrollHeight - this.clientHeight);
mask.style.strokeDashoffset = dashoffset;
});
#wrap,svg{border:1px solid}
#wrap{height:200px; overflow:scroll}
use{fill:none;}
path{stroke-width:3px;}
#mask{stroke:white}
<div id="wrap">
<svg id="svg"
width="100" viewBox="0 0 78.571 753.021" >
<defs>
<path id="thePath" d="M46.249,7c0,0-37.5,0-37.5,32.812s20.312,56.25,37.5,75
s23.881,51.525,6.25,73.438c-31.43,39.062,21.875,43.882,18.75,70.378s-35.938,63.997-45.312,90.559s17.08,37.5,23.438,81.25
s-23.438,75-18.75,118.75s45.312,75,26.562,103.125s-51.812,83.438-50.125,100"/>
<mask id="mask1">
<use id="mask" xlink:href="#thePath" />
</mask>
</defs>
<use xlink:href="#thePath" stroke-dasharray="10 10" stroke="black" mask="url(#mask1)" />
</svg>
</div>