0

I'm having some issues with an effect I'm trying to achieve using canvas and the CSS blur filter.

Essentially I need a canvas that is 100% of the height and width of the window, which can be erased to show elements sitting beneath. I am using the blur so the shapes/drawing looks blurred (this is needed).

My issue is that despite oversizing the canvas, there is still a transparent edge around the corners, which shows the elements beneath (i.e. the body with a blue background). I have tried multiple negative margin/overflow hacks, but can't seem to get around it?

I need this canvas to be the full width of the screen, blurred, and not crop in at all, but maybe this is just how CSS filters render, only what is visible?

(function() {
     
     // make canvas larger than window 
     var largeWidth = window.innerWidth * 3;
     var largeHeight = window.innerHeight * 3;
     function createCanvas(parent, width, height) {
      var canvas = {};
      canvas.node = document.createElement('canvas');
      canvas.context = canvas.node.getContext('2d');
      canvas.node.width = largeWidth;
      canvas.node.height = largeHeight;
      parent.appendChild(canvas.node);
      return canvas;
     }

    function init(container, width, height, fillColor) {
     var canvas = createCanvas(container, 3000, 3000);
     var ctx = canvas.context;
     ctx.fillCircle = function(x, y, radius, fillColor) {
      this.fillStyle = fillColor;
      this.beginPath();
      this.moveTo(x, y);
      this.arc(x, y, radius, 0, Math.PI * 2, false);
      this.fill();
     };
     ctx.clearTo = function(fillColor) {
      ctx.fillStyle = fillColor;
      ctx.fillRect(0, 0, width, height);
     };
     ctx.clearTo(fillColor || "#ddd");
     canvas.node.onmousemove = function(e) {
      var x = e.pageX - this.offsetLeft;
      var y = e.pageY - this.offsetTop;
      var radius = 100; // or whatever
      var fillColor = '#ff0000';
      ctx.globalCompositeOperation = 'destination-out';
      ctx.fillCircle(x, y, radius, fillColor);
     };
     canvas.node.onmousedown = function(e) {
      canvas.isDrawing = true;
     };
    }

    var container = document.getElementById('canvas');
    init(container, largeWidth, largeHeight, '#fff');

    })();
/* CSS: */

body {
  background: blue;
}

#canvas {
  z-index: 1;
  top: 0;
  left: 0;
  position: fixed;
  filter: blur(10px);
  -webkit-filter: blur(10px);
}
<div id = "canvas"></div>

Please see my fiddle

Thanks

biscuit_
  • 187
  • 1
  • 3
  • 16

3 Answers3

1

Solution 1 - AKA "Ready Today"

Don't blur your canvas but blur what you put inside it; ex:

// After filling circle
context.shadowColor = color;
context.shadowBlur = 16;
context.stroke();

Here is a fiddle

Solution 2 - AKA "Tomorrow .. maybe"

Webkit is working on such feature. But I'm not sure it will work as you intend with canvas, maybe it will considere the whole canvas as "blur mask" so it will blur underneath event if content inside canvas is erased. Here is the feature :

backdrop-filter: blur(10px);

Here is some doc

ps :

  1. I'm not sure it's necessary to wrap canvas as you did .. juste create one and edit its properties directly !
  2. Ouch ! if you make element size 3 times bigger but don't set offset it will only be able overflow on right and bottom sides
Victor Drouin
  • 597
  • 2
  • 15
0

you should change your css as below

(function() {

  var largeWidth = ( window.innerWidth * 3)+30;
  var largeHeight = (window.innerHeight * 3)+30;

  function createCanvas(parent, width, height) {

    var canvas = {};
    canvas.node = document.createElement('canvas');
    canvas.context = canvas.node.getContext('2d');
    canvas.node.width = largeWidth;
    canvas.node.height = largeHeight;
    parent.appendChild(canvas.node);
    var overlay = document.getElementById("overlay");
    overlay.style.width=(largeWidth -30) +"px";
    overlay.style.height =( largeHeight-30)+"px";
    return canvas;
  }

  function init(container, width, height, fillColor) {
    var canvas = createCanvas(container, 3000, 3000);
    var ctx = canvas.context;
    ctx.fillCircle = function(x, y, radius, fillColor) {
      this.fillStyle = fillColor;
      this.beginPath();
      this.moveTo(x, y);
      this.arc(x, y, radius, 0, Math.PI * 2, false);
      this.fill();
    };
    ctx.clearTo = function(fillColor) {
      ctx.fillStyle = fillColor;
      ctx.fillRect(0, 0, width, height);
    };
    ctx.clearTo(fillColor || "#ddd");
    canvas.node.onmousemove = function(e) {
      var x = e.pageX - this.offsetLeft;
      var y = e.pageY - this.offsetTop;
      var radius = 100; // or whatever
      var fillColor = '#ff0000';
      ctx.globalCompositeOperation = 'destination-out';
      ctx.fillCircle(x, y, radius, fillColor);
    };
    canvas.node.onmousedown = function(e) {
      canvas.isDrawing = true;
    };
  }

  var container = document.getElementById('canvas');
  init(container, largeWidth, largeHeight, '#fff');

})();
body {
  background: blue;
}
#canvas {
  margin: -15px;
  filter: blur(10px);
  -webkit-filter: blur(10px);
  position: relative;
}
#overlay {
  overflow:hidden;
  position: fixed;
  top: 0px;
  left: 0px;
  z-index: 1;
  filter: unset;
  -webkit-filter: unset;
  }
<div id="overlay">
 <div id="canvas">
 </div>
</div>
Mr. A
  • 1,221
  • 18
  • 28
0

You can remove the filter from the canvas and use a gradient brush to achieve the same.

(function() {
     
     // make canvas larger than window 
     var largeWidth = window.innerWidth * 3;
     var largeHeight = window.innerHeight * 3;
     function createCanvas(parent, width, height) {
      var canvas = {};
      canvas.node = document.createElement('canvas');
      canvas.context = canvas.node.getContext('2d');
      canvas.node.width = largeWidth;
      canvas.node.height = largeHeight;
      parent.appendChild(canvas.node);
      return canvas;
     }

    function init(container, width, height, fillColor) {
     var canvas = createCanvas(container, 3000, 3000);
     var ctx = canvas.context;
     ctx.fillCircle = function(x, y, radius, fillColor) {
      this.fillStyle = fillColor;
      this.beginPath();
      this.moveTo(x, y);
      this.arc(x, y, radius, 0, Math.PI * 2, false);
      this.fill();
     };
     ctx.clearTo = function(fillColor) {
      ctx.fillStyle = fillColor;
      ctx.fillRect(0, 0, width, height);
     };
     ctx.clearTo(fillColor || "#ddd");
     canvas.node.onmousemove = function(e) {
        var x = e.pageX - this.offsetLeft;
        var y = e.pageY - this.offsetTop;
        var radius = 100; // or whatever
        var fillColor = '#ff0000';
        var radgrad = ctx.createRadialGradient(x,y,0,x,y,radius);

         radgrad.addColorStop(0, 'rgba(255,0,0,1)');
         radgrad.addColorStop(0.6, 'rgba(228,0,0,.6)');
         radgrad.addColorStop(1, 'rgba(228,0,0,0)');

        ctx.globalCompositeOperation = 'destination-out';
        ctx.fillCircle(x, y, radius, radgrad);
    };
     canvas.node.onmousedown = function(e) {
      canvas.isDrawing = true;
     };
    }

    var container = document.getElementById('canvas');
    init(container, largeWidth, largeHeight, '#fff');

    })();
/* CSS: */

body {
  background: blue;
}

#canvas {
  z-index: 1;
  top: 0;
  left: 0;
  position: fixed;
  
}
<div id = "canvas"></div>
Community
  • 1
  • 1
Mat J
  • 5,422
  • 6
  • 40
  • 56