How to create custom brush paint with fabric.js?

2019-04-17 12:26发布

I have been trying to create a custom brush paint with an image file using fabric JS . I have tried using the fabric.PatternBrush but this is not the exact thing that I was looking for because this creates a background pattern kind of paint and what I am trying to do is repeat the image wherever the mouse is dragged.

Can anyone please direct me towards the right way? It will be fine for me to switch to any other drawing library that does what I am looking for.

1条回答
叛逆
2楼-- · 2019-04-17 12:46

I found a solution to this problem. We can create a custom brush using fabric.BaseBrush as follows:

  fabric.SprayBrush = fabric.util.createClass(fabric.BaseBrush, {

    opacity: .2,
    width: 30,

    _baseWidth: 5,
    _drips: [],
    _dripThreshold: 15,
    _inkAmount: 0,
    _interval: 20,
    _lastPoint: null,
    _point: null,
    _strokeId: 0,
    brush: null,
    brushCol : '/static/img/creation_room/textures/texture2.png',

    initialize: function(canvas, opt) {
      var context = this;
      opt = opt || {};

      this.canvas = canvas;
      this.width = opt.width || canvas.freeDrawingBrush.width;
      this.opacity = opt.opacity || canvas.contextTop.globalAlpha;
      this.color = opt.color || canvas.freeDrawingBrush.color;

      this.canvas.contextTop.lineJoin = "round";
      this.canvas.contextTop.lineCap = "round";

      this._reset();

      fabric.Image.fromURL(this.brushCol, function(brush) {
        console.log(brush);
        context.brush = brush;
        context.brush.filters = [];
        context.changeColor(context.color || this.color);
      }, { crossOrigin: "anonymous" });
    },

    changeColor: function(color) {
      this.color = color;
      this.brush.filters[0] = new fabric.Image.filters.Tint({ color: color });
      this.brush.applyFilters(this.canvas.renderAll.bind(this.canvas));
    },

    changeOpacity: function(value) {
      this.opacity = value;
      this.canvas.contextTop.globalAlpha = value;
    },

    onMouseDown: function(pointer) {
      this._point = new fabric.Point(pointer.x, pointer.y);
      this._lastPoint = this._point;

      this.size = this.width + this._baseWidth;
      this._strokeId = +new Date();
      this._inkAmount = 0;

      this.changeColor(this.color);
      this._render();
    },

    onMouseMove: function(pointer) {
      this._lastPoint = this._point;
      this._point = new fabric.Point(pointer.x, pointer.y);
    },

    onMouseUp: function(pointer) {
    },

    _render: function() {
      var context = this;

      setTimeout(draw, this._interval);

      function draw() {
        var point, distance, angle, amount, x, y;

        point = new fabric.Point(context._point.x || 0, context._point.y || 0);
        distance = point.distanceFrom(context._lastPoint);
        angle = point.angleBetween(context._lastPoint);
        amount = (100 / context.size) / (Math.pow(distance, 2) + 1);

        context._inkAmount += amount;
        context._inkAmount = Math.max(context._inkAmount - distance / 10, 0);
        if (context._inkAmount > context._dripThreshold) {
          context._drips.push(new fabric.Drip(context.canvas.contextTop, point, context._inkAmount / 2, context.color, context._strokeId));
          context._inkAmount = 0;
        }

        x = context._lastPoint.x + Math.sin(angle) - context.size / 2;
        y = context._lastPoint.y + Math.cos(angle) - context.size / 2;
        context.canvas.contextTop.drawImage(context.brush._element, x, y, context.size, context.size);

        if (context.canvas._isCurrentlyDrawing) {
          setTimeout(draw, context._interval);
        } else {
          context._reset();
        }
      }
    },

    _reset: function() {
      this._drips.length = 0;
      this._point = null;
      this._lastPoint = null;
    }
  });

Now, we just need to use this brush in the canvas.

var canvas = new fabric.Canvas('canvas');
canvas.freeDrawingBrush = new fabric.SprayBrush(canvas, { width: 70,opacity: 0.6, color: "transparent" });
查看更多
登录 后发表回答