您当前的位置:首页 >> 大数据 >  正文
【世界热闻】Fabric.js 拖放元素进画布
来源: 腾讯云      时间:2023-01-15 10:15:31
本文简介

学习 Fabric.js,我的建议是看文档不如看 demo。


(资料图片仅供参考)

本文实现的功能:将元素拖进到画布中并生成对应的图形或图片。

效果如下图所示:

思路

要实现以上效果,需要考虑以下几点:

元素有拖拽功能。能在画布中生成对应的元素。画布有可能缩放。画布有可能移动。画布的位置可能在页面的某处。在3和4情况下还能在准确的位置生成元素。

基于以上几点,我得出以下解法。

解1:要让 HTML元素具备拖拽功能,只要将 draggable属性设置为 true即可。解2:Fabric.js创建元素可看 《Fabric.js 从入门到膨胀》的基础图形篇,要创建图片可以看 图片篇。解3:缩放画布我在 《Fabric.js 缩放画布》 里讲解过。解4:移动画布我在 《Fabric.js 拖拽平移画布》 里讲解过。解5:画布的左上角不一定在body的左上角,也就是鼠标当前位置可能和画布对应的坐标不一样,需要通过加减法计算一下。解6:Fabric.js提供了一个方法可以将鼠标当前坐标转换为画布对应的真实坐标,这个方法叫 restorePointerVpt

动手

我分几个步骤慢慢实现上述功能。我知道你很急,但你先别急

创建画布及元素

<script src="https://unpkg.com/fabric@5.2.1/dist/fabric.min.js"></script><script> let canvas = null // 初始化画布 function initCanvas() { // 创建画布 canvas = new fabric.Canvas("c", { width: 800, height: 600 }) // 矩形 const rect = new fabric.Rect({ top: 30, left: 30, width: 60, height: 60, fill: "pink" }) // 将矩形添加到画布中 canvas.add(rect) // 接下来3个事件监听的主要功能是移动画布,在按住 alt 后鼠标可以拖拽画布 // 按下鼠标事件 canvas.on("mouse:down", function (opt) { var evt = opt.e; if (evt.altKey === true) { this.isDragging = true this.lastPosX = evt.clientX this.lastPosY = evt.clientY } }) // 移动鼠标事件 canvas.on("mouse:move", function (opt) { if (this.isDragging) { var e = opt.e; var vpt = this.viewportTransform; vpt[4] += e.clientX - this.lastPosX vpt[5] += e.clientY - this.lastPosY this.requestRenderAll() this.lastPosX = e.clientX this.lastPosY = e.clientY } }) // 松开鼠标事件 canvas.on("mouse:up", function (opt) { this.setViewportTransform(this.viewportTransform) this.isDragging = false }) // 监听鼠标滚轮缩放事件,可以缩放画布 canvas.on("mouse:wheel", opt => { const delta = opt.e.deltaY // 滚轮,向上滚一下是 -100,向下滚一下是 100 let zoom = canvas.getZoom() // 获取画布当前缩放值 zoom *= 0.999 ** delta if (zoom > 20) zoom = 20 // 限制最大缩放级别 if (zoom < 0.01) zoom = 0.01 // 限制最小缩放级别 // 以鼠标所在位置为原点缩放 canvas.zoomToPoint( { // 关键点 x: opt.e.offsetX, y: opt.e.offsetY }, zoom // 传入修改后的缩放级别 ) }) } initCanvas()</script>

上面的代码使用了 Fabric.js绑定了页面上的画布,并创造了一个粉红色的矩形。

按住 alt后,使用鼠标在画布上可以拖拽画布。

在画布上滚动鼠标滚轮可以缩放画布。

左侧的元素列表也将 draggable属性设置为 true,元素具备拖拽功能了。

监听元素放进画布

我们还需要使用一个变量来记录当前拖拽的是什么元素。

<script>let currentElType = null // 当前要创建的元素类型// 拖拽开始时就记录当前打算创建的元素类型function onDragstart(type) { currentType = type}</script>

前面的代码已经知道拖拽时需要生成什么类型的元素了,现在还需要知道生成到画布的哪个地方(x和y坐标)

松开鼠标时,需要计算鼠标在画布的坐标。这里的坐标是指画布在页面中的位置转换出来的坐标,而且还要计算画布拖拽和缩放过的情况。

我的做法是通过 canvas元素的 getBoundingClientRect()方法返回的对象中获取到 topleft两个数据。这两个数据就是 canvas元素距离页面顶部和左侧的距离。

然后通过鼠标当前坐标减去 canvas距离页面顶部或左侧的距离,计算出鼠标点击画布的真实坐标。

但画布有可能拖拽和缩放,所以需要通过 Fabric.js提供的 restorePointerVpt()方法将坐标转换一下。

于是有了下面的代码。

// 省略部分代码......canvas.on("drop", function(opt) {  // 画布元素距离浏览器左侧和顶部的距离  let offset = {    left: canvas.getSelectionElement().getBoundingClientRect().left,    top: canvas.getSelectionElement().getBoundingClientRect().top  }    // 鼠标坐标转换成画布的坐标(未经过缩放和平移的坐标)  let point = {    x: opt.e.x - offset.left,    y: opt.e.y - offset.top,  }  // 转换后的坐标,restorePointerVpt 不受视窗变换的影响  let pointerVpt = canvas.restorePointerVpt(point)})

生成对应的元素

上面的代码最后得出的 pointerVpt就是转换后最终的坐标,我们在这个坐标上生成元素即可。

// 省略部分代码......canvas.on("drop", function(opt) {  // 省略部分代码......  switch (currentType) {    case "rect":      createRect(pointerVpt.y, pointerVpt.x)      break    case "circle":      createCircle(pointerVpt.y, pointerVpt.x)      break    case "img":      createImg(pointerVpt.y, pointerVpt.x)    break  }  // 创建完元素,把当前操作的元素类型设置回 null  currentElType = null})// 创建矩形function createRect(top, left) {  canvas.add(new fabric.Rect({    top,    left,    width: 60,    height: 60,    fill: "pink"  }))}// 创建圆形function createCircle(top, left) {  canvas.add(new fabric.Circle({    top,    left,    radius: 30,    fill: "pink"  }))}// 创建图片元素function createImg(top, left) {  fabric.Image.fromURL("./picture.jpg", oImg => {    oImg.top = top    oImg.left = left    canvas.add(oImg)  })}

代码仓库

前面都是碎碎念,代码一段一段的。如果需要完整版代码可以打开链接自取。

⭐ Fabric.js 拖拽创建元素

X 关闭

X 关闭