Wave Filter in SVG

While attempting to create a fisheye-esque filter in my SVG, I came across this interesting codepen example: http://codepen.io/johanberonius/pen/RopjYW

The effect works well, but I would like it to be a bit more pronounced. Unfortunately, I am unable to modify the displacement map since it is generated in JavaScript.

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);
});

The formula used here is quite complex for me to tweak on my own. So, I'm curious if there is a simpler way to generate such maps or if anyone could assist me with a modified formula.

Answer №1

Creating a displacement map as an SVG filter itself is possible, giving the ability to combine drawing and application in one file. However, due to browsers not supporting enable-background, these must be separated into two files.

The first file contains 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>

The second file applies the displacement map 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>

For further customization, consider experimenting with the parameters such as blur radius, erode radius, displacement offsets, and color matrix values.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Guide on navigating an array of objects using the provided keys as a starting point in Javascript/Typescript

Assuming I have an array of objects structured like this: const events: Array<{year: number, month: number, date: number}> = [ {year: 2020, month: 10, date: 13}, {year: 2021: month: 3, date: 12}, {year: 2021: month: 9, date: 6}, {year: 2021: mont ...

Expanding the height of Bootstrap 4 cards

I'm having an issue with Bootstrap 4's card columns where the height of the shorter card ends up stretching to match the one beside it. This only occurs when I add the 'row' class to the parent div. If I remove the 'row' class ...

Unable to pass data to the onChange event for the material-ui datePicker components

Need help with a form that includes a material-ui DatePicker. Here is an example: <DatePicker name="startDate" autoOk={true} floatingLabelText="startDate" onChange={(x, event) => {console.log(arguments);}} /> When I change the date, the console ...

Tips to store Google fonts in the assets directory

I've included this link in my styles.scss @import url('https://fonts.googleapis.com/css2?family=Open+Sans:wght@400;600;700&display=swap'); While it works locally, the API fails on production or is blocked. How can I host it within my p ...

Apply a different color to every other header using the nth-child selector

I'm attempting to create alternating color headers without defining multiple header styles. I've opted to use the nth-child selector for this purpose, but I'm having trouble achieving the desired colors. JSFiddle: http://jsfiddle.net/CRh6L/ ...

Guide on how to align the bootstrap popover's arrow tip with a text field using CSS and jQuery

I have tried multiple solutions from various questions on Stack Overflow, but I am still struggling to position the arrow tip of the bootstrap popover correctly. html: <input type = "text" id="account_create"/> js: $('.popov ...

Forwarding from a user interface element in Next.JS

I am currently working on a project utilizing Next.js 13, and I have encountered a situation where I need to invoke a client-side component from a server-side page. The specific component in question is the DeleteAddressAlertDialog which interacts with my ...

Developing a dynamic web application using the Django framework along with the Vue.js library and Highcharts for

I am currently working on a data visualization web app using Django, Highcharts, and JQuery. I have recently transitioned from JQuery to Vue JS and I am struggling with fetching JSON data from a specific URL. Below is the code snippet: Template <!doc ...

Methods for breaking down a number into individual elements within an array

Suppose there is a number given: let num = 969 The goal is to separate this number into an array of digits. The first two techniques fail, but the third one succeeds. What makes the third method different from the first two? num + ''.split(&ap ...

Can Vue recognize array changes using the Spread syntax?

According to Vue documentation: Vue is unable to detect certain changes made to an array, such as: Directly setting an item using the index, for example vm.items[indexOfItem] = newValue Modifying the length of the array, like vm.items.length = newLength ...

How can Ext JS 4 handle the transmission of multiple metaData to support multiple dynamic grids by utilizing a single JSON file?

Looking to create multiple grids on a single panel using an accordion layout? I'll be dynamically generating all the grids based on metaData in JSON and handling metachange listener events on my store to reconfigure the grid. But here's the quest ...

Experimenting with a sample post on a minimalist Node.js application using Mocha and Superagent

I trust you are having a splendid day. Currently, I am focusing on enhancing my TDD skills in Node.js. To practice, I have developed a minimalistic application that handles basic GET and POST requests. The app simply displays a straightforward form to the ...

The Reason Behind Angular Error when Using CSS Custom Tags

I have the following SCSS code: main{ width: 100%; height: 840px; /*background: red;*/ margin: 10px auto; position: relative; padding: 5px 0; } section{ width: 98%; height: 600px; margin: auto; display: flex; ...

Exploring the retrieval of JavaScript array elements from a ListModel within QML

Currently, I have some JavaScript data that consists of a list of objects containing other objects and arrays, which I want to append to a ListModel. This is what the structure looks like (assuming that the data is generated elsewhere and its structure sh ...

Google App Engine does not properly interpret PHP code when making AJAX requests

I am currently facing an issue with using AJAX request on Google App Engine. In my local development environment, everything works fine and the request is correctly interpreted. However, when I deploy the code to production, the AJAX request renders the co ...

challenges with positioning div elements using relative CSS styling

This is a section of my code: CSS : .body .left, .right { position:relative; z-index:6; display:inline-block; } .body .left { top:0; left:0; width:100px; height:300px; margin-right:10px; borde ...

Looking to empty a textbox, give it focus, and avoid triggering an ASP.NET postback all with a single click of a

I am working on an ASP.NET project and I have a simple HTML button. When this button is clicked, my goal is to clear textbox1, set the focus on textbox1, and prevent any postback from occurring. However, I am running into an issue where preventing postba ...

The cause of Interface A improperly extending Interface B errors in Typescript

Why does extending an interface by adding more properties make it non-assignable to a function accepting the base interface type? Shouldn't the overriding interface always have the properties that the function expects from the Base interface type? Th ...

"Update data on a webpage using Javascript without the need to refresh the

I encountered a problem with my code for posting messages in the "chatbox". When I include return false; at the end of the function, the data is not submitted. However, if I remove it, the data submits successfully. JavaScript Code function dopost() { ...

ACL - Utilize ACL in conjunction with the passport authentication system

I am experimenting with node_acl in combination with passport-local. Unfortunately, I am facing an issue when trying to secure the route for the admin-user '/admin', as it keeps redirecting me to the /login page. Below is a simplified version of ...