透明对象与阴影

时间:2016-07-25 11:49:10

标签: javascript html5-canvas fabricjs

无论如何在FabricJS中为透明对象添加阴影?我已经使用了set fill tr​​ansparent和之后的sethadow。但通常无法看到阴影,因为对象是透明的。

2 个答案:

答案 0 :(得分:1)

在绘制带有阴影的对象时,可以使用clip path完成此操作。为此,您可以使用FabricJS子类化生成阴影的对象类型,并重写_render函数以设置一个剪切路径,该路径包括阴影掉落的区域,但不包括对象本身。理想情况下,这会重用实际绘制对象的代码。

fabric.BoxShadow = fabric.util.createClass(fabric.Rect, {

  shadowColor: undefined,

  shadowBlur: 0,
  shadowOffsetX: 0,
  shadowOffsetY: 0,

  initialize(options) {
    this.callSuper('initialize', options);

    // Note: the way I have implemented this, the shadow settings cannot be changed after the object has been created.
    this._shadow = new fabric.Shadow({
      color: this.shadowColor,
      blur: this.shadowBlur,
      offsetX: this.shadowOffsetX,
      offsetY: this.shadowOffsetY
    });
  },

  _render: function(ctx) {
    ctx.save();

    // set clip path
    let [offsetX, offsetY, blur] = [this.shadowOffsetX,
      this.shadowOffsetY,
      this.shadowBlur
    ];

    let [top, left] = [this.width / -2, this.height / -2];

    let region = new Path2D();
    // The outer rectangle for our clipping path completely encompases the object and its shadow
    let bounds = {
      t: Math.min(top, top + offsetY - blur),
      l: Math.min(left, left + offsetX - blur),
      b: Math.max(top + this.height, top + this.height + offsetY + blur),
      r: Math.max(left + this.width, left + this.width + offsetX + blur),
    };

    region.rect(bounds.l, bounds.t, bounds.r - bounds.l, bounds.b - bounds.t);

    // now we subtract the actual object from our clipping path
    // Note: we have to add  beginPath function because the base class render code is going to treat this likc a CanvasRenderingContext2D instead of a Path2D
    region.beginPath = function() { };
    this.callSuper('_render', region);
    
    ctx.clip(region, "evenodd");

    // Fabric draws shadows, oddly enough, around the entire area rendered within this function. I haven't figured out the correct function to override to get our clip path to work with the normal fabric rendering pipeline
    this.shadow = this._shadow;
    // leverage the FabricJS shadow sizing logic
    this._setShadow(ctx);
    
    this.callSuper('_render', ctx);
    this.shadow = undefined;

    ctx.restore();
  },
  
  _renderPaintInOrder: function(ctx) {
    if (ctx instanceof CanvasRenderingContext2D) {
    	this.callSuper('_renderPaintInOrder', ctx);
    }
  }
});

(function() {
  let canvas = new fabric.Canvas('c');
  fabric.Object.prototype.transparentCorners = false;

  canvas.add(new fabric.Rect({
    top: 40,
    left: 40,
    width: 100,
    height: 100,
    fill: 'lightblue'
  }));

  canvas.add(
    new fabric.BoxShadow({
      rx: 10,
      top: 10,
      left: 10,
      width: 100,
      height: 100,
      shadowColor: 'black',
      shadowBlur: 4,
      shadowOffsetX: 3,
      shadowOffsetY: 3
    })
  );

  canvas.setWidth(document.body.clientWidth);
  canvas.setHeight(document.body.clientHeight);
})();
html {
  height: 100%;
}

body {
  height: 100%;
}
<html>

  <head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.7.0/fabric.js"></script>
  </head>

  <body>
    <canvas id="c"></canvas>
  </body>

</html>

答案 1 :(得分:0)

我认为FabricJS API没有阴影 - 无形状选项。

但是您可以使用本机html5画布轻松创建阴影,然后使用该本机画布作为Fabric.Image对象的图像源。

使用原生html5画布,你可以创建一个没有它的源形状的阴影:

  • 绘制阴影形状,
  • 使用合成来&#34;擦除&#34;形状 - 只留下它的影子

enter image description here

仅在本机html5画布上绘制阴影的示例代码:

&#13;
&#13;
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");

var shadowBlur=8;
var x=shadowBlur;
var y=shadowBlur;
var width=100;
var height=65;
canvas.width=width+shadowBlur*2;
canvas.height=height+shadowBlur*2;

// draw the shadowed shape
ctx.shadowColor='black';
ctx.shadowBlur=8;
ctx.fillRect(x-ctx.shadowOffsetX,y,width,height);
// always clean up! -- undo shadowing
ctx.shadowColor='rgba(0,0,0,0';

// use compositing to remove the shape
// (leaving just the shadow);
ctx.globalCompositeOperation='destination-out';
ctx.fillRect(x,y,width,height);
// always clean up! -- set compositing to default
ctx.globalCompositeOperation='source-over';
&#13;
body{ background-color:white; }
#canvas{border:1px solid red; }
&#13;
<canvas id="canvas" width=512 height=512></canvas>
&#13;
&#13;
&#13;

使用原生html5画布作为图像源创建Fabric.Image的示例:

// where "canvas" is a reference to an html5 canvas element
var myFabricImage=new fabric.Image(canvas, { left:0, top:0 });