向控件添加自定义删除(后退、前移)按钮
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">✕</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">✕</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 );
;
【讨论】:
以上是关于向控件添加自定义删除(后退、前移)按钮的主要内容,如果未能解决你的问题,请参考以下文章
创建自定义导航栏渲染器以在 xamarin 表单 IOS 项目中添加自定义后退按钮图标
android 自定义控件(带有删除按钮的imageview) 怎么在ImageView背景上添加button按钮 动态添加imageview 自带删除图标的imageview list删除某