仿写一个设计编辑器第三天

47 阅读3分钟
仿写设计编辑器第三天

今天主要完成了头部区域的导入文件,和对画布中的元素的排列方式操作

导入JSON文件

使用Element-ui 的upload上传,在文件上传成功前使用before-upload 拿到上传的文件 使用HTML5的文件解析FileReder(),使用reader.readAsText(file),对文件进行解析,在文件读取成功的钩子onload()后拿到文件读取的结果,拿到读取后的json文件后,下载所需要的font-family 最后使用fabric.js的loadFromJSON()将JSON文件渲染到画布

methods: {
// 上传前拿到文件进行处理
handleUpload(file) {
    const reader = new FileReader();
    reader.readAsText(file);
    reader.onload = () => {
        this.jsonFile = reader.result;
    };
},

// 插入文件
insertJSON() {
    downFontByJSON(this.jsonFile).then(() => {
        this.canvas.c.loadFromJSON(
        this.jsonFile,
        this.canvas.c.renderAll.bind(this.canvas.c)
        );
    });
},

导入SVG图片

拿到文件的操作与前面相同,读取文件使用的是readAsDataURL()解析文件,然后使用fabric.js的loadSVGFromURL(){其中使用fabric.util.groupSVGElements()组合svg}渲染到画布

methods: {
// 在上传文件前处理文件
handleUpload(file) {
    getImgStr(file).then((res) => {
        this.svgFile = res;
    });
},

// 插入svg文件
insertSVG() {
    this.fabric.loadSVGFromURL(this.svgFile, (objects, options) => {
        const item = this.fabric.util.groupSVGElements(objects, {
                ...options,
                name: "svg",
                id: uuid(),
            });
            item.scale(0.1);
            this.canvas.c.add(item).centerObject(item).renderAll();
        });
    },
},

导入图片

methods: {
    handleUpload(file) {
    getImgStr(file).then((res) => {
        this.imgFile = res;
    });
},

//插入图片
insertImg() {
    const imgEle = document.createElement("img");
    imgEle.src = this.imgFile;
    document.body.appendChild(imgEle);
    imgEle.onload = () => {
        // 创建图片对象
        const imgInstance = new this.fabric.Image(imgEle, {
        id: uuid(),
        name: "图片1",
        left: 100,
        top: 100,
    });
    imgInstance.scale(0.2);
    // 添加canvas
    this.canvas.c.add(imgInstance);
    // 设置图片可缩放
    this.canvas.c.setActiveObject(imgInstance);
    this.canvas.c.renderAll();
    // 删除创建的图片元素
    imgEle.remove();
    };
},
},

画布里面图片的排列

首先要确定选中的元素是单个还是多个,在util中使用EventEmiter给元素绑定选中和取消选中事件,每次触发事件就调用定义在select.js中的选择事件

//uitil
import EventEmitter from 'events'

class EventHandle extends EventEmitter {
// 初始化绑定事件
init(handler) {
    this.handler = handler
    this.handler.on("selection:created", (e) => this._selected(e))
    this.handler.on("selection:updated", (e) => this._selected(e))
    this.handler.on("selection:cleared", (e) => this._selected(e))
}

// 暴露多选事件
_selected(e) {
    // getActiveObjects()拿到选中的元素
    const actives = this.handler.getActiveObjects()
    if (actives && actives.length === 1) {
        // 触发选中事件
        this.emit('selectOne', actives)
    } else if (actives && actives.length > 1) {
        this.mSelectMode = 'multiple'
        this.emit('selectMultiple', actives)
    } else {
        this.emit('selectCancel')
    }
   }
}
export default EventHandle
// 混入 canvas fabric event
export default {
    inject: ['canvas', 'fabric', 'event'],
    data() {
        return {
            mSelectMode: '', // one | multiple
            mSelectOneType: '', // i-text | group ...
            mSelectId: '', // 选择id
            mSelectIds: [], // 选择id
    }
    },
    created() {
        // 给event实例改在选择事件
        this.event.on('selectOne', (e) => {
            this.mSelectMode = 'one'
            this.mSelectId = e[0].id
            this.mSelectOneType = e[0].type
            this.mSelectIds = e.map(item => item.id)
        })
        this.event.on('selectMultiple', (e) => {
            this.mSelectMode = 'multiple'
            this.mSelectId = ''
            this.mSelectIds = e.map(item => item.id)
        })
        this.event.on('selectCancel', () => {
            this.mSelectId = ''
            this.mSelectIds = []
            this.mSelectMode = ''
            this.mSelectOneType = ''
        })
    },
}

在选中后根据选中的图片是一个还是多个来判断是否显示按钮 点击按钮后先用canvas.getActiveObject()拿到选中的元素,之后再对每个元素的left和top元素进行操作


// 左对齐
alignLeft() {
// 获取选中的元素
    const activeObject = this.canvas.c.getActiveObject();
    if (activeObject && activeObject.type === "activeSelection") {
        const activeSelection = activeObject;
        const activeObjectLeft = -(activeObject.width / 2);
        activeSelection.forEachObject((item) => {
        item.set({
        left: activeObjectLeft,
    });
        // 调用setCoords()才能重新计算控制位置
        item.setCoords();
        this.canvas.c.renderAll();
        });
    }
},

// 右对齐
alignRight() {
    const activeObject = this.canvas.c.getActiveObject();
    if (activeObject && activeObject.type === "activeSelection") {
        const activeSelection = activeObject;
        const activeObjectLeft = activeObject.width / 2;
            activeSelection.forEachObject((item) => {
            item.set({
            left: activeObjectLeft - item.width * item.scaleX,
        });
            item.setCoords();
            this.canvas.c.renderAll();
        });
    }
},

// 水平居中对齐
centerHorizontally() {
    const activeObject = this.canvas.c.getActiveObject();
    if (activeObject && activeObject.type === "activeSelection") {
        activeObject.forEachObject((item) => {
            item.set({
            left: 0 - (item.width * item.scaleX) / 2,
        });
            item.setCoords();
            this.canvas.c.renderAll();
        });
    }
},

// 垂直居中对齐
verticalCenter() {
    const activeObject = this.canvas.c.getActiveObject();
        if (activeObject && activeObject.type === "activeSelection") {
        activeObject.forEachObject((item) => {
            item.set({
            top: 0 - (item.width * item.scaleY) / 2,
        });
            item.setCoords();
            this.canvas.c.renderAll();
        });
    }
},

// 顶部对齐
alignTop() {
    const activeObject = this.canvas.c.getActiveObject();
    if (activeObject && activeObject.type === "activeSelection") {
        const activeObjectTop = -(activeObject.height / 2);
        activeObject.forEachObject((item) => {
            item.set({
            top: activeObjectTop,
        });
            item.setCoords();
            this.canvas.c.renderAll();
        });
    }
},

// 底部对齐
alingBottom() {
    const activeObject = this.canvas.c.getActiveObject();
    if (activeObject && activeObject.type === "activeSelection") {
        const activeObjectTop = activeObject.height / 2;
        activeObject.forEachObject((item) => {
            item.set({
            top: activeObjectTop - item.height * item.scaleY,
        });
            item.setCoords();
            this.canvas.c.renderAll();
        });
    }
},

选中元素的旋转

拿到选中的元ji使用cnavas.set(scaleX,-1)进行绕X轴旋转,canvas.set(scaleY,-1),绕Y轴旋转,旋转后要使用cnavas.scale()把元素设置为原来的尺寸

flip(type) {
const activeObject = this.canvas.c.getActiveObject();
    console.log(activeObject.type)
    activeObject.set("scale" + type, -1).setCoords();
    activeObject.scale(0.1);
    this.canvas.c.renderAll();
},

合拼或者打散选中的元素

拿到选中的元素,选中类型为mutiple时,使用toGroup()将元素组合在一起,选中类型为one时,使用toActiveSelection()将元素拆解

// 打散组合
unGroup() {
    // 先获取对象然后打散
    const activeObject = this.canvas.c.getActiveObject().toActiveSelection();
    //取消选中
    this.canvas.c.discardActiveObject().renderAll();
},

// 组合SVG图片
toGroup() {
    const activeObject = this.canvas.c.getActiveObject();
    const activeGrounp = activeObject.toGroup();
},

改变选中元素的尺寸

拿到选中的元素后,对canvas.scaleX和canvas.scalexY的值进行加减

// 放大选中的图片
toLarger() {
    const activeObject = this.canvas.c.getActiveObject();
    activeObject.scaleX += 0.03;
    activeObject.scaleY += 0.03;
    this.canvas.c.renderAll();
},

// 缩小选中的图片
toSmall(e) {
    const activeObject = this.canvas.c.getActiveObject();
    activeObject.scaleX -= 0.03;
    activeObject.scaleY -= 0.03;
    this.canvas.c.renderAll();
},

// 还原选中的图片
toDefault() {
    const activeObject = this.canvas.c.getActiveObject();
    activeObject.scale(0.1);
    this.canvas.c.renderAll();
},