在不调整文本框大小的情况下调整Fabric Rect的大小 [英] Resize Fabric Rect without resizing Textbox

查看:503
本文介绍了在不调整文本框大小的情况下调整Fabric Rect的大小的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在此 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:

    传递给fabric.RectWithText构造函数的
  • rectOptionstextOptions是通常通常相应地传递给fabric.Rectfabric.Textbox构造函数的对象.
  • TextboxRectWithText实例的text属性引用.
  • recalcTextPosition使用两个三角函数公式来计算文本相对于矩形的位置,给定两者之间的初始偏移量.
  • 我们需要密切注意矩形的movingscalingrotating事件,以平滑地重新计算文本的位置.
  • mousedown:beforemousedblclickediting:exited确保双击后文本保持可编辑状态.
  • 我们通过在单击对象时修改canvas.preserveObjectStacking来将文本保留在顶部.
  • rectOptions and textOptions passed into the fabric.RectWithText constructor, are the objects you would normally pass into fabric.Rect and fabric.Textbox constructors, accordingly.
  • the Textbox is referenced by a text property of the RectWithText 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, and rotating 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆