Add Delete button on element in Canvas Fabric JS

target.oCoords.mt is middle-top corner.

Use the top-right corner instead: e.target.oCoords.tr

    var canvas = new fabric.Canvas('canvas');
var HideControls = {
            'tl':true,
            'tr':false,
            'bl':true,
            'br':true,
            'ml':true,
            'mt':true,
            'mr':true,
            'mb':true,
            'mtr':true
        };
fabric.Image.fromURL('http://serio.piiym.net/CVBla/txtboard/thumb/1260285874089s.jpg', function (img) {
    img.top = 60;
    img.left = 30;
    img.setControlsVisibility(HideControls);
    canvas.add(img);
});

canvas.renderAll();

function addDeleteBtn(x, y){
    $(".deleteBtn").remove(); 
    var btnLeft = x-10;
    var btnTop = y-10;
    var deleteBtn = '<img src="https://www.funagain.com/images/old/common/delete-icon.png" class="deleteBtn" style="position:absolute;top:'+btnTop+'px;left:'+btnLeft+'px;cursor:pointer;width:20px;height:20px;"/>';
    $(".canvas-container").append(deleteBtn);
}

canvas.on('object:selected',function(e){
        addDeleteBtn(e.target.oCoords.tr.x, e.target.oCoords.tr.y);
});

canvas.on('mouse:down',function(e){
    if(!canvas.getActiveObject())
    {
        $(".deleteBtn").remove(); 
    }
});

canvas.on('object:modified',function(e){
    addDeleteBtn(e.target.oCoords.tr.x, e.target.oCoords.tr.y);
});

canvas.on('object:scaling',function(e){
    $(".deleteBtn").remove(); 
});
canvas.on('object:moving',function(e){
    $(".deleteBtn").remove(); 
});
canvas.on('object:rotating',function(e){
    $(".deleteBtn").remove(); 
});
$(document).on('click',".deleteBtn",function(){
    if(canvas.getActiveObject())
    {
        canvas.remove(canvas.getActiveObject());
        $(".deleteBtn").remove();
    }
});

Hello i would suggest a different approach to this functionality that it is more stable as it does not add elements on the DOM , we can use it on as many objects as we like , we dont need to hide and show the custom corner buttons, and the corner buttons are visible each time the object is active(native fabricjs functions).

  1. I am going to override the object's prototype _drawControl function , for to add my custom corner images.
  2. And override the canvas prototype _setCornerCursor , for to change realtime the mouse cursor ,according to which corner is over.
  3. I have made a live fiddle here : https://jsfiddle.net/tornado1979/j987gb6f/

A. First of all i need to preload the custom corner images, so whenever we click on an object there would not be any delay(i used random images just for the show).

var ctrlImages = new Array()

  function preload() {
    for (i = 0; i < preload.arguments.length; i++) {
      ctrlImages[i] = new Image();
      ctrlImages[i].src = preload.arguments[i];
    }
  }

  preload(
      "https://cdn1.iconfinder.com/data/icons/ui-color/512/Untitled-12-128.png",
      "https://cdn2.iconfinder.com/data/icons/social-messaging-productivity-1/128/sync-16.png",
      "https://cdn2.iconfinder.com/data/icons/social-messaging-productivity-1/128/write-compose-16.png",

B. I override the _drawcontrol (i show just the snippet that change the corners):

switch (control)
            {
            case 'tl':
              SelectedIconImage.src = ctrlImages[1].src;//our custom img
              break;
            case 'tr':
              if (flipiX && !flipiY) { n='2'; }
              if (!flipiX && flipiY) { n='3'; }
              if (flipiX && flipiY) { n='4'; }
              SelectedIconImage.src = ctrlImages[0].src;//our custom img
              break;
            case 'mt':

              break;
            case 'bl':
              if (flipiY) { n='2'; }
             SelectedIconImage.src = ctrlImages[3].src;//our custom img
              break;
            case 'br':
              if (flipiX || flipiY) { n='2'; }
              if (flipiX && flipiY) { n=''; }
              SelectedIconImage.src = ctrlImages[2].src;//our custom img
              break;
            case 'mb':

              break;
            case 'ml':

              break;
            case 'mr':

              break;
            default:
              ctx[methodName](left, top, sizeX, sizeY);
              break;
            }

C. Override _setCornerCursor function, for to change the cursor when mouse is over object's corner. Inside the function i use the setCursor() function which actually takes a string as a parameter, so we can take a look here for cursors: https://www.w3.org/TR/css3-ui/#cursor

fabric.Canvas.prototype._setCornerCursor =  function(corner, target) {
      //for top left corner
       if(corner == "tl"){
          this.setCursor(this.rotationCursor); return false;
          //for top right corner
      }else if(corner == "tr"){
          this.setCursor('pointer'); return false;
          //for bottom left corner
      }else if(corner == "bl"){
          this.setCursor('help'); return false;      
          //for bottom right corner
      }else if(corner == "br"){
          this.setCursor('copy'); return false;      
      }
    };

D. And finaly on mouse:down i check the corner and add functionality canvas.on('mouse:down',function(e){..}

custom corner images and cursors

Hope helps, good luck.


your reasoning is correct. Unfortunately, I have in your example "TypeError: t is undefined --> fabric.min.js:1:14099"

I have your example a little modified. I overriede four Methodes:

  • _drawControl --> draw icon
  • _setCornerCursor --> show cursor
  • _getActionFromCorner --> create action by mouse down
  • _performTransformAction --> perform action by mouse move

var canvas = new fabric.Canvas('canvas');
var DIMICON = 15;
var HideControls = {
            'tl':true,
            'tr':true,
            'bl':true,
            'br':true,
            'ml':false,
            'mt':false,
            'mr':false,
            'mb':false,
            'mtr':false
        };


 var dataImage = [
	"https://cdn1.iconfinder.com/data/icons/streamline-interface/60/cell-8-10-120.png", /*scale*/
      "https://cdn1.iconfinder.com/data/icons/ui-color/512/Untitled-12-128.png", /*delete*/
      "https://cdn2.iconfinder.com/data/icons/social-messaging-productivity-1/128/sync-16.png", /*rotate*/
      "https://cdn2.iconfinder.com/data/icons/social-messaging-productivity-1/128/write-compose-16.png", /*change text*/
      "https://cdn3.iconfinder.com/data/icons/social-messaging-productivity-1/128/save-16.png" /*save*/
  ];
//********override*****//
fabric.Object.prototype._drawControl = function(control, ctx, methodName, left, top) {
      if (!this.isControlVisible(control)) {
        return;
      }
	  var SelectedIconImage = new Image();
      var size = this.cornerSize;
    /*  fabric.isVML() ||*/ this.transparentCorners || ctx.clearRect(left, top, size, size);
	   switch (control)
            {
            case 'tl':/*delete*/
              SelectedIconImage.src = dataImage[1];
			  break;
            case 'tr':/*scale*/
              SelectedIconImage.src = dataImage[0];	  
			  break;
            case 'bl':/*scale*/
             SelectedIconImage.src = dataImage[0];
			  break;
            case 'br':/*rotate*/
              SelectedIconImage.src = dataImage[2];
			  break;
            default:
              ctx[methodName](left, top, size, size);
            }
             
            if (control == 'tl' || control == 'tr' || control == 'bl' || control == 'br')
            {
              try {
                ctx.drawImage(SelectedIconImage, left, top, DIMICON, DIMICON); 
              } catch (e) {
				  ctx[methodName](left, top, size, size);
              }
            }
    }
 
//override prorotype _setCornerCursor to change the corner cusrors
	fabric.Canvas.prototype._setCornerCursor =  function(corner, target) {
		if (corner === 'mtr' && target.hasRotatingPoint) {
			this.setCursor(this.rotationCursor);
			/*ADD*/
		  }else if(corner == "tr" || corner == "bl" ){
			  this.setCursor('sw-resize'); 

		  }else if(corner == "tl" || corner == "br"){
			  this.setCursor('pointer');  
		  }			  
			/*ADD END*/
		  else {
			this.setCursor(this.defaultCursor);
			return false;
		  }
    };
	fabric.Canvas.prototype._getActionFromCorner = function(target, corner){
      var action = 'drag';
	  if (corner){
		  switch(corner){
			case 'ml':
			case 'mr':
				action = 'scaleX';
				break;
			case 'mt':
			case 'mb':
				action = 'scaleY';
				break;
			case 'mtr':
				action = 'rotate';
				break;
			/**ADD **/	
			case 'br':
				action = 'rotate';
				break;
			case 'tl'://delete function if mouse down
				action = 'delete';
				canvas.remove(canvas.getActiveObject());
				break;		
			/**ADD END**/				
			default:  action = 'scale';
		  }
		  return action;
	  }
    }  
	
	fabric.Canvas.prototype._performTransformAction = function(e, transform, pointer) {
      var x = pointer.x,
          y = pointer.y,
          target = transform.target,
          action = transform.action;

      if (action === 'rotate') {
        this._rotateObject(x, y);
        this._fire('rotating', target, e);
      }
      else if (action === 'scale') {
        this._onScale(e, transform, x, y);
        this._fire('scaling', target, e);
      }
      else if (action === 'scaleX') {
        this._scaleObject(x, y, 'x');
        this._fire('scaling', target, e);
      }
      else if (action === 'scaleY') {
        this._scaleObject(x, y, 'y');
        this._fire('scaling', target, e);
      }
	  /**ADD**/
	  else if (action === 'delete') {
		//do nothing, because here function executed when mouse moves
	  }
	  /**ADD END**/
	  else {
        this._translateObject(x, y);
        this._fire('moving', target, e);
        this.setCursor(this.moveCursor);
      }
    }
//********override END*****//
 
 //create a rect object  
 var rect = new fabric.Rect({
        left: 100,
        top: 100,
        fill:  "#FF0000",
        stroke: "#000",
        width: 100,
        height: 100,
        strokeWidth: 10, 
        opacity: .8       
    });
canvas.add(rect);    
rect.setControlsVisibility(HideControls);

fabric.Image.fromURL('http://serio.piiym.net/CVBla/txtboard/thumb/1260285874089s.jpg', function (img) {
    img.top = 60;
    img.left = 250;
    img.setControlsVisibility(HideControls);
    canvas.add(img);
});

canvas.renderAll();
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.5.0/fabric.min.js"></script>
<div id="canvas-container" class="over">
    <div class="canvas-container" style="width: 800px; height: 600px; position: relative; -webkit-user-select: none;">
        <canvas id="canvas" width="800" height="600"></canvas>
    </div>
</div>