如何在 Fabric.js 中的对象周围创建自定义边界框,该边界框跟随旋转并在选择事件中持续存在?

问题描述 投票:0回答:1

标题:自定义边界框跟随旋转,但在 Fabric.js 中取消选择和重新选择后不跟随旋转

描述: 各位开发者大家好,

我正在使用 Fabric.js 开发一个项目,并且我面临着在对象周围创建自定义边界框(标尺)的问题。具体如下:

  1. 最初,我尝试使用线条作为标尺,但它们在旋转过程中没有与对象同步。
  2. 现在,我已改用围绕对象的矩形,这在旋转过程中效果很好。
  3. 但是,取消选择该项目然后重新选择它后(特别是当它已经旋转时),标尺尺寸不准确。标尺没有正确跟随矩形的位置。

其他详细信息

  • 您可以查看附图以供参考(不幸的是,我无法直接在此处分享该图像)。
  • 这是我用于自定义边界框的相关代码片段:
  export class CustomFabricCanvas extends fabric.Canvas {
    constructor(element, options) {
        super(element, options);
        this.rulerLine = null;
        this.on("selection:created", this.onSelectionCreated.bind(this));
        this.on("selection:cleared", this.onSelectionCleared.bind(this));

        this.on("object:scaling", this.onObjectScaling.bind(this));
        this.on("object:moving", this.onObjectMoving.bind(this));
        this.on("object:rotating", this.onObjectRotating.bind(this));
    }

    onSelectionCreated(event) {
        const activeObject = event.selected;
        if (activeObject?.length > 0) {
            activeObject.forEach((obj) => {
                this.showRuler({ ...obj });
            });
        }
    }

    onSelectionCleared() {
        this.hideRuler();
    }

    showRuler(options) {
        if (!this.rulerLine) {
            this.rulerLine = new fabric.Rect({
                left: options.left + 50, // 
                top: options.top + 50, // +
                height: options.height + 10, 
                width: options.width + 10, 
                stroke: "black",
                strokeWidth: 1,
                fill: "transparent",
                selectable: false,
                originX: "center",
                originY: "center",
                angle: options.angle,
            });

            this.add(this.rulerLine);
            this.renderAll();
        }
    }

    hideRuler() {
        if (this.rulerLine) {
            this.remove(this.rulerLine);
            this.rulerLine = null;
            this.renderAll();
        }
    }
   onObjectRotating(e) {
        const target = e.target;
        console.log(e.target);
        this.rulerLine.set({
            angle: target.angle,
        });

        this.renderAll();
    }

}

请求帮助: 我需要帮助实施一个解决方案,以确保标尺即使在取消选择和重新选择后仍与对象的位置成比例。如何使基于矩形的标尺正确保留?

图片参考

  • 旋转后
    after rotation
  • 旋转前
    before rotation

我尝试在 Fabric.js 中的对象周围创建自定义边界框(标尺)。最初,我使用线条作为标尺,但它们在旋转过程中与对象不同步。现在,我已改用围绕对象的矩形,这在旋转过程中效果很好。

但是,取消选择该项目然后重新选择它后(特别是当它已经旋转时),标尺尺寸不准确。标尺没有正确跟随矩形的位置。

我希望标尺能够根据对象的位置进行一致调整,即使在取消选择和重新选择之后也是如此。

javascript html5-canvas fabricjs
1个回答
0
投票

在您使用的代码中:

left: options.left + 50

当您旋转左侧位置发生变化的矩形时,
如果您取消选择并重新选择,是的,您的“边界框”矩形将绘制在不同的位置...

请参阅下面的示例代码(主要是您的代码),我更改了

onObjectRotating
也设置了左侧和顶部,这样我们不仅可以在选择时看到旋转事件时您在做什么。

class CustomFabricCanvas extends fabric.Canvas {
    constructor(element, options) {
        super(element, options);
        this.rulerLine = null;
        this.on("selection:created", this.onSelectionCreated.bind(this));
        this.on("selection:cleared", this.onSelectionCleared.bind(this));

        // this.on("object:scaling", this.onObjectScaling.bind(this));
        // this.on("object:moving", this.onObjectMoving.bind(this));
        this.on("object:rotating", this.onObjectRotating.bind(this));
    }
    onSelectionCreated(event) {
        const activeObject = event.selected;
        if (activeObject?.length > 0) {
            activeObject.forEach((obj) => {
                this.showRuler({ ...obj });
            });
        }
    }
    onSelectionCleared() {
        this.hideRuler();
    }
    showRuler(options) {
        if (!this.rulerLine) {
            this.rulerLine = new fabric.Rect({
                left: options.left + 50, // 
                top: options.top + 50, // +
                height: options.height + 10, 
                width: options.width + 10, 
                stroke: "black",
                strokeWidth: 1,
                fill: "transparent",
                selectable: false,
                originX: "center",
                originY: "center",
                angle: options.angle,
            });

            this.add(this.rulerLine);
            this.renderAll();
        }
    }
    hideRuler() {
        if (this.rulerLine) {
            this.remove(this.rulerLine);
            this.rulerLine = null;
            this.renderAll();
        }
    }
    onObjectRotating(e) {
        const target = e.target;
        console.log(e.target);
        this.rulerLine.set({
            angle: target.angle,
            left: target.left + 50, // 
            top: target.top + 50
        });
        this.renderAll();
    }
}

var canvas = new CustomFabricCanvas('a');
var rect = new fabric.Rect({ left: 15, top: 50, height: 50, width: 50 })
canvas.add(rect);
canvas.renderAll();
canvas.setActiveObject(rect);
<script type='text/javascript' src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/5.3.1/fabric.min.js"></script>

<canvas id="a" width="200" height="200"></canvas>

© www.soinside.com 2019 - 2024. All rights reserved.