向控件中添加自定义的删除(后退,前进)按钮

17
我想知道是否有一种简单的方法将删除、置顶和置底功能添加到现有的fabric.js对象控件中。
目前,我只能点击按钮来删除对象、置顶等等。
我正在努力寻找解决方案,以便在对象上按X(位于右上角)并删除该对象
我猜这将涉及覆盖、包装或子类化现有控件对象。
也许我错过了什么,有一个简单的解决方案?请不要使用div封装器。 Fabric.js Canvas Object Selection Delete X
5个回答

11

Fabric.js没有提供为对象添加控件的简单方式。

如果您想创建自己的控件,您将需要覆盖Object类,特别是:

  • 覆盖drawControls方法,以绘制您自定义的按钮。
  • 您需要存储按钮的坐标,以便能够检测用户何时单击它们。请参考_setCornerCoords_findTargetCorner
  • __onMouseDown中的某个位置整合您的操作。

您不需要担心撤销控件的绘制,因为当取消选择对象时,整个画布将被重新渲染。

希望这些信息对您有所帮助,祝好运 :)


所以我猜这是我们能得到的最接近的了? :) 我看到了 object_interactivity.mixin.js 中的 drawControls。我会去看一下的。如果没有其他答案,你就会得到赏金。 - zer02
@zer02,你有没有找到解决方案?我也想实现类似的东西。 - Kundan Singh Chouhan

5

我是通过定位HTML元素来实现的

canvas.on('object:selected',function(e){


        jQuery(".deleteBtn").remove(); 
        var btnLeft = e.target.oCoords.mt.x;
        var btnTop = e.target.oCoords.mt.y - 25;
        var widthadjust=e.target.width/2;
        btnLeft=widthadjust+btnLeft-10;
        var deleteBtn = '<p" class="deleteBtn" title="Delete" style="position:absolute;top:'+btnTop+'px;left:'+btnLeft+'px;cursor:pointer;" title="Remove object">&#10005;</p>';
        jQuery(".canvas-container").append(deleteBtn);
        //.canvas-container is the parent div to the canvas positioned relative via CSS



    });

canvas.on('mouse:down',function(e){
    if(canvas.getActiveObject())
    {

    }
    else
    {
         jQuery(".deleteBtn").remove(); 
    }
});


canvas.on('object:modified',function(e){


        jQuery(".deleteBtn").remove(); 
        var btnLeft = e.target.oCoords.mt.x;
        var btnTop = e.target.oCoords.mt.y - 25;
        var widthadjust=e.target.width/2;
        btnLeft=widthadjust+btnLeft-10;
        var deleteBtn = '<p" class="deleteBtn" title="Delete" style="position:absolute;top:'+btnTop+'px;left:'+btnLeft+'px;cursor:pointer;" title="Remove object">&#10005;</p>';
        jQuery(".canvas-container").append(deleteBtn);
        //.canvas-container is the parent div to the canvas positioned relative via CSS



    });


//THE DELETE BUTTON CLICK EVENT
 jQuery(document).on('click',".deleteBtn",function(){


    if(canvas.getActiveObject())
    {
         canvas.remove(canvas.getActiveObject());
//this would remove the currently active object on stage,
         jQuery(this).remove();
         jQuery(".deleteBtn").remove();
    }


     })

请查看已实现上述代码的jsfiddle - melwyn pawar
我正在我的画布中应用相同的解决方案。所有东西都运行良好,但是当用户旋转图像时,删除图像无法放置在正确的位置。请问当用户旋转时,我应该尝试添加什么来放置删除图像? - Vineet

3

我认为使用DOM元素的解决方案不太稳定,但如果它能满足你的需求就可以了。同时,我还需要为我的Web应用程序更改默认对象的角落按钮为自定义按钮。

  1. '更改大小' 按钮,/出于某些原因,我不再使用它/
  2. '删除对象' 按钮
  3. '编辑对象' 按钮
  4. '旋转对象' 按钮

所以你需要改变两件事才能成功:

1. 修改fabric.js文件中的私有函数'_drawControl'。在我的fabric.js文件中,此函数大约在第13367行。在该函数中,fabric绘制对象的默认角落按钮并在选择时显示它们。我们可以很容易地将png更改为我们的自定义按钮。

下面是我更改后的_drawControl(fabric.js):

     _drawControl: function(control, ctx, methodName, left, top, flipiX, flipiY) {

              var sizeX = this.cornerSize / this.scaleX,
                  sizeY = this.cornerSize / this.scaleY;

              if (this.isControlVisible(control)) {
                isVML || this.transparentCorners || ctx.clearRect(left, top, sizeX, sizeY);

          var SelectedIconImage = new Image();
          var lx='';
          var ly='';
          var n='';

          switch (control)
            {
            case 'tl':      
              if (flipiY) { ly='b'; } else { ly = 't'; }
              if (flipiX) { lx='r'; } else { lx = 'l'; }
              break;
            case 'tr':
              if (flipiY) { ly='b'; } else { ly = 't'; }
              if (flipiX) { lx='l'; } else { lx = 'r'; }
              break;
            case 'bl':
              if (flipiY) { ly='t'; } else { ly = 'b'; }
              if (flipiX) { lx='r'; } else { lx = 'l'; }
              break;
            case 'br':
              if (flipiY) { ly='t'; } else { ly = 'b'; }
              if (flipiX) { lx='l'; } else { lx = 'r'; }
              break;
            default:
              ly=control.substr(0, 1);
              lx=control.substr(1, 1);
              break;
            }

          control=ly+lx;

          switch (control)
            {
            case 'tl':      

//my custom png for the object's top left corner
              SelectedIconImage.src = 'assets/img/icons/draw_control/icon_rotate.png';
              break;
            case 'tr':
              if (flipiX && !flipiY) { n='2'; }
              if (!flipiX && flipiY) { n='3'; }
              if (flipiX && flipiY) { n='4'; }

//my custom png for the object's top right corner
                SelectedIconImage.src = 'assets/img/icons/draw_control/icon_delete.png';
              break;
            case 'mt':
              SelectedIconImage.src = //add your png here if you want middle top custom image;
              break;
            case 'bl':
              if (flipiY) { n='2'; }
              SelectedIconImage.src = //add your png here if you want bottom left corner custom image;
              break;
            case 'br':
              if (flipiX || flipiY) { n='2'; }
              if (flipiX && flipiY) { n=''; }
//my custom png for the object's bottom right corner
              SelectedIconImage.src = 'assets/img/icons/draw_control/icon_settings.png';
              break;
            case 'mb':
              SelectedIconImage.src = //middle bottom png here ;
              break;
            case 'ml':
              SelectedIconImage.src = 'assets/img/icons/draw_control/icono_escala_horizontal'+n+'.jpg';
              break;
            case 'mr':
              SelectedIconImage.src = //middle right png here;
              break;
            default:
              ctx[methodName](left, top, sizeX, sizeY);
              break;
            }

     // keep middle buttons size fixed
            if (control == 'tl' || control == 'tr' || control == 'bl' || control == 'br'
            || control == 'mt' || control == 'mb' || control == 'ml' || control == 'mr')
            {
              sizeX = 19;
              sizeY = 19;
              ctx.drawImage(SelectedIconImage, left, top, sizeX, sizeY);
            }


              try {
                ctx.drawImage(SelectedIconImage, left, top, sizeX, sizeY); 

              } catch (e) {
                if (e.name != "NS_ERROR_NOT_AVAILABLE") {
                  throw e;
                }
              }


        }
  },
  1. As Toon Nelissen mentioned before, i overide the fabric.Canvas.prototype.__onMouseDown function , and control my custom buttons.

    fabric.Canvas.prototype.__onMouseDown = function (e) {
    
    // accept only left clicks
    var isLeftClick  = 'which' in e ? e.which === 1 : e.button === 1;
    if (!isLeftClick && !fabric.isTouchSupported) {
        return;
    }
    
    if (this.isDrawingMode) {
        this._onMouseDownInDrawingMode(e);
        return;
    }
    
    // ignore if some object is being transformed at this moment
    if (this._currentTransform) {
        return;
    }
    
    var target = this.findTarget(e), 
    pointer = this.getPointer(e, true);
    
    //if user clicked on the top right corner image
    if (target && target.__corner === 'tr') {
              //my code goes here
        }
    } else {
        // save pointer for check in __onMouseUp event
        this._previousPointer = pointer;
    
        var shouldRender = this._shouldRender(target, pointer),
          shouldGroup = this._shouldGroup(e, target);
    
        if (this._shouldClearSelection(e, target)) {
            this._clearSelection(e, target, pointer);
        } else if (shouldGroup) {
            this._handleGrouping(e, target);
            target = this.getActiveGroup();
        }
    
        if (target && target.selectable && !shouldGroup) {
        this._beforeTransform(e, target);
        this._setupCurrentTransform(e, target);
        }
        // we must renderAll so that active image is placed on the top canvas
        shouldRender && this.renderAll();
    
        this.fire('mouse:down', { target: target, e: e });
        target && target.fire('mousedown', { e: e });
    }
    

    };

对于其余的角落,我们也编写了适当的代码片段(在__onMouseDown内):

 //if user clicked on the bottom right corner image
        if (target && target.__corner === 'br') {
             //my code here
         }else{
            //the same as 'tr'
        }

 //if user clicked on the top left corner image
            if (target && target.__corner === 'tl') {
                 //my code here
             }else{
                //the same as 'tr'
            }

 //if user clicked on the bottom left corner image
            if (target && target.__corner === 'bl') {
                 //my code here
             }else{
                //the same as 'tr'
            }

以下是我的Web应用程序自定义图像的截图。 在此输入图片描述

2
您可以尝试使用HTML按钮。看看这个示例:

http://fabricjs.com/interaction-with-objects-outside-canvas/

这里是代码示例:
    (function() {
  var canvas = this.__canvas = new fabric.Canvas('c');
  fabric.Object.prototype.transparentCorners = false;
  fabric.Object.prototype.originX = fabric.Object.prototype.originY = 'center';

  fabric.Canvas.prototype.getAbsoluteCoords = function(object) {
    return {
      left: object.left + this._offset.left,
      top: object.top + this._offset.top
    };
  }

  var btn = document.getElementById('inline-btn'),
      btnWidth = 85,
      btnHeight = 18;

  function positionBtn(obj) {
    var absCoords = canvas.getAbsoluteCoords(obj);

    btn.style.left = (absCoords.left - btnWidth / 2) + 'px';
    btn.style.top = (absCoords.top - btnHeight / 2) + 'px';
  }

  fabric.Image.fromURL('../lib/pug.jpg', function(img) {

    canvas.add(img.set({ left: 250, top: 250, angle: 30 }).scale(0.25));

    img.on('moving', function() { positionBtn(img) });
    positionBtn(img);
  });
})();

这不是我的,所以我无法删除它,抱歉。 - kleopatra

1

例如,您可以覆盖 __onMouseDown 函数,像这样。

目标对象包含 __corner 元素 target.__corner

检查这是否为“tr”(右上角),然后删除 activeObject。

    if (target.__corner === 'tr') {
        if(canvas.getActiveObject()){
            canvas.remove(canvas.getActiveObject());
        }
    }

完整代码:

fabric.Canvas.prototype.__onMouseDown = function (e) {

    // accept only left clicks
    var isLeftClick  = 'which' in e ? e.which === 1 : e.button === 1;
    if (!isLeftClick && !fabric.isTouchSupported) {
        return;
    }

    if (this.isDrawingMode) {
        this._onMouseDownInDrawingMode(e);
        return;
    }

    // ignore if some object is being transformed at this moment
    if (this._currentTransform) {
        return;
    }

    var target = this.findTarget(e), 
    pointer = this.getPointer(e, true);

    if (target && target.__corner === 'tr') {
        if(this.getActiveObject()){
            this.remove(this.getActiveObject());
        }
    } else {
        // save pointer for check in __onMouseUp event
        this._previousPointer = pointer;

        var shouldRender = this._shouldRender(target, pointer),
          shouldGroup = this._shouldGroup(e, target);

        if (this._shouldClearSelection(e, target)) {
            this._clearSelection(e, target, pointer);
        } else if (shouldGroup) {
            this._handleGrouping(e, target);
            target = this.getActiveGroup();
        }

        if (target && target.selectable && !shouldGroup) {
        this._beforeTransform(e, target);
        this._setupCurrentTransform(e, target);
        }
        // we must renderAll so that active image is placed on the top canvas
        shouldRender && this.renderAll();

        this.fire('mouse:down', { target: target, e: e });
        target && target.fire('mousedown', { e: e });
    }
};

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接