最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - FabricJS prevent canvas.clipTo from clipping canvas.backgroundImage - Stack Overflow

programmeradmin2浏览0评论

I want to set a global clipTo in my Fabric-powered Canvas that will affect all user-added layers. I want a background image and an overlay image, which are unaffected by this clip mask.

Example:

Here's what's happening in this photo:

  1. A canvas overlay image makes the t-shirt look naturally wrinkled. This overlay image is mostly transparent
  2. A background image in the exact shape of the t-shirt was added, which is supposed to make the t-shirt look blue
  3. A canvas.clipTo function was added, which clips the canvas to a rectangular shape
  4. A user-added image (the famous Fabric pug) was added

I want the user-added image (the pug) to be limited to the rectangular area.

I do not want the background image (the blue t-shirt shape) affected by the clip area.

Is there a simple way to accomplish this? I really don't want to have to add a clipTo on every single user layer rather than one tidy global clipTo.

You can play with a JS fiddle showing the problem here.

I want to set a global clipTo in my Fabric-powered Canvas that will affect all user-added layers. I want a background image and an overlay image, which are unaffected by this clip mask.

Example:

Here's what's happening in this photo:

  1. A canvas overlay image makes the t-shirt look naturally wrinkled. This overlay image is mostly transparent
  2. A background image in the exact shape of the t-shirt was added, which is supposed to make the t-shirt look blue
  3. A canvas.clipTo function was added, which clips the canvas to a rectangular shape
  4. A user-added image (the famous Fabric pug) was added

I want the user-added image (the pug) to be limited to the rectangular area.

I do not want the background image (the blue t-shirt shape) affected by the clip area.

Is there a simple way to accomplish this? I really don't want to have to add a clipTo on every single user layer rather than one tidy global clipTo.

You can play with a JS fiddle showing the problem here.

Share Improve this question edited Oct 7, 2015 at 16:02 chadoh asked Oct 7, 2015 at 15:55 chadohchadoh 4,4326 gold badges42 silver badges65 bronze badges 2
  • Have you ever got this working? – Rivka Commented Jan 12, 2016 at 17:52
  • @Rivka not in a way I liked. I got it working by adding a (very complex) clipTo to every single user layer, rather than one simple, global clipTo. – chadoh Commented Jan 12, 2016 at 21:09
Add a comment  | 

4 Answers 4

Reset to default 1

I came here with the same need and ultimately found a solution for what I'm working on. Maybe it helps:

For SVG paths, within the clipTo function you can modify the ctx directly prior to calling render(ctx) and these changes apply outside the clipped path o. Like so:

var clipPath = new fabric.Path("M 10 10 L 100 10 L 100 100 L 10 100", {
  fill: 'rgba(0,0,0,0)',
});

var backgroundColor = "rgba(0,0,0, 0.2)";

var opts = {
  controlsAboveOverlay: true,
  backgroundColor: 'rgb(255,255,255)',
  clipTo: function (ctx) {
    if (typeof backgroundColor !== 'undefined') {
      ctx.fillStyle = backgroundColor;
      ctx.fillRect(0, 0, 300, 150);
    }
    clipPath.render(ctx);
  }
}
var canvas = new fabric.Canvas('c', opts);

canvas.add(new fabric.Rect({
  width: 50,
  height: 50,
  left: 30,
  top: 30,
  fill: 'rgb(255,0,0)'
}));

You can of course add an image instead of a color, or whatever else you want done. The trick I've found is to put it in the clipTo function on the ctx directly.

here's a fiddle

One (sorta hacky) solution: set a CSS background image on your canvas element, as shown in https://jsfiddle.net/qpnvo3cL/

<canvas id="c" width="500" height="500"></canvas>
<style>
  background: url('http://fabricjs.com/assets/jail_cell_bars.png') no-repeat;
</style>
<script>
  var canvas = window._canvas = new fabric.Canvas('c');
  canvas.clipTo = function(ctx) {
      ctx.rect(100,100,100,100);
  }
</script>

Have you tried clipping a fabric Group? You could make the whole shirt one canvas. The center graphics would be one Group which you clip to where you want it. The white t-shirt and the blue overlay would of course not be part of the clipped group.

Here's an example of clipping a group:

var rect = new fabric.Rect({width:100, height: 100, fill: 'red' });
var circle = new fabric.Circle({ radius: 100, fill: 'green' });
var group1 = new fabric.Group([ circle, rect ], { left: 100, top: 100 });
canvas.add(group1);

group1.clipTo = function(ctx) {
    ctx.rect(50,50,200,200);
};

See this jsfiddle I made: https://jsfiddle.net/uvepfag5/4/

I find clip rather slow so I tend to use globalCompositeOperation to do masking.

If you really need to use clip then use it in conjunction with save and restore.

// ctx is canvas context 2d
// pug is the image to be clipped

// draw your background
ctx.save(); // save state
ctx.rect(100,100,100,100); // set the clip area
ctx.clip(); // apply the clip 
ctx.drawImage(pug,x,y); // draw the clipped image
ctx.restore(); // remove the clipping
// draw the other layers.

or you can

// draw background
ctx.globalCompositeOperation = "xor";  // set up the mask
ctx.fillRect(100,100,100,100); // draw the mask, could be an image. 
                               // Alpha will effect the amount of masking,
                               // not available with clip 
ctx.globalCompositeOperation = "destination-over";
ctx.drawImage(pug,x,y); // draw the image that is masked                        
ctx.globalCompositeOperation = "source-over";
// draw the stuff that needs to be over everything.

The advantage of composite operations is you have control over the clipping at a per pixel level, including the amount of clipping via the pixel alpha value

发布评论

评论列表(0)

  1. 暂无评论