今天完成了canvas对象的锁定,删除复制,整个画布的清空,和保存画布为JSON文件,SVG,复制到剪贴板,保存为图片,还实现了返回上一步操作
选中对象的锁定
使用Element-ui的switch组件,使用v-model绑定switch的开关值,判断是否选中canvas对象,来决定开关是否可用,给event实例上绑定的selectOne上事件设定回调,每次选中单个元素是,就拿到当前选中元素的hasControls的属性值并赋值给switch的开关值,使每次选中对象时都可正确显示开光,点击开关时绑定事件,改变选中对象的可控属性,把选中元素的hasControls属性取反可以使对象无法改变大小,并且给选中对象的lockMovementX(Y,Z)设置为当前的开关的值,可以是选中对象无法移动
created() {
this.event.on("selectOne", (item) => {
if (this.isLocked !== "undefined") {
this.isLocked = !item[0].hasControls;
}
});
},
methods: {
isSelected() {
return this.mSelectMode !== "one";
},
changeLock() {
const activeObject = this.canvas.c.getActiveObject();
// 改变选中对象的大小是否可设置属性
activeObject.hasControls = !activeObject.hasControls;
// 取消选中
this.canvas.c.discardActiveObject().renderAll();
// 修改选中对象的是否可以移动属性
lockAttrs.forEach((item) => {
activeObject[item] = this.isLocked;
});
},
},
复制元素
使用fabric.js的clone方法克隆后添加到画板即可
copySelected() {
const activeObject = this.canvas.c.getActiveObject();
// 克隆选中的对象
activeObject.clone((cloned) => {
this.canvas.c.discardActiveObject();
cloned.set({
left: cloned.left + 10,
top: cloned.top + 10,
id: uuid(),
});
// 添加克隆的对象
this.canvas.c.add(cloned);
this.canvas.c.renderAll();
});
},
清空画板
使用fabric.js的clear方法即可清空画板
clear() {
this.canvas.c.clear();
},
保存画板
使用Element-ui的## Dropdown下拉菜单来实现ui,el-dropdown里面可以绑定command事件,可以根据el-dropdown-item的command属性来判断点哪个下拉菜单
复制到剪贴板
copyToClipboard() {
const jsonStr = this.canvas.c.toJSON(["id"]);
this._mixinClipboard(JSON.stringify(jsonStr, null, "\t"));
},
// 复制
import VueClipboard from "vue-clipboard2";
_mixinClipboard(clipboardText) {
this.$copyText(clipboardText).then(() => {
this.$message('复制成功');
}, () => {
this.$message('复制失败');
})
},
保存为图片,svg文件,json文件
拿到文件路径后,生成一个a标签,把生成的路径给元素的herf,然后使用a.download下载路径文件
// 下载文件
downFile(fileUrl, fileType) {
const a = document.createElement("a");
a.href = fileUrl;
a.download = uuid() + "." + fileType;
a.click();
a.remove();
},
保存为图片
saveToImg() {
//图片设置
const option = {
name: "New Image",
format: "png",
quality: 1,
multiplier: 2,
};
const dataUrl = this.canvas.c.toDataURL(option);
this.downFile(dataUrl, "png");
},
保存为SVG文件
saveToSvg() {
const svgUrl = this.canvas.c.toSVG();
// encodeURIComponent() 函数
// 作用:可把字符串作为URI 组件进行编码。其返回值URIstring 的副本,其中的某些字符将被十六进制的转义序列进行替换。
const fileStr = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(
svgUrl
)}`;
this.downFile(fileStr, "svg");
},
保存为JSON文件
saveToJSON() {
const jsonUrl = this.canvas.c.toJSON();
const fileStr = `data:text/json;charset=utf-8,${encodeURIComponent(
JSON.stringify(jsonUrl, null, "\t")
)}`;
this.downFile(fileStr, "json");
},
返回上一步操作
思路:创建两个队列一个保存之前的canvas(backList),一个保存返回之前的canvas(toList),给canvas绑定事件: 先将改变前的canvas加入backList object:modified,selection:updated,但更改canvas对象时,使用push将当前canvas对象加入backList(json格式),当用点击返回上一步时,使用splice(backList.lenght,1)[0],拿到改变前的json对象,然后使用loadFormJSON()使用拿到的对象渲染画布,之后使用pop()拿到当前的json对象,把这个对象push到toList,点击前进时使用pop()拿到toList的最后一个json对象,使用这个对象渲染画布
mounted() {
this.$nextTick(() => {
this.backList = this.$backList;
this.canvas.c.on({
"object:modified": this.save,
"selection:updated": this.save,
});
});
methods: {
// 保存纪录
save() {
const item = this.canvas.c.toJSON("id");
if (this.backList.length == maxNum) {
this.backList.shift();
}
this.backList.push(item);
},
// 后退
back() {
if (this.backList.length) {
// 拿到返回队列最新添加的元素
const item = this.backList.splice(this.backList.length - 2, 1)[0];
this.renderCanvas(item);
// 将本次加入队列
const item2 = this.backList.pop();
this.goList.push(item2);
}
},
// 前进
go() {
if (this.goList.length) {
const item = this.goList.pop();
this.renderCanvas(item);
this.backList.push(item);
}
},
// 渲染
renderCanvas(json) {
this.canvas.c.clear();
this.canvas.c.loadFromJSON(
json,
this.canvas.c.renderAll.bind(this.canvas.c)
);
this.canvas.c.requestRenderAll();
},
},