向控件添加自定义删除(后退、前移)按钮

Posted

技术标签:

【中文标题】向控件添加自定义删除(后退、前移)按钮【英文标题】:Adding Custom Delete (Back,toFront) Button to Controls 【发布时间】:2014-03-06 20:41:16 【问题描述】:

我想知道是否有一种简单的方法可以添加删除、放在前面、放在后面 将函数添加到现有的 fabric.js 对象控件中。

目前我只能点击删除对象、放在前面等按钮。

我正在努力寻找能够在对象上按 X(右上角)并删除该对象的解决方案。

我猜这与覆盖、包装或继承现有的控件对象有关。

也许我已经监督了一些事情并且有一个简单的解决方案?请不要使用 Div Wrapper。

【问题讨论】:

【参考方案1】:

Fabric.js 不提供向对象添加控件的任何简单方法。 如果您想创建自己的控件,则必须覆盖 Object 类,特别是:

覆盖drawControls,以绘制您的自定义按钮 您需要存储按钮的坐标,以便您可以检测用户何时单击它们。参考文献_setCornerCoords_findTargetCorner__onMouseDown 的某处合并您的操作

您无需“取消绘制”控件,因为当取消选择对象时会重新渲染整个画布。

我希望这会有所帮助,祝你好运:)

【讨论】:

所以我想这是我们能得到的最接近的? :) 我在object_interactivity.mixin.js 中看到了drawControls。我会调查一下。如果没有其他答案,您将获得赏金。 @zer02,你有解决办法吗?我也想实现类似的东西。【参考方案2】:

我已经通过定位一个 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上面实现的代码 我在画布中应用的相同解决方案。一切正常,但是当用户旋转图像时,delete 图像无法放置在正确的位置。我可以知道当用户旋转时我应该尝试添加删除图像吗?【参考方案3】:

我相信带有 dom 元素的解决方案不是那么稳定,但如果它满足您的需求,它就可以了, 我还需要将默认对象的角按钮更改为我的 Web 应用程序的自定义按钮。 我用,

    “改变尺寸”按钮,/出于我的原因,我不再使用它了/ “删除对象”按钮 “编辑对象”按钮 '旋转对象'按钮

所以你必须改变两件事才能成功:

1. 从 fabric.js 文件中更改私有函数“_drawControl”。这大约在第 13367 行(在我的 fabric.js 上)。在该功能上,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;
                
              


        
  ,

    正如 Toon Nelissen 之前提到的,我覆盖了fabric.Canvas.prototype.__onMouseDown 函数,并控制了我的自定义按钮。

    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 );
    
    

    ;

对于其余的角落,我们也编写适当的 sn-p(inside __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'
            

下面是我的网络应用的自定义图像的屏幕截图

【讨论】:

【参考方案4】:

您可以尝试使用 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);
  );
)();

【讨论】:

它不是我的,所以我不能删除它,对不起【参考方案5】:

您可以像这样覆盖 __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 );
    
;

【讨论】:

以上是关于向控件添加自定义删除(后退、前移)按钮的主要内容,如果未能解决你的问题,请参考以下文章

导航栏中的 Swift 自定义后退按钮

创建自定义导航栏渲染器以在 xamarin 表单 IOS 项目中添加自定义后退按钮图标

android 自定义控件(带有删除按钮的imageview) 怎么在ImageView背景上添加button按钮 动态添加imageview 自带删除图标的imageview list删除某

Ios 导航 - 自定义后退按钮或从堆栈中删除视图控制器?

UINavigationController 的自定义修剪后退按钮文本

c# 自定义添加了控件,我想要删除其中的一个,请问要怎么做?