Adding Custom Delete (Back,toFront) Button to Controls

后端 未结 5 1788
悲哀的现实
悲哀的现实 2020-12-30 04:11

I would like to know if there is an easy way to add a delete, bring to front, bring to back function into the existing fabric.js object controls.

A

相关标签:
5条回答
  • 2020-12-30 05:00

    You can try with html buttons. Look at the example:

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

    Here is the code example:

        (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);
      });
    })();
    
    0 讨论(0)
  • 2020-12-30 05:00

    i believe the the solution with the dom elements is not so stable but its ok if it covers your needs, I also needed to change the default object's corner buttons , to my custom buttons for my web application. I use ,

    1. 'alter size' button, /i dont use it any more for my reasons/
    2. 'delete object' button
    3. 'edit object' button
    4. 'rotate object' button

    so you have to change 2 things in order to succeed that:

    1. change the private function '_drawControl' from fabric.js file. This is about on line 13367 (on my fabric.js). On that function fabric draws the default cornet buttons of objects and show them on seleced. We can easily change the png to our custom ones.

    below is my changed _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 });
      }
      

      };

    For the rest corners we as well write the appropriate snippet(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'
                }
    

    below is a screenshot of my web app's custom images

    0 讨论(0)
  • 2020-12-30 05:00

    You can overwrite the __onMouseDown function for example like this.

    the target object contains __corner element target.__corner

    Check if this is 'tr' (top right) and delete activeObject

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

    Full code:

    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 });
        }
    };
    
    0 讨论(0)
  • 2020-12-30 05:03

    Fabric.js does not offer any simple mean of adding controls to objects. If you want to create your own controls, you will have to overwrite the Object class, notably:

    • override drawControls, to draw your custom button
    • you will need to store the button's coordinates, so that you can detect when the user clicks them. C.f. _setCornerCoords and _findTargetCorner
    • incorporate your action somewhere in __onMouseDown

    You don't need to take care of 'undrawing' the controls, as the whole canvas is re-rendered when an object is de-selected.

    I hope this helps, and good luck :)

    0 讨论(0)
  • 2020-12-30 05:11

    I have implemented it via positioning an html element

    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();
        }
    
    
         })
    
    0 讨论(0)
提交回复
热议问题