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

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

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

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

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

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

【问题讨论】:

    标签: javascript html canvas html5-canvas fabricjs


    【解决方案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. “改变尺寸”按钮,/出于我的原因,我不再使用它了/
    2. “删除对象”按钮
    3. “编辑对象”按钮
    4. '旋转对象'按钮

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

    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;
                    }
                  }
    
    
            }
      },
    
    1. 正如 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 });
          }
      };
      

      【讨论】:

        猜你喜欢
        • 2011-10-18
        • 2020-07-21
        • 1970-01-01
        • 2021-06-27
        • 1970-01-01
        • 2011-06-09
        • 2018-01-31
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多