JSFiddle - React, Tailwind, and code Playground

by Vijay Gujar

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/4.0.0-beta.5/fabric.js"></script>
<button id='btnGroup' onclick="group()" >
Group
</button>
<canvas id="canvas" width="500" height="500"></canvas>

JavaScript

var canvas = new fabric.Canvas('canvas');
var strokeWidth = 8;
var r1 = new fabric.Rect({
	left: 50,
  top: 50,
  width: 70,
  height: 50,
  strokeWidth: strokeWidth,
  stroke: '#ff00ff',
  fill: 'transparent'
})

canvas.add(r1);

var t1 = new fabric.Textbox('Hello', {
    width: 100,
    height: 100,
    top: 100,
    left: 50,
    fontSize: 52,
    textAlign: 'left'
});

canvas.add(t1);

canvas.renderAll();

function group() {
	var activeObject = canvas.getActiveObject();
  
	if (activeObject && activeObject.type === 'activeSelection') {
    var objects = activeObject._objects.concat();
    activeObject._objects = [];
    var options = fabric.Object.prototype.toObject.call(activeObject);

    var canvasGroupObject = new fabric.CustomGroup([]);
    delete options.type;
    canvasGroupObject.set(options);

    objects.forEach(function(canvasObject) {

      canvas.remove(canvasObject);

      canvasObject.group = canvasGroupObject;
      canvasObject.setCoords();
    });
    canvasGroupObject._objects = objects;
    canvasGroupObject.set({'canvas': canvas});
    canvasGroupObject.setCoords();


    canvas.add(canvasGroupObject);
  }
}

fabric.CustomGroup = fabric.util.createClass(fabric.Group, {
  type: 'customGroup',
  
  initialize : function(objects, options) {
      options || ( options = { });
      this.callSuper('initialize', objects, options);
      this.set({subTargetCheck: true});
  },
  _renderControls: function(ctx, styleOverride, childrenOverride) {
    ctx.save();
    ctx.globalAlpha = this.isMoving ? this.borderOpacityWhenMoving : 1;
    this.callSuper('_renderControls', ctx, styleOverride);
    childrenOverride = childrenOverride || { };
    if (typeof childrenOverride.hasControls === 'undefined') {
      childrenOverride.hasControls = false;
    }
    childrenOverride.forActiveSelection = true;
    if (this.subTarget) {
      this.subTarget._renderControls(ctx, childrenOverride);
    }
    ctx.restore();
  },
});

fabric.CustomGroup.fromObject =...