JSFiddle - React, Tailwind, and code Playground

HTML

<input type="range" id="range1" min="0" max="100" step="1">
<input type="range" id="range2" min="0" max="200" step="1">
<input type="range" id="range3" min="0" max="200" step="1">
<br>
<canvas width="200" height="200" id="cv"></canvas>
<canvas width="200" height="200" id="cv2"></canvas>

JavaScript

$(function() {
  var M = 200;
  var N = 200;
  var cv = $("#cv").get(0);
  var cv2 = $("#cv2").get(0);
  var ctx = cv.getContext("2d");
  var ctx2 = cv2.getContext("2d");

  var Z = 25;
  var f = function(x) {
    return -x*Math.exp(-x/Z) + x;
  };
  var Q = 2;
  var X = M/2;
  var Y = N/2;
  var img = new Image;
  var draw = function() {
      ctx.drawImage(img, 0, 0);
      var d = ctx.getImageData(0, 0, M, N);
      var d2_ = ctx2.getImageData(0, 0, M, N);
      var data = d.data;
      var data2 = d2_.data;
      var set = function(n, o) {
        data2[n] = data[o];
        data2[n + 1] = data[o + 1];
        data2[n + 2] = data[o + 2];
        data2[n + 3] = 255;
      };
      for(var i = 0; i < M * N * 4; i += 4) {
        var x = (i / 4) % M;
        var y = Math.floor((i / 4) / M);
        x -= X;
        y -= Y;
        var r = Math.sqrt(x*x + y*y);
        r = f(r);
        var t = Math.atan2(y, x);
        var nx = r * Math.cos(t);
        var ny = r * Math.sin(t);
        nx = ~~(nx + X);
        ny = ~~(ny + Y);
        set(i,   ny * N * 4 + nx * 4);
      }
      ctx2.putImageData(d2_, 0, 0);
  };
  img.onload = draw;
  $("#range1").on("change", function() {
    Z = +$(this).val();
  });
  $("#range2").on("change", function() {
    X = +$(this).val();
  });
  $("#range3").on("change", function() {
    Y = +$(this).val();
  });
  $("input").on("change", draw);
  
  img.src = 'data:image/jpeg;base64,' +
        '/9j/4AAQSkZJRgABAQAAAQABAAD//gA7Q1JFQVRPUjogZ2QtanBlZyB2MS4wICh1c2luZyBJSkcgSlBF' +
        'RyB2NjIpLCBxdWFsaXR5ID0gNzAK/9sAQwAKBwcIBwYKCAgICwoKCw4YEA4NDQ4dFRYRGCMfJSQiHyIh' +
        'Jis3LyYpNCkhIjBBMTQ5Oz4+PiUuRElDPEg3PT47/9sAQwEKCwsODQ4cEBAcOygiKDs7Ozs7Ozs7Ozs7' +
        'Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7/8AAEQgAyADIAwEiAAIRAQMRAf/E' +
        'AB8AAAEFAQEBAQEBAAAAAAAAAAABAgMEBQYHCAkKC//EALUQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUS' +
        'ITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RV'...