Vue3使用fabric.js实现可以加载图片与绘制功能的画布

28人浏览 / 0人评论 / 添加收藏

先看下效果图:

如图所示,黑色部分为画板区域,中间为图片区域,下面的一排按钮为功能按钮,下面会一一讲解实现步骤

1. 项目初始化

1. 创建Vue3项目

yarn create vite
npm init vite@latest 
pnpm create vite

2. 处理main.js,挂载依赖
import { createApp } from 'vue'
import VueKonva from 'vue-konva';
import './index.css'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import App from './App.vue'
createApp(App).use(ElementPlus).use(VueKonva).mount('#app')

3. 项目完整代码

<template>

<div>

<canvas ref="canvasRef" id="canvas" width="800" height="600" style="border:1px solid #f00;" ></canvas>

<el-row type="flex" justify="center" style="margin-top: 50px">

<input id="setColor" v-model="brushColor" @change="selectColor" type="color" style="opacity: 0" />

<el-button type="primary" @click="openColorSelect">设置画笔颜色</el-button>

<el-button :type="paintBrush ? 'primary' : 'default'" @click="openRangeInput">设置画笔粗细</el-button>

<el-button type="primary" @click.stop="selectEraser(fabricStatus)">{{ fabricStatus ? '使用画笔' : '使用橡皮擦' }}</el-button>

<el-button :type="paintEraser ? 'primary' : 'default'" @click="openBrushNum">设置橡皮擦粗细</el-button>

<el-button type="primary" @click="undo()">上一步</el-button>

<el-button type="primary" @click="redo()">下一步</el-button>

</el-row>

<el-row type="flex" justify="center" style="margin-top: 20px">

<el-form>

<el-form-item v-if="paintBrush" label="设置画笔粗细">

<el-slider style="width: 200px" v-model="brushNum" @change="changeBrushNum" />

</el-form-item>

<el-form-item v-if="paintEraser" label="设置橡皮擦粗细">

<el-slider style="width: 200px" v-model="eraser" @change="changeEraserNum" />

</el-form-item>

</el-form>

</el-row>

</div>

</template>


<script setup>

// 导入fabric第三方库

import { fabric } from 'fabric';

import { onMounted, ref, nextTick } from 'vue'


// 创建canvas实例

const canvasRef = ref();


// 画板中默认显示的图片路径

const showImgSrc = 'https://images.ctfassets.net/hrltx12pl8hq/3E5SSUuJCKt1KyebMAdr7f/6b98ce27789b03a6b4a62092ea4566b6/Group_5_B.jpg?fit=fill&w=600&h=400';


// 画笔颜色

const brushColor = ref('#000');


// 画笔粗细滑块显示/隐藏

const paintBrush = ref(false);


// 画笔粗细

const brushNum = ref(10);


// eraser粗细滑块显示/隐藏

const paintEraser = ref(false);


// 橡皮擦粗细

const eraser = ref(10);


// 当前状态为画笔/橡皮差

const fabricStatus = ref(false);


// 撤销的快照数组,用来记录历史

let undoList = [];


// 恢复的快照数组,用来记录历史

let redoList = [];


// 添加新状态到历史记录中

function saveState() {

undoList.push(JSON.stringify(canvasRef.value.toDatalessJSON()));

}


// 撤销操作

function undo() {

// 点击撤销按钮时将undoList中的最后一个画面移动到redoList中

if (undoList.length !== 0) {

const last = undoList.pop();

redoList.push(last);

// 调用绘画页面的方法

canvasRef.value.loadFromJSON(last, function () {

canvasRef.value.renderAll();

});

}

}


// 恢复操作

function redo() {

// 点击撤销按钮时将undoList中的最后一个画面移动到redoList中

if (redoList.length !== 0) {

undoList.push(redoList.pop());

// 调用绘画页面的方法

canvasRef.value.loadFromJSON(redoList[redoList.length - 1], function () {

canvasRef.value.renderAll();

});

}

}


// 将图片绘制到canvas中

const drawCanvas = () => {

// 获取canvas元素,fabric将功能应用到此canvas中

const canvas = document.querySelector('#canvas');

// let canvas = new fabric.Canvas('canvas');

console.log('canvas.width:', canvas.width);

console.log('canvas.height:', canvas.height);


// 创建一个img实例

const img = new Image();


// 设置img的图片地址,后续此图片将会加载进canvas中

img.src = showImgSrc;


// 在图片记载完成后进行处理

img.onload = function () {

// fabric实例化

canvasRef.value = new fabric.Canvas(canvas, {

// 生成的图像宽高,这里的图像宽高为默认的canvas宽高

width: canvas.width,

height: canvas.height,

// 内部图像不允许拖动(因为拖动的动作为画笔动作,两者冲突)

selection: false,

// 开启画笔

isDrawingMode: true,

// 笔刷高清

devicePixelRatio: true,

});


console.log('img.width:', img.width);

console.log('img.height:', img.height);


// 创建图像图层

let imgLayer = new fabric.Image(img, {

erasable: false, // 不允许擦拭

// 设置图像在fabric画板中的位置为水平垂直居中

left: (canvas.width - img.width) / 2,

top: (canvas.height - img.height) / 2,

});

// 将图片添加到canvas中

canvasRef.value.add(imgLayer);

console.log('imgLayer left:', imgLayer.left);

console.log('imgLayer top:', imgLayer.top);

imgLayer.left = 100;

imgLayer.top = 100;


// 监听鼠标按下事件,添加新的状态到历史记录

canvasRef.value.on('mouse:down', function () {

saveState();

});


// 监听鼠标抬起事件,添加新的状态到历史记录

canvasRef.value.on('mouse:up', function () {

saveState();

});


// 添加缩放功能, 画板跟随鼠标缩放

canvasRef.value.on('mouse:wheel', event => {

// 获取鼠标的缩放值

var delta = event.e.deltaY;


// 获取当前画布的缩放值

var zoom = canvasRef.value.getZoom();


// 根据鼠标滚轮的滚动设置画布的缩放值

zoom *= 0.999 ** delta;


// 设置缩放值最大为1.5(原先图像的1.5倍)

if (zoom > 1.5) zoom = 1.5;


// 设置缩放值最小为0.5(原先图像的0.5倍)

if (zoom < 0.5) zoom = 0.5;


// 给定缩放所在的位置以及缩放的大小,画板就会根据给定的位置进行缩放

canvasRef.value.zoomToPoint({ x: event.e.offsetX, y: event.e.offsetY }, zoom);


// 阻止默认行为与阻止事件冒泡

event.e.preventDefault();

event.e.stopPropagation();

});

};

};


// 打开颜色选择画板

const openColorSelect = () => {

nextTick(() => document.querySelector('#setColor').click());

};


// 修改画笔颜色

const selectColor = ({ target }) => {

canvasRef.value.freeDrawingBrush.color = target.value;

};


// 切换橡皮擦/画笔状态

const selectEraser = status => {

// 判断是否为画笔状态

if (!status) {

changeAction('erase');

// 修改为橡皮擦状态

} else {

changeAction('undoErasing');

}

// 切换为另一个状态

fabricStatus.value = !fabricStatus.value;

};


// 打开/关闭设置画笔粗细滑块

const openRangeInput = () => {

paintBrush.value = !paintBrush.value;

};


// 修改画笔粗细

const changeBrushNum = () => {

canvasRef.value.freeDrawingBrush.width = brushNum.value; // 设置画笔粗细为 10

changeAction(fabricStatus.value ? 'erase' : 'undoErasing');

};


// 打开/关闭设置橡皮擦粗细滑块

const openBrushNum = () => {

paintEraser.value = !paintEraser.value;

};


// 修改橡皮擦粗细

const changeEraserNum = () => {

canvasRef.value.freeDrawingBrush.width = eraser.value; // 设置橡皮擦粗细

changeAction(fabricStatus.value ? 'erase' : 'undoErasing');

};


// 修改画板行为模式

function changeAction(mode) {

switch (mode) {

case 'erase':

canvasRef.value.freeDrawingBrush = new fabric.EraserBrush(canvasRef.value); // 使用橡皮擦

canvasRef.value.freeDrawingBrush.width = eraser.value; // 设置橡皮擦粗细

break;

case 'undoErasing':

canvasRef.value.freeDrawingBrush = new fabric.PencilBrush(canvasRef.value); // 使用橡皮擦

canvasRef.value.freeDrawingBrush.color = brushColor.value; // 使用画笔

canvasRef.value.freeDrawingBrush.width = brushNum.value; // 设置画笔粗细

default:

break;

}

}


onMounted(() => {

drawCanvas();

});

</script>
<style></style>

  

全部评论