Is there a way to achieve a perfect seamless waving effect for the whole of a svg. I tried approaching the problem by animating the baseFrequency
of feTurbulence
filter but it is not giving me what I need.
const lower = 0;
const upper = 0.008;
const step = 0.0001;
const time = 5000;
function animateBaseFrequency() {
let direction = 1; // 1 for incrementing, -1 for decrementing
let x = lower;
d3.select('#fltOne')
.transition()
.duration(time)
.ease(d3.easeLinear)
.tween('x', function() {
return function(t) {
x = x + step * direction;
if (x >= upper || x <= lower) {
direction *= -1; // Reverse direction at upper and lower bounds
}
d3.select(this).attr('baseFrequency', x);
};
}).on('end', animateBaseFrequency);
}
animateBaseFrequency();
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<script type="text/javascript" src="https://d3js.org/d3.v7.min.js"></script>
<body>
<link rel="stylesheet" href="style.css">
<div id="container" class="svg-container">
<svg viewBox="0 0 1280 720" xmlns="http://www.w3.org/2000/svg">
<defs id="pattern">
<pattern id="af" width="100%" height="100%" patternContentUnits="objectBoundingBox">
<image xlink:href="https://raw.githubusercontent.com/d3/d3-logo/master/d3.svg"
preserveAspectRatio="xMidYMid meet" width="1" height="1"></image>
</pattern>
<pattern patternContentUnits="userSpaceOnUse" id="main">
<rect class="patRect" width="400" height="300" fill="url(#af)"></rect>
</pattern>
<filter id="filt">
<feTurbulence result="TURBULENCE" numOctaves="1" seed="1" baseFrequency="0" stitchTiles="noStitch"
id="fltOne"></feTurbulence>
<feDisplacementMap in="SourceGraphic" in2="TURBULENCE" scale="30" result="dist" id="fltTwo">
</feDisplacementMap>
</filter>
</defs>
<rect class="rectOne" x="100" y="100" width="400" height="300" fill="url(#af)"
style="filter: url("#filt");"></rect>
</svg>
</div>
<!--d3 script-->
<script src="prod.js" defer></script>
</body>
</html>
How about this:
stitchTiles="stitch"
on the turbulence so that a seamlessly repeatable tile is produced<feTile>
x
position of that pattern repeatedly for the width of the turbulence tileNote that the whole filter must have sufficient width to contain the complete repeated tile before the offset is applied, otherwise <feTile>
will be cut of at the border of the filter region.
In the picture, the green dashed line is the extent of the image the filter is applied to. The blue line is the filter effect region. Every filter effect is clipped to this rectangle. Its size depends on the values of the attributes filterUnits, x, y, width, height
. In the line below, default values are shown in grey.
The size of each filter primitive, the filter primitive subregion is given with its own x, y, width, height
values. But the values are not interpreted in multiples of the image size, like the filter effect region, but in the coordinate system of the image, as prescribed by the attribute filterPrimitiveUnits="userSpaceOnUse"
.
The tiled pattern fills the filter effects region. Would that be smaller, it would be cut of at its border, regardless what the size of the feTile primitive says.
The last line of pictures shows stages of the animation. Note how the tiled pattern is cut of at the left side.
<svg viewBox="0 0 1280 720" xmlns="http://www.w3.org/2000/svg">
<defs id="pattern">
<filter id="filt" width="2">
<feTurbulence numOctaves="1" seed="1" baseFrequency="0.008"
stitchTiles="stitch"
id="fltOne" width="400" height="400">
</feTurbulence>
<feTile width="800" height="400">
</feTile>
<feOffset result="TURBULENCE" dx="0">
<animate attributeName="dx" from="-400" to="0"
begin="0s" dur="2s" repeatCount="indefinite" />
</feOffset>
<feDisplacementMap in="SourceGraphic" in2="TURBULENCE" scale="30" result="dist" id="fltTwo">
</feDisplacementMap>
</filter>
</defs>
<image xlink:href="https://raw.githubusercontent.com/d3/d3-logo/master/d3.svg" x="100" y="100" width="400" height="300" style="filter: url(#filt);" />
</svg>