Добавление кнопки Custom Delete (Back, toFront) для элементов управления

Я хотел бы знать, есть ли простой способ добавить удаление, вывести на передний план, вернуть назад в существующие элементы управления fabric.js.

В данный момент я могу только нажимать на кнопки, которые удаляли бы объект, доставляли бы на передний план и т.д.

Я работаю над поиском решения, чтобы иметь возможность нажимать X (в верхнем правом углу) на объект и удалять объект.

Я предполагаю, что это будет связано с переписыванием, оберткой или подклассом существующего объекта управления.

Возможно, я что-то контролировал, и есть простое решение? Пожалуйста, нет Div Wrapper.

Fabric.js Canvas Object Selection Delete X

Ответы

Ответ 1

Fabric.js не предлагает простого средства добавления элементов управления к объектам. Если вы хотите создать свои собственные элементы управления, вам придется перезаписать класс Object, в частности:

  • переопределить drawControls, чтобы нарисовать пользовательскую кнопку
  • вам нужно будет сохранить координаты кнопок, чтобы вы могли обнаружить, когда пользователь нажимает на них. C.F. _setCornerCoords и _findTargetCorner
  • включить свое действие где-нибудь в __onMouseDown

Вам не нужно заботиться о том, чтобы "разворачивать" элементы управления, поскольку весь холст повторно отображается, когда объект не выбран.

Надеюсь, это поможет, и удачи:)

Ответ 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();
    }


     })

Ответ 3

Я считаю, что решение с элементами dom не так стабильно, но оно нормально, если оно покрывает ваши потребности,  Мне также нужно было изменить кнопки угла объекта по умолчанию, на мои пользовательские кнопки для моего веб-приложения. Я использую

  • 'изменить размер',/я больше не использую его по причинам /
  • кнопка "удалить объект"
  • кнопка "редактировать объект"
  • кнопка "поворот объекта"

поэтому вам нужно изменить 2 вещи, чтобы добиться успеха:

1. изменить частную функцию '_drawControl' из файла fabric.js. Это примерно в строке 13367 (на моем fabric.js). На этой функции ткань рисует кнопки cornet по умолчанию объектов и показывает их на seleced. Мы можем легко изменить 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 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 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 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 });
    }
    

    };

Для остальных углов мы также напишем соответствующий фрагмент (внутри __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

Вы можете перезаписать функцию __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 });
    }
};

Ответ 5

Вы можете попробовать с помощью кнопок 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);
  });
})();