JS原生使用Fabric设计简单的图形编辑器

JS原生使用Fabric设计简单的图形编辑器

壹、在fabric和konva选型方面

作为canvas对象模型的两款框架来说都很实用,前者比较老牌,而后者符合新时代语法。fabric本身经过长时间的锤炼API很丰富但是其细节功能还是比较简单,反而konva能很好的契合TS代码简介且直观。所以我选择frabic。(笑)

贰、页面容器配置和画布创建

在你的页面直接引入不用导包

<script src="https://cdn.jsdelivr.net/npm/fabric"></script>

另起一个JS文件创建一个GraphicEditor类,哪里需要编辑器直接实例化就行:

class GraphicEditor{
    static type = 'GraphicEditor'
	constructor(param){
        super(param)
    }
	
	//初始化
	createDom(){
        //创建一个div容器用来存放你的canvas,这里我是直接用的封装好的div模块就不赘述了,跳过。
        ......
        //其次创建你的canvas来存放fabric画布
        const canv = document.createElement('canvas')
        //给canvas一个ID
        canv.setAttribute('id','canvas')
        ....针对canvas设置样式
        //将创建好的canvas添加到容器中
        容器的DOM.appendChild(canv)
        //把容器放到你页面中,可以是任意位置,我这里直接放在body下面
        document.body.appendChild('容器DOM')
        
        //接下来就是创建fabric画布
        const canvas = new fabric.Canvas('canvas')
        //设置画布的大小
        canvas.setWidth(900)
        canvas.setHeight(600)
        
        ....到此画布就创建完成了
        
    }

}

叁、图片导入(支持本地上传,电脑桌面手动复制和直接把图片拖入编辑器)

通过上面的配置,我们基本已经创建好了画布,但是一片空白啥都没有。

接下来我们导入几张图片(在类里面写个导入方法):

 // 导入图片
	//这个方法没有写上传图片的功能,只是导入到画布,你自己要得到图片路径和名称传进去
    exportToCanvas(imgSrc, imgName) {
        let imgNames = 'myImgName'
        let obj = window.grapDom.canvas.getActiveObject()
        //判断画布上是否存在图片
        if (obj) { 
            //选中的照片给清除
            window.grapDom.canvas.remove(window.grapDom.canvas.getActiveObject()) } else {
            window.grapDom.canvas.clear(); // 清空画布
        }
        fabric.Image.fromURL(imgSrc, function (oImg) {
            oImg[imgNames] = imgName //给图片对象新增一个自定义属性为图片名称
            window.grapDom.canvas.add(oImg) //讲图片给添加到画布中
            window.grapDom.canvas.centerObject(oImg); //设置图片始终处于画板中心
            window.grapDom.canvas.renderAll(); //刷新画板
        }, { crossOrigin: 'anonymous' }); //有可能报跨域的错误得添加这句话
    }

通过上面的方法就可以在画布上看见你自己上传的图片了。接下来记录下有用的两种导入图片的方法:

1.复制和粘贴图片从其他地方到画布

//首先解释下复制粘贴的实现,现代浏览器内置许多监听事件,比如我们常用的鼠标事件、键盘事件,其中当然也有我们要用到的粘贴事件paste,我们就是靠它实现。
//对你要粘贴的地方进行事件的监听,一般都是画布区域,我这里是画布是整个body.
document.body.addEventListener('paste',(event)=>{
    //获取剪切板的内容
    let cbData = event.clipboarData
    //items存放的就是剪切板的数据做循环找出图片
    for(let i=0;i<cbData.items.length;i++){
        let cbDataItem = cbData.items[i]
        let type = cbDataItem.type //判断文件类型
        if(type.indexOf("image") != -1){
           //对找到的文件做处理,转换为file对象
            let imageData = cbDataItem.getAsFile()
            //也可以在这里将文件处理为base64的文件上传到服务器后拿到图片地址,我这里通过URL方法直接转换为预览地址
			let imageURL = window.webkitURL.createObjectURL(imageData)
            
            //拿到这个地址后就和上面的导入方法进行联动了
            this.exportToCanvas(imageURL,'随便起个名字')
           }
    }
})

是不是很简单,这样就可以随意粘贴复制图片到画布了。接下来的拖拽图片到画布也是同样的原理。

2.直接从桌面拖入到画布中

拖拽的事件为dragover+drop实现,我们都知道托一张图片到网页会打开另一个网页进行预览效果,而我们则需要阻止预览打开这一行为.再次,具体流程通俗易懂来说分为:

创建一个你要放置图片的放置区域---->拖入到浏览器时触发事件这两步

//首要要有一个放置区域,反正就是我们画布的位置。我这里画布是整个body
// 初始化时将整个页面定义为放置区域
// 实时更新浏览器界面
document.body.addEventListener('dragover', (event) => {
    event.stopPropagation(); //阻止浏览器预览图片事件
    event.preventDefault();
    // 将拖放作为"复制文件"的操作。
    event.dataTransfer.dropEffect = 'copy';
})
// 浏览器接触文件时触发
document.body.addEventListener('drop', (event) => {
    event.stopPropagation();
    event.preventDefault();
    const fileList = event.dataTransfer.files; //访问文件列表
    //文件拖进来时是一个file的列表,其次就是我们的老套路了,讲file对象进行路径的转换,可以上传到服务器也可以是我这种预览文件
    let imageURL = window.webkitURL.createObjectURL(fileList[0])
    //调用图片导入方法
    this.exportToCanvas(imageURL,'随便起个名字')
})

这样几个图片导入到画布的方法就写完了,我个人觉得复制粘贴方法挺实用的,但还有很多东西没有考虑到,请大家明鉴。

肆、图片滤镜、添加文字、添加各种各样的图形

这些功能都在官网上面有对应的例子,但是官网文档读起来比较那个(你懂得),在此记录一下。

1.一些内置滤镜

  • BaseFilter 基本过滤器
  • Blur 模糊
  • Brightness 亮度
  • ColorMatrix 颜色矩阵
  • Contrast 对比
  • Convolute 卷积
  • Gamma 伽玛
  • Grayscale 灰度
  • HueRotation 色调旋转
  • Invert 倒置
  • Noise 噪音
  • Pixelate 像素化
  • RemoveColor 移除颜色
  • Resize 调整大小
  • Saturation 饱和
  • Sepia 色偏

怎么用?

// 模糊
setVague() {
    //选中你的图片
    let obj = window.grapDom.canvas.getActiveObject()
    if (!obj) return //没有就返回
    //设置图片的模糊度
    let filter = new fabric.Image.filters.Blur({
        blur: 0.5
    })
    //将滤镜添加到图片对象中
    obj.filters.push(filter)
    obj.applyFilters() //应用滤镜
    //刷新下画布
    canvas.renderAll()
}

想要清除滤镜效果的可以直接将图片对象中的filters设置为[]

2.添加文字

创建文本框对象

let text = new fabric.Textbox('双击编辑文本', {
    width: 100
})
//添加到画布中
canvas.add(text)

3.画各种图形

 // 画各种各样的图形
    /**
     * 
     * @param {String} type 什么类型的图形 
     * @param {Object} canvas 当前图形所在的画布DOM
     */
    drawSquare(type, canvas) {
        // canvas.style.cursor = 'crosshair'
        // 清空图形之前的事件
        canvas.__eventListeners["mouse:down"] ? canvas.__eventListeners["mouse:down"].splice(0) : null
        canvas.__eventListeners["mouse:move"].splice(0)
        canvas.__eventListeners["mouse:up"].splice(1)

        // 画图形时禁用画布选中和移动
        canvas.selectionColor = "transparent"
        canvas.selectionBorderColor = "transparent"
        canvas.skipTargetFind = true

        // 设置图形的起点和终点
        let downPoint = null
        let upPoint = null
        let currentSquare = null

        // 监听当前画布事件对象
        canvas.on('mouse:down', function (e) {
            // 将鼠标按下的坐标点给起点
            downPoint = e.absolutePointer
            // 检测输入的图形类型
            switch (type) {
                case 'line':
                    currentSquare = new fabric.Line([
                        downPoint.x, downPoint.y,
                        downPoint.x, downPoint.y
                    ], { stroke: 'rgba(0, 0, 0, 0.2)' })
                    break;
                case 'circle':
                    currentSquare = new fabric.Circle({
                        top: downPoint.y,
                        left: downPoint.x,
                        radius: 0,
                        fill: 'transparent',
                        stroke: 'rgba(0, 0, 0, 0.2)'
                    })
                    break;
                default:
                    break;
            }

            // 将临时轨迹添加到画布
            canvas.add(currentSquare)
        })


        canvas.on('mouse:move', function (e) {
            if (currentSquare) {
                const currentPoint = e.absolutePointer
                switch (type) {
                    case 'line':
                        currentSquare.set('x2', currentPoint.x)
                        currentSquare.set('y2', currentPoint.y)
                        break;
                    case 'circle':
                        let radius = Math.min(Math.abs(downPoint.x - currentPoint.x), Math.abs(downPoint.y - currentPoint.y)) / 2
                        let top = currentPoint.y > downPoint.y ? downPoint.y : downPoint.y - radius * 2
                        let left = currentPoint.x > downPoint.x ? downPoint.x : downPoint.x - radius * 2
                        currentSquare.set('radius', radius)
                        currentSquare.set('top', top)
                        currentSquare.set('left', left)
                        break;
                    default:
                        break;
                }
                canvas.requestRenderAll()
            }
        })

        canvas.on('mouse:up', function (e) {
            upPoint = e.absolutePointer
            if (JSON.stringify(downPoint) === JSON.stringify(upPoint)) {
                window.grapDom.canvas.remove(currentSquare)
            } else if (currentSquare) {
                currentSquare.set('stroke', '#000')
            }
            currentSquare = null
        })


    }

其他的什么裁剪图片、旋转放大缩小都比较简单就不详细说了,官网都有实际例子.

到此这个简单的图形编辑器就完成了,正好项目中要用就在此记录了一下。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值