• fabric 组合group 增加边框


    本身是没有边框属性支持的,所以想要边框就得手写:

    大体逻辑:

    1、组合时,额外增加 rect 模拟边框样式,保存最初组合时 left top width height 属性

    2、拆分时,需计算元素 top left(缩放等属性,因为group 移除元素时使用了 removeWithUpdate,故省却计算)

    3、更新边框属性时,需删除对应边框(通常为组合最后一个元素),再根据当前 left top 和 历史 width height 计算出边框值添加到组合中

    代码:

    import { fabric } from "fabric";
    import { KeyCode } from "./key-code";
    
    /**
     * 组合
     * 使用添加 边框方法,模拟 group 的边框
     * 组合时,额外增加 rect 模拟边框样式,保存最初组合时 left top width height 属性
     * 拆分时,需计算元素 top left(缩放等属性,因为group 移除元素时使用了 removeWithUpdate,故省却计算)
     * 更新边框属性时,需删除对应边框(通常为组合最后一个元素),再根据当前 left top 和 历史 width height 计算出边框值添加到组合中
     */
    export class GroupBoxTest {
        constructor(canvas) {
            // 创建多个 rect 对象
            let rect = new fabric.Rect(GroupBoxTest.defaultRect('red', 100));
            let rect1 = new fabric.Rect(GroupBoxTest.defaultRect('yellow', 250));
            let rect2 = new fabric.Rect(GroupBoxTest.defaultRect('blue', 400));
            canvas.add(rect, rect1, rect2);
            // 绑定键盘事件
            this.bindKeyBoard(canvas);
        }
    
        /**
         * 绑定键盘事件
         * @param canvas
         */
        bindKeyBoard(canvas) {
            $(document).on('keydown', (e) => {
                const key = e.originalEvent.keyCode;
                let objs = null;
                switch (key) {
                    case KeyCode.Q: // 打印显示
                        console.log(canvas.getObjects());
                        break;
                    case KeyCode.W: // 组合
                        // 获取选中元素
                        objs = canvas.getActiveObjects();
                        // 增加判断只能组合未组合图形
                        let hasGroup = false;
                        objs.forEach((item) => {
                            if (item.id.match(/group/)) {
                                hasGroup = true;
                                return false;
                            }
                        });
                        if (hasGroup) {
                            return false;
                        }
                        // 清除活动对象,活动对象已成组,会导致位置紊乱
                        canvas.discardActiveObject();
                        // 再进行组合
                        let group = new fabric.Group(objs, {
                            id: GroupBoxTest.getId('group'),
                            lockRotation: true, // 组合元素不给旋转
                        });
                        // 给组合增加 矩形背景,用于设置 模拟组容器边框等属性
                        let groupInfo = {
                             group.width - 1,
                            height: group.height - 1,
                            left: group.get('left'),
                            top: group.get('top')
                        };
                        let borderInfo = new fabric.Rect(GroupBoxTest.defaultBorder(groupInfo));
                        group.addWithUpdate(new fabric.Rect(borderInfo));
                        canvas.add(group);
    
                        // 删掉之前对象
                        let ids = objs.map((o) => {
                            return o.id;
                        });
                        canvas.getObjects().forEach((item) => {
                            if (ids.includes(item.id)) {
                                canvas.remove(item);
                            }
                        });
                        canvas.setActiveObject(group).renderAll();
                        break;
                    case KeyCode.E: // 拆分
                        objs = canvas.getActiveObjects();
                        if (objs.length === 1 && objs[0].id.match(/group/)) {
                            // 组标志,同时拆分1 个组
                            canvas.discardActiveObject().renderAll();
                            let group = objs[0];
                            let childrenLen = group.size();
                            // 删除边框
                            group.removeWithUpdate(childrenLen - 1);
                            childrenLen -= 1;
                            // 处理内部元素
                            while (childrenLen > 0) {
                                let child = group.item(childrenLen - 1);
                                this.deleteGroup(child);
                                child.setCoords();
                                canvas.add(child);
                                childrenLen--;
                            }
                            canvas.remove(group).renderAll();
                            canvas.discardActiveObject();
                        }
                        break;
                    case KeyCode.R: // 更新表框属性
                        objs = canvas.getActiveObjects();
                        if (objs.length === 1 && objs[0].id.match(/group/)) {
                            let group = objs[0];
                            let childrenLen = group.size();
                            group.removeWithUpdate(group.item(childrenLen - 1));
                            let colorA = ['purple', 'grey', 'green', 'lightblue', 'orange', 'red'];
                            let r = Math.round(Math.random() * 20);
                            let sw = Math.round(Math.random() * 10);
                            let c = Math.round(Math.random() * 5);
                            let borderInfo = {
                                rx: r,
                                ry: r,
                                 group.width - 1,
                                height: group.height - 1,
                                left: group.left,
                                top: group.top,
                                stroke: colorA[c],
                                strokeWidth: sw,
                            };
                            group.addWithUpdate(new fabric.Rect(GroupBoxTest.defaultBorder(borderInfo)));
                            canvas.renderAll();
                        }
                        break;
                }
            });
        }
    
        /**
         * 删除组信息,并计算元素相对信息数据
         * @param ele
         */
        deleteGroup(ele) {
            ele.top = ele.top + ele.group.top + ele.group.height * 0.5;
            ele.left = ele.left + ele.group.left + ele.group.width * 0.5;
            ele.width = ele.width * ele.scaleX;
            ele.height = ele.height * ele.scaleY;
            ele.scaleX = 1;
            ele.scaleY = 1;
            delete ele.group;
        }
    
        /**
         * 获取 id = type_time
         * @param type
         * @returns {string}
         */
        static getId(type) {
            return type + '_' + new Date().getTime();
        }
    
        /**
         * 获取默认测试矩形
         * @param color
         * @param left
         * @returns {{top: number, left,  number, id: string, fill, height: number}}
         */
        static defaultRect(color, left) {
            return {
                fill: color,
                height: 100,
                left: left,
                top: 100,
                 100,
                id: GroupBoxTest.getId('rect'),
            }
        }
    
        /**
         * 获取模拟边框默认样式
         * @param info
         * @returns {{strokeWidth: number, top: number, left: number, rx: number, ry: number,  *, fill: string, stroke: string, height: *}}
         */
        static defaultBorder(info) {
            let rx = info.rx || 0;
            let ry = info.ry || 0;
            let strokeWidth = info.strokeWidth || 1;
            let stroke =  info.stroke || '#000';
            return {
                ry: rx,
                rx: ry,
                 info.width + rx + strokeWidth,
                height: info.height + ry + strokeWidth,
                left: info.left - rx * 0.5 - strokeWidth,
                top: info.top - ry * 0.5 - strokeWidth,
                fill: 'transparent',
                stroke: stroke,
                strokeWidth: strokeWidth,
            }
        }
    }
  • 相关阅读:
    Falsk的模板分配和蓝图、定制错误信息、 和补充
    Flask配置文件和 路由系统
    初始Flask
    REST Framework组件的解析源码
    MdelForm 和formset
    待修改脚本
    时间打点脚本
    Move Over and Click Link
    Wait and Click Element
    Strings=newString(“xyz”);创建了几个 StringObject?
  • 原文地址:https://www.cnblogs.com/guofan/p/16203373.html
Copyright © 2020-2023  润新知