Open 9am opened 11 months ago
Inspired by the famous album cover of Joy Division made by Peter Saville, I wanted to build an SVG filter that turns the source(image, text) into a bunch of 'contour' lines. That's where feDisplacementMap
kicks in. It's one of my favorite filter primitives. In this article, I'll show you things we can do with it.
Album cover by Peter Saville
𐄡
𐄡
𐄡
𐄡
## Super power of `feDisplacementMap ` ␥
Most of the filter elements in SVG work like `Pixel shaders`, just do simple pixel in, pixel out. But `feDisplacementMap` offers the ability to re-arrange the position of pixels.
> The
> ![displacementmap](https://github.com/9am/9am.github.io/assets/1435457/6033ac14-ae20-44fb-8699-1540a99d4fa7)
How the position displaces depends on the color channel of the `'Map'` input, yeah, we can control `source`'s pixel position by the color of the `Map`. Consider we have a green crossline as `source`, if we want to move the area in the center, we'll use the alpha channel, a `map` with `alpha != 1` rectangle placed in the center will do the job. The distance offset of the pixel could be controlled by `scale` and the value offset from '0.5' of the color channel. The direction is controlled by `xChannelSelector` or `yChannelSelector`.
>
> [![Edit how-fedisplacementmap-works](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/how-fedisplacementmap-works-tmcqkj?fontsize=14&hidenavigation=1&theme=dark)
With that, we'll build the contour filter to show the alpha value of the 'source', this is what we'll build.
> ![final contour](https://github.com/9am/9am.github.io/assets/1435457/51250621-b1e4-48c7-b965-9ab33b8a48dd)
## Contour filter ␥
### 1. Create the stripes ␥
With the help of `
<div style="filter: url(#contour)"></div>
<svg>
<defs>
<polygon
id="line"
points="0,0 1000,0"
fill="none"
stroke="black"
stroke-width="4px"
/>
<filter
id="contour"
color-interpolation-filters="sRGB"
x="0"
y="0"
width="100%"
height="100%"
>
<feImage href="#line" width="1%" height="2%" />
<feTile result="TILE" />
</filter>
</defs>
</svg>
### 2. Prepare the map ␥
We have our `source`, which is the stripes. Now let's prepare the `map`. Add a `rgba(127, 127, 127, 0.5)` background to make an identity base map. Put some text into the `
<svg>
...
<feMerge>
<feMergeNode in="SourceGraphic" />
<feMergeNode in="TILE" />
</feMerge>
...
</svg>
<div><p>Twist The Reality !</p></div>
### 3. Bend the lines ␥
Now using what we know about `
<svg>
...
<feDisplacementMap
in2="SourceGraphic"
in="TILE"
scale="10"
xChannelSelector="R"
yChannelSelector="A"
result="OUTPUT"
/>
...
</svg>
### 4. Smooth the contour ␥
Apply a `
> Throw more vertical stripes, and a `linear-gradient` to show alpha change.
>
> ![demo-1](https://github.com/9am/9am.github.io/assets/1435457/404d766e-3f51-4d38-ba61-3a98f71d6baf)
>
> [Codepen](https://codepen.io/9am/pen/dywaRZq)
<svg>
...
<filter
id="contour"
color-interpolation-filters="sRGB"
x="0"
y="0"
width="100%"
height="100%"
>
<feGaussianBlur
stdDeviation=".8"
result="BLUR"
/>
...
</svg>
## Global Magnifier filter ␥
After the contour, I thought `
## Closing thoughts
There is so much fun playing with SVG filters, they're like built-in shaders that offer limited parameters, but with a little bit of innovation, they can be powerful and maybe it's the simplest way to tweak pixels on a web page. I'm considering writing a series to dig more for each of them. Thanks for reading, see you next time.
---
> ## @9am 🕘
> * Read more [articles](https://9am.github.io) at [9am.github.io](https://9am.github.io)
> * Find other [things](https://www.npmjs.com/search?q=%409am) I built on [GitHub](https://github.com/9am) and [NPM](https://www.npmjs.com/~9am)
> * Contact me via [email](mailto:tech.9am@gmail.com)
> * [![Creative Commons License](https://i.creativecommons.org/l/by-nc-nd/4.0/80x15.png)](http://creativecommons.org/licenses/by-nc-nd/4.0/)