card('https://i.sstatic.net/EK1my.png?s=128')
card('https://i.sstatic.net/EK1my.png?s=128')
card('https://i.sstatic.net/EK1my.png?s=128')
function card(url) {
let s = 500; // size
let step = 100; // x-axis step
let range = [-50, 50]; // y-axis range
// add new svg to document.body with origin at 0
let svg = d3.select('body')
.append('svg')
.attr('viewBox', `0 0 ${s} ${s}`);
// interpolation algorithm for points used to form masking shape
let line = d3.line()
.curve(d3.curveCardinalClosed);
// random values generator function
let rnd = d3.randomUniform.apply(0, range);
// image goes first
svg.append("svg:image")
.attr('mask', 'url(#mask)')
.attr('width', s)
.attr('height', s)
.attr("xlink:href", url)
// here i place points with fixed `step` by `x` axis
// and random value in `range` by `y` axis
// which forms the "original path"
let pts = d3.range(-1, s/step+2).map(i => [i*step, rnd()]);
// shift points down from "original path",
// amount of shift depends from point index
let pts1 = pts.map((p, i) => [
p[0], p[1] + s*0.3 - i*s*0.08
]);
// reverse order of original and shift points down on
// bigger values, depending from point index
let pts2 = pts.reverse().map((p, i) => [
p[0], p[1] + s*0.8 - i*s*0.03
]);
// forming single interpolated path for all
// points from prev steps concatenated in single array
let d = line(pts2.concat(pts1));
// append rect sized as viewport with hole formed by interpolated path
// with random color from hsl palette and opacity 0.9
svg.append('path')
.attr('opacity', 0.9)
.attr('fill', `hsl(${Math.random()*255}, 55%, 55%)`)
.attr('d', `M0,0 v${s} h${s} v${-s} z ${d}`)
}
svg {
height: 150px;
margin: 10px;
box-shadow: 0 2px 10px 2px lightgray;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>