最近项目有一个绘制的功能,搜了一圈发现fabric.js口碑不错,但是文档稀缺,于是东看看西搜搜的把项目的需求都给实现了,想分享一下。

篇幅有点长,但看完后可以轻松驾驭fabric。我的项目是基于VUE+webpack的。

先来看一下整体效果

1.安装fabric

在node环境下安装fabric.js需要先安装 jsdom 和canvas

①安装jsdom依赖

npm install jsdom --save-dev

②安装canvas依赖

npm install canvas --save-dev

③安装fabric.js

npm install fabricjs --save-dev

安装完成后 npm run dev启动你的项目就可以,无需更改其他配置

2.使用fabric

fabric.js是基于canvas的一款强大的绘制插件,我的项目里主要包括功能如下

`铅笔 箭头 直线 虚线 圆 椭圆 矩形 三角形 输入文字 移动 清空 撤回 前进 绘制图片 上传背景图`

使用之前你需要在你使用的vue页面导入fabric

import { fabric } from 'fabric'

①初始化

你的html需要有一个canvas标签: <canvas id="canvas"></canvas>

初始化:

let _this = this  //下面得用this.canvasObj = new fabric.Canvas('canvas', {
        isDrawingMode: true,   //设置是否可以绘制
        selectable: false,     //设置是否可以选中拖动  fabric提供的
        selection: false
})
this.canvasObj.setWidth(this.canvasWidth)     //设置画布的宽度this.canvasObj.setHeight(this.canvasHeight)   //设置画布的高度

/* this.canvasWidth 和 this.canvasHeight 是我在 computed 里定义的 */

//绑定画板时间 fabric为我们提供了一些事件this.canvasObj.on({  'mouse:down': (o) => {    //鼠标在画布上按下事件(起点)    //mouseFrom.x 和 mouseFrom.y 是在data中定义的数据 可以打印这个o看看    this.mouseFrom.x = o.pointer.x   //鼠标按下的X的起点    this.mouseFrom.y = o.pointer.y   //鼠标按下的y的起点    this.doDrawing = true            //绘制设为true  },  'mouse:up': (o) => {    //鼠标抬起的事件(终点)    //mouseTo.x 和 mouseTo.y 也是在data中定义的数据    this.mouseTo.x = o.pointer.x       this.mouseTo.y = o.pointer.y
    this.drawingObject = null

    this.doDrawing = false    //停止绘制
  },  'mouse:move': (o) => {    //鼠标在移动中的事件    this.offsetX = o.pointer.x.toFixed(0)   //因为是小数,所以我给取整    this.offsetY = o.pointer.y.toFixed(0)    if(!_this.doDrawing){      return    }    this.mouseTo.x = o.pointer.x    this.mouseTo.y = o.pointer.y    if(this.sineNum === 1){   //这个if是我的项目里有自定义图片的功能      this.drawing()    }else if(this.sineNum === 2){      this.diy()    }  },  'object:move': (e) => {    e.target.opacity = 0.5  //你绘画在画布上对象,移动它们的时候,让它们的透明度变成0.5  },  'object:added': (e) => {    if(!this.controlFlag){      this.redo = []  //撤回用的    }    this.controlFlag = false  },  'object:modified': (e) => {    e.target.opacity = 1  }})

初始化就这样完成了!

②点击不同形状的icon绘制不同的图形(左边那一列是写在data里的数据,然后通过v-for加载出来的)

toolsArr: [  {    name: 'pencil',    icon: 'iconpen',    label: '铅笔'  },]格式就是这样的。然后我们给每个li添加一个名叫 handleTools的事件
handleTools (tools, idx) {      //tools是item,idx是index
      this.sineNum = 1   //把sineNum设置为1 就会去加载drawing方法
      console.log(tools)
      this.initIdx = idx   //这是给li绑定的高亮的样式
      this.$store.commit('TOOGLE_TOOLS', tools.name)  //把我们点击的图形保存到vuex里
      if (tools.name === 'delete') {   //清空单独处理
        this.resetObj()                //重置的方法
        this.canvasObj.clear()         //清空画布
        this.canvasObj.renderAll()     //重新渲染
      } else if (tools.name === 'text') {   //文字也单独处理 因为在选择到文字的时候 有一个改变文字大小的range
        this.canvasObj.isDrawingMode = true
        this.drawing()
        this.choseItem = true      //文字大小range是否显示  是
      } else {
        this.drawing()            //调用drawing方法
        this.choseItem = false    //否
      }
}
之前存到vuex里的数据,现在我们要拿出来:
watch: {
    '$store.state.drawType': function () {
      this.currentTool = this.$store.state.drawType
    }
  }
接下来先看看resetObj方法:
resetObj () {
      this.canvasObj.isDrawingMode = false
      this.canvasObj.selectable = false
      this.canvasObj.selection = false
      this.canvasObj.skipTargetFind = true
    }

然后是drawing方法:(重点)------用到一个switch case

drawing () {
      if (this.drawingObject) {
        this.canvasObj.remove(this.drawingObject)
      }
      let canvasObject = null
      switch (this.currentTool) {
        case 'pencil':    //name为铅笔时
          this.resetObj()
          this.canvasObj.isDrawingMode = true
          this.canvasObj.freeDrawingBrush.color = this.strokeColor   //画笔颜色
          this.canvasObj.freeDrawingBrush.width = this.strokeWidths  //画笔宽度
          break
        case 'line':   //name为直线
          this.resetObj()
          canvasObject = new fabric.Line([this.mouseFrom.x, this.mouseFrom.y, this.mouseTo.x, this.mouseTo.y], {            //fabric.Line是fabric封装的方法 直接用就好了
            stroke: this.strokeColor,   //画笔颜色
            strokeWidth: this.strokeWidths   //画笔宽度
          })
          console.log(canvasObject)
          break
        case 'arrow':
          this.resetObj()          //isFill 是用来判断是否要填充颜色
          if (this.isFill === false) {
            this.fillColor = ''
          } else {
            this.fillColor = this.strokeInnerColor
          }
          canvasObject = new fabric.Path(this.drawArrow(this.mouseFrom.x, this.mouseFrom.y, this.mouseTo.x, this.mouseTo.y, 17.5, 17.5), {
            stroke: this.strokeColor,
            fill: this.fillColor,
            strokeWidth: this.strokeWidths
          })
          break
        case 'xuxian':
          this.resetObj()
          canvasObject = new fabric.Line([this.mouseFrom.x, this.mouseFrom.y, this.mouseTo.x, this.mouseTo.y], {
            strokeDashArray: [3, 3],  //[3,3]是每个3个像素,间隔3个像素  后面的参数是间隔数
            stroke: this.strokeColor,
            strokeWidth: this.strokeWidths
          })
          break
        case 'juxing':
          this.resetObj()
          if (this.isFill === false) {
            this.fillColor = ''
          } else {
            this.fillColor = this.strokeInnerColor
          }
          canvasObject = new fabric.Rect({
            left: this.mouseFrom.x,
            top: this.mouseFrom.y,
            width: this.mouseTo.x - this.mouseFrom.x,
            height: this.mouseTo.y - this.mouseFrom.y,
            stroke: this.strokeColor,
            fill: this.fillColor
          })
          console.log(canvasObject)
          break
        case 'circle':
          this.resetObj()
          if (this.isFill === false) {
            this.fillColor = ''
          } else {
            this.fillColor = this.strokeInnerColor
          }
          let radius = Math.sqrt((this.mouseTo.x - this.mouseFrom.x) * (this.mouseTo.x - this.mouseFrom.x) + (this.mouseTo.y - this.mouseFrom.y) * (this.mouseTo.y - this.mouseFrom.y)) / 2;
          //Math.sqrt 这个方法是返回平方根  计算圆的半径时用的是勾股定理          canvasObject = new fabric.Circle({
            left: this.mouseFrom.x,
            top: this.mouseFrom.y,
            radius: radius,   //圆的半径
            stroke: this.strokeColor,
            strokeWidth: this.strokeWidths,
            fill: this.fillColor
          })
          console.log(canvasObject)
          break
        case 'ellipse':   //椭圆
          this.resetObj()
          let left = this.mouseFrom.x
          let top = this.mouseFrom.y
          if (this.isFill === false) {
            this.fillColor = ''
          } else {
            this.fillColor = this.strokeInnerColor
          }
          let ellipse = Math.sqrt((this.mouseTo.x - left) * (this.mouseTo.x - left) + (this.mouseTo.y - top) * (this.mouseTo.y - top)) / 2
          canvasObject = new fabric.Ellipse({
            left: left,
            top: top,
            fill: this.fillColor,
            originX: 'center',    //从X轴中心点绘制
            originY: 'center',    //从Y轴中心点绘制
            rx: Math.abs(left - this.mouseTo.x),  //x轴半径
            ry: Math.abs(top - this.mouseTo.y),   //y轴半径   math.abs返回绝对值
            stroke: this.strokeColor,
            strokeWidth: this.strokeWidths
          })
          break
        case 'equilateral':
          this.resetObj()
          if (this.isFill === false) {
            this.fillColor = ''
          } else {
            this.fillColor = this.strokeInnerColor
          }
          let height = this.mouseTo.y - this.mouseFrom.y
          canvasObject = new fabric.Triangle({
            top: this.mouseFrom.y,
            left: this.mouseFrom.x,
            width: Math.sqrt(Math.pow(height, 2) + Math.pow(height / 2.0, 2)),
            height: height,
            stroke: this.strokeColor,
            strokeWidth: this.strokeWidths,
            fill: this.fillColor
          })
          break
        case 'text':
          this.resetObj()
          let textbox = new fabric.Textbox('', {
            left: this.mouseFrom.x,
            top: this.mouseFrom.y,
            width: 150,
            fontSize: this.fontSizes,
            fill: this.strokeColor,
            hasControls: false
          })
          this.canvasObj.add(textbox)
          textbox.enterEditing()
          console.log(textbox)
          console.log(this.canvasObj)
          break
        case 'draggle':   //移动
          this.canvasObj.isDrawingMode = false
          this.canvasObj.skipTargetFind = false
          this.canvasObj.selectable = true
          this.canvasObj.selection = true
          break
        case 'undo':     //撤回
          this.resetObj()
          if (this.canvasObj._objects.length > 0) {
            this.redo.push(this.canvasObj._objects.pop())
            this.canvasObj.renderAll()
          }
          break
        case 'redo':    //前进
          this.resetObj()
          if (this.redo.length > 0) {
            this.controlFlag = true
            this.canvasObj.add(this.redo.pop())
            this.canvasObj.renderAll()
          }
          break
        case 'eraser':  //橡皮擦功能还在研究中心0.0
          console.log('擦掉')
          this.resetObj()
          //this.canvasObj.clearRect(12, 12, 20, 20)
          //canvasObject = new fabric.clear()
          break
        default:
          break
      }
      if (canvasObject) {
        this.canvasObj.add(canvasObject)   //把要绘制的内容添加到画布中
        this.canvasObj.renderAll()
        this.drawingObject = canvasObject
      }
    },

这样你就可以在页面上绘制大多数图形了 其中有个橡皮擦功能还在研究中。。。

③设置背景图片:

正上方有个点击上传 用el-upload做的

fabric.Image.fromURL(imgUrl, (img) => {     //imgUrl接收路径和base64  这里你上传的照片 肯定是用base64  img是固定写法
        console.log(img)
        this.bgcW = img.width
        this.bgcH = img.height
        img.set({
          width: img.width,
          height: img.height
        })
        this.canvasObj.setBackgroundImage(img, this.canvasObj.renderAll.bind(this.canvasObj))
        this.canvasObj.renderAll()
      })

④至于在桌面上绘制图片,有的需求里没有 但我这里有 前面我们设置了sineNum=1 加载drawing这个方法 当sineName=2的时候 我们加载diy() 这个方法

点击这个图标的时候,弹出popover 这里面的图片是通过接口加载出来的  当点击里面的图片的时候 在点击画布 画布上就会加载刚刚我点击的图片

这个地方的实现跟设置背景图片差不多,代码如下:

diy () {
      if (this.drawingObject) {
        this.canvasObj.remove(this.drawingObject)
      }
      let canvasObject = null
      console.log(this.diyImage)
      this.resetObj()
      canvasObject = fabric.Image.fromURL(this.diyImage, (img) => {
        console.log(img)
        img.set({
          left: this.mouseFrom.x,
          top: this.mouseFrom.y,
          fill: ''
        })
        this.canvasObj.add(img)
      })
      if (canvasObject) {
        this.canvasObj.add(canvasObject)
        this.drawingObject = canvasObject
      }
    },

然后可以把当前画好的访问后台接口保存起来。因为我的项目里有一些其他功能,这里就不把全部代码贴出来了。

fabric一些常用的方法都在这儿了,如果有什么错误,还望指教,互相探讨。

================================分割线 2019/12/20========================================

箭头的实现方法:
/*箭头的方法*/drawArrow (fromX, fromY, toX, toY, theta, headlen) {  theta = typeof theta !== 'undefined' ? theta : 30  headlen = typeof theta !== 'undefined' ? headlen : 10  // 计算各角度和对应的P2,P3坐标  let angle = Math.atan2(fromY - toY, fromX - toX) * 180 / Math.PI,    angle1 = (angle + theta) * Math.PI / 180,    angle2 = (angle - theta) * Math.PI / 180,    topX = headlen * Math.cos(angle1),    topY = headlen * Math.sin(angle1),    botX = headlen * Math.cos(angle2),    botY = headlen * Math.sin(angle2)  let arrowX = fromX - topX,    arrowY = fromY - topY  let path = ' M ' + fromX + ' ' + fromY  path += ' L ' + toX + ' ' + toY  arrowX = toX + topX  arrowY = toY + topY  path += ' M ' + arrowX + ' ' + arrowY  path += ' L ' + toX + ' ' + toY  arrowX = toX + botX  arrowY = toY + botY  path += ' L ' + arrowX + ' ' + arrowY  return path}

Fabric.js的使用的更多相关文章

  1. HTML5 Canvas JavaScript库 Fabric.js 使用经验

    首先,表明我的态度:采用 Flash 才是最优方案,不建议使用 HTML 5 的 Canvas 做一些生产/工业级的网页应用. Flash的优势一是浏览器支持好,二是代码成熟稳定.而HTML5 的 C ...

  2. fabric.js和高级画板

    本文介绍fabric.js框架使用,以及使用fabricjs打造一个高级画板程序. 高级画板功能介绍 全局绘制颜色选择 护眼模式.网格模式切换 自由绘制 画箭头 画直线 画虚线 画圆/椭圆/矩形/直角 ...

  3. fabric.js 学习

    官网地址:http://fabricjs.com/    git     https://github.com/kangax/fabric.js/ <!DOCTYPE html> < ...

  4. Fabric.js canvas 图形库

    1.github地址: https://github.com/fabricjs/fabric.js 2.简述 Fabric.js将canvas的编程变得简单.同时在canvas上添加了交互.交互包括: ...

  5. fabric.js 知识点整理

    fabric.js是一个很好用的 canvas 操作插件,下面整理了一些平时项目中用到的知识点: //1: 获得画布上的所有对象: var items = canvas.getObjects(); / ...

  6. Canvas实用库Fabric.js使用手册

    简介什么是Fabric.js? Fabric.js是一个可以简化Canvas程序编写的库. Fabric.js为Canvas提供所缺少的对象模型, svg parser, 交互和一整套其他不可或缺的工 ...

  7. (转)第05节:Fabric.js的动画设置

    凡是出色的Canvas库都少不了制作动画的方法,Fabric.js也不例外,它有着编写简单且功能强大的动画助手,这就是animate( )方法. animate主要使用代码如下: rect.anima ...

  8. (转)第04节:Fabric.js用路径画不规则图形

    在Canvas上画方形.圆形.三角形都是很容易的,只要调用fabric对应的方法就可以了,但这些都是规则的图形,如果你想画一个不规则的图形,这时候你可以用fabric.js提供的路径绘图方法.所谓路径 ...

  9. (转)第01节:初识简单而且强大的Fabric.js库

    Fabric.js是一个功能强大和简单Javascript HTML5的canvas库.Fabric提供了很多可以互动的Canvas元素,还在canvas上提供了SVG的语法分析器. 你可以轻松的使用 ...

随机推荐

  1. 使用Makefile编译Erlang

    #配置选项,可以是DEBUG和RELEASE CONFIG ?= RELEASE #语言配置,可以是chs(简体中文).cht(繁体中文)等等 Region ?= chs #源文件目录 SOURCE_ ...

  2. 使用canvas时, 如何用相对单位(rem, rpx)来适配不同机型

    使用canvas的api时, 使用的都是绝对数值, 如: 方法传参是坐标位置,不带单位,如ctx.translate(10,10); 那么此时, 我就需要将rem或rpx 转换成 px; 首先, 获取 ...

  3. 数据结构---Java---String、StringBuilder、StringBuffer

    1.概述 1.1 String:不可变字符串 public final class String implements java.io.Serializable, Comparable<Stri ...

  4. 【leetcode】925.Long Pressed Name

    题目如下: Your friend is typing his name into a keyboard.  Sometimes, when typing a character c, the key ...

  5. PHP基础知识------页面静态化

    1.在开发项目时,有时会遇到一些页面数据量特别大,但是又不经常改变的情况,如商城首页等,这时候就需要进行页面静态化,减轻服务器和数据库的压力. 这里我们先用原生的PHP写一个简单的demo,用来理解页 ...

  6. Linux进程管理之ps的使用

    主题Linux进程管理之ps工具的使用 一ps工具的介绍 ps: process state  进程状态ps - report a snapshot of the current processesL ...

  7. CDN技术之--集群服务与负载均衡

    Web集群是由多个同时运行同一个web应用的服务器组成,在外界看来就像一个服务器一样,这多台服务器共同来为客户提供更高性能的服务.集群更标准的定义是:一组相互独立的服务器在网络中表现为单一的系统,并以 ...

  8. 团队冲刺DAY4

    DES算法 算法概要 在DES.java当中创立两个方法分别用作加密和解密 通过 `public static byte[] encrypt(byte[] data, String sKey) 创建方 ...

  9. Django基础篇(二)与mysql配合使用

    需求:模拟实现学员管理系统.<*_* 从基础做起> 表结构如下: 班级/学生/老师 班级表: id     title 1       xx 2 xx 学生表: id    name    ...

  10. 框架-.NET:ASP.NET MVC

    ylbtech-框架-.NET:ASP.NET MVC ASP.NET MVC 是Windows系统下面的Web研发框架,有Microsoft提供.MVC顾名思义:Model, View, Contr ...