在不调整文本框大小的情况下调整Fabric Rect的大小 [英] Resize Fabric Rect without resizing Textbox
问题描述
在此 jsFiddle 中,我有一个包含Rect和文本框的Fabric组.我需要能够在不缩放文本的情况下缩放Rect,所以我试图在选定组时取消分组,并在清除选定内容后再次进行分组.另外:
In this jsFiddle I have a Fabric group containing a Rect and a Textbox. I need to be able to scale the Rect without scaling the text, so I'm trying to ungroup when the group is selected, and group again when the selection is cleared. Also:
- 将Rect和Textbox分组在一起,以便能够将它们一起移动.
- 文本需要可编辑.
- 文本必须在矩形上方(即应始终可见).
如何使jsFiddle工作?
How to make the jsFiddle work?
注意
即使在选择之前或之后,文本和矩形也始终一起移动.
The text and the rectangle always move together, even before or after any selection.
var canvas = window._canvas = new fabric.Canvas('c');
var text = new fabric.Textbox("Some text", {
width: 100,
height: 22,
fontSize: 12,
editable: true
});
var rect = new fabric.Rect({
width: 100,
height: 22,
fill: 'yellow'
});
var group = new fabric.Group([ rect, text ], {
left: 30,
top: 30
});
canvas.add(group);
group.on('selected', function (e){
canvas.remove(group);
canvas.add(rect);
canvas.add(text);
canvas.renderAll();
canvas.setActiveObject(rect);
});
canvas.on('selection:cleared', function(e) {
group = new fabric.Group([ rect, text ], {});
});
推荐答案
编辑:OP阐明了一些要求,因此对解决方案进行了相应的编辑.
EDIT: the OP clarified some of the requirements, so the solution was edited accordingly.
虽然起初分组似乎是一个好主意,但是如果考虑一下,文本/矩形组合所需的唯一分组功能是能够一起移动.这意味着创建一个组并尝试禁用所有不需要的功能实际上比将Text粘贴到Rect并仅处理您关心的事件要困难得多.
While grouping may seem like a good idea at first, if you think about it, the only group feature your text/rect combination needs is the ability to move together. Which means that creating a group and trying to disable all the unwanted features is actually harder than glueing Text to your Rect and only handling events that you care about.
Fabric.js具有出色的子类化机制,我们将使用该机制扩展fabric.Rect
类.
Fabric.js has a wonderful subclassing mechanism, which we'll use to extend fabric.Rect
class.
下面的代码几乎是不言自明的,我只注意几个关键方面:
The code below is pretty much self-explanatory, I'll just note several key aspects:
-
传递给
-
rectOptions
和textOptions
是通常通常相应地传递给fabric.Rect
和fabric.Textbox
构造函数的对象. -
Textbox
由RectWithText
实例的text
属性引用. -
recalcTextPosition
使用两个三角函数公式来计算文本相对于矩形的位置,给定两者之间的初始偏移量. - 我们需要密切注意矩形的
moving
,scaling
和rotating
事件,以平滑地重新计算文本的位置. -
mousedown:before
,mousedblclick
,editing:exited
确保双击后文本保持可编辑状态. - 我们通过在单击对象时修改
canvas.preserveObjectStacking
来将文本保留在顶部.
fabric.RectWithText
构造函数的rectOptions
andtextOptions
passed into thefabric.RectWithText
constructor, are the objects you would normally pass intofabric.Rect
andfabric.Textbox
constructors, accordingly.- the
Textbox
is referenced by atext
property of theRectWithText
instance. recalcTextPosition
uses a couple of trigonometry formulas to calculate text's position in relation to the rectangle, given the initial offset between the two.- we need to keep an eye on the rectangle's
moving
,scaling
, androtating
events to recalculate text's position smoothly. mousedown:before
,mousedblclick
,editing:exited
make sure the text stays editable on double click.- we're keeping the text on top by modifying
canvas.preserveObjectStacking
when the object is clicked on.
const canvas = new fabric.Canvas('c')
fabric.RectWithText = fabric.util.createClass(fabric.Rect, {
type: 'rectWithText',
text: null,
textOffsetLeft: 0,
textOffsetTop: 0,
_prevObjectStacking: null,
_prevAngle: 0,
recalcTextPosition: function () {
const sin = Math.sin(fabric.util.degreesToRadians(this.angle))
const cos = Math.cos(fabric.util.degreesToRadians(this.angle))
const newTop = sin * this.textOffsetLeft + cos * this.textOffsetTop
const newLeft = cos * this.textOffsetLeft - sin * this.textOffsetTop
const rectLeftTop = this.getPointByOrigin('left', 'top')
this.text.set('left', rectLeftTop.x + newLeft)
this.text.set('top', rectLeftTop.y + newTop)
},
initialize: function (rectOptions, textOptions, text) {
this.callSuper('initialize', rectOptions)
this.text = new fabric.Textbox(text, {
...textOptions,
selectable: false,
evented: false,
})
this.textOffsetLeft = this.text.left - this.left
this.textOffsetTop = this.text.top - this.top
this.on('moving', () => {
this.recalcTextPosition()
})
this.on('rotating', () => {
this.text.rotate(this.text.angle + this.angle - this._prevAngle)
this.recalcTextPosition()
this._prevAngle = this.angle
})
this.on('scaling', (e) => {
this.recalcTextPosition()
})
this.on('added', () => {
this.canvas.add(this.text)
})
this.on('removed', () => {
this.canvas.remove(this.text)
})
this.on('mousedown:before', () => {
this._prevObjectStacking = this.canvas.preserveObjectStacking
this.canvas.preserveObjectStacking = true
})
this.on('mousedblclick', () => {
this.text.selectable = true
this.text.evented = true
this.canvas.setActiveObject(this.text)
this.text.enterEditing()
this.selectable = false
})
this.on('deselected', () => {
this.canvas.preserveObjectStacking = this._prevObjectStacking
})
this.text.on('editing:exited', () => {
this.text.selectable = false
this.text.evented = false
this.selectable = true
})
}
})
const rectOptions = {
left: 10,
top: 10,
width: 200,
height: 75,
fill: 'rgba(30, 30, 30, 0.3)',
}
const textOptions = {
left: 35,
top: 30,
width: 150,
fill: 'white',
shadow: new fabric.Shadow({
color: 'rgba(34, 34, 100, 0.4)',
blur: 2,
offsetX: -2,
offsetY: 2
}),
fontSize: 30,
}
const rectWithText = new fabric.RectWithText(rectOptions, textOptions, 'Some text')
canvas.add(rectWithText)
body {
background: ivory;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/3.4.0/fabric.js"></script>
<canvas id="c" width="300" height="200"></canvas>
这篇关于在不调整文本框大小的情况下调整Fabric Rect的大小的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!