Fabric.js 画布基础功能

原文出处:Fabric.js 从入门到________

Fabric.js 简介

Fabric.js 是一个功能强大且操作简单的 Javascript HTML5 canvas 工具库。

如果你需要用 canvas 做特效,那我推荐你使用 Fabric.js ,因为 Fabric.js 语法更加简单易用,而且还提供了很多交互类的 api

Fabric.js 简化了很多 Canvas 里的概念,代码看上去也更加语义化。

Fabric.js 能做什么?

可以打开 『Fabric.js 官网首页』 直接看例子,也可以看看 『Fabric.js Demos』 查看更炫酷的例子。





本文简介

本文主要讲解 Fabric 提供的基础 画布 操作,包含一下内容

  • 安装 Fabric.js
  • 画布基础版(可交互)
  • 不可交互的画布
  • js 设置画布参数
  • 使用背景图
  • 旋转背景图
  • 拉伸背景图
  • 重复背景图
  • 重叠影像

本文在案例在 Vue3 环境下使用,不懂 Vue3 也没关系,因为不会涉及多少 Vue 的知识。





相关链接

原文出处:Fabric.js 从入门到________

『Fabric.js npm地址』

『Fabric.js github地址』

🎁本文案例在线预览

🎁本文所有案例仓库地址 【欢迎Star,不定期更新!!!】





动手!

安装 Fabric.js

CDN

<script src="https://unpkg.com/fabric@4.6.0/dist/fabric.min.js"></script>


npm

npm i fabric --save



基础版(可交互)

基础版就是“起步”章节所说的那个例子。

<template>
  <canvas width="400" height="400" id="canvas" style="border: 1px solid #ccc;"></canvas>
</template>

<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric' // 引入 fabric

function init() {
  const canvas = new fabric.Canvas('canvas') // 这里传入的是canvas元素的id

  // 创建一个长方形
  const rect = new fabric.Rect({
    top: 100, // 距离容器顶部 100px
    left: 100, // 距离容器左侧 100px
    width: 30, // 矩形宽度 30px
    height: 30, // 矩形高度 30px
    fill: 'red' // 填充 红色
  })

  canvas.add(rect) // 将矩形添加到 canvas 画布里
}

onMounted(() => {
  init()
})
</script>



不可交互

<template>
  <canvas width="400" height="400" id="canvas" style="border: 1px solid #ccc;"></canvas>
</template>

<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric' // 引入 fabric

function init() {
  // 使用 StaticCanvas 创建一个不可操作的画布
  const canvas = new fabric.StaticCanvas('canvas') // 这里传入的是canvas元素的id

  // 创建一个长方形
  const rect = new fabric.Rect({
    top: 100, // 距离容器顶部 100px
    left: 100, // 距离容器左侧 100px
    width: 30, // 矩形宽度 30px
    height: 30, // 矩形高度 30px
    fill: 'red' // 填充 红色
  })

  canvas.add(rect) // 将矩形添加到 canvas 画布里
}

onMounted(() => {
  init()
})
</script>

创建不可交互的画布,其实只需把 new fabric.Canvas 改成 new fabric.StaticCanvas 即可。



在js设定画布参数

<template>
  <canvas id="canvas"></canvas>
</template>

<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric' // 引入 fabric

function init() {
  const canvas = new fabric.Canvas('canvas', {
    width: 300, // 画布宽度
    height: 300, // 画布高度
    backgroundColor: '#eee' // 画布背景色
  })

  // 圆形
  const circle = new fabric.Circle({
    radius: 30, // 圆的半径
    top: 20, // 距离容器顶部 20px
    left: 20, // 距离容器左侧 20px
    fill: 'pink' // 填充 粉色
  })
  
  canvas.add(circle) // 将圆形添加到 canvas 画布里
}

onMounted(() => {
  init()
})
</script>

new fabric.Canvas 的第二个参数是用来设置画布基础功能的。更多配置参数可以查看 『官方文档』



使用背景图

<template>
  <canvas width="400" height="400" id="canvas" style="border: 1px solid #ccc;"></canvas>
</template>

<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'

function init() {
  const canvas = new fabric.Canvas('canvas')

  // 设置背景图
  // 参数1:背景图资源(可以引入本地,也可以使用网络图)
  // 参数2:设置完背景图执行以下重新渲染canvas的操作,这样背景图就会展示出来了
  canvas.setBackgroundImage(
    'https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/27d1b4e5f8824198b6d51a2b1c2d0d75~tplv-k3u1fbpfcp-zoom-crop-mark:400:400:400:400.awebp',
    canvas.renderAll.bind(canvas)
  )
}

onMounted(() => {
  init()
})
</script>

setBackgroundImage 这个很好懂,设置背景图片。

需要注意的是,在 Fabric.js 里使用 gif 只会渲染第一帧。



旋转背景图

<template>
  <canvas width="400" height="400" id="canvas" style="border: 1px solid #ccc;"></canvas>
</template>

<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'

function init() {
  const canvas = new fabric.Canvas('canvas')

  // 设置背景图
  // 参数1:背景图资源(可以引入本地,也可以使用网络图)
  // 参数2:设置完背景图执行以下重新渲染canvas的操作,这样背景图就会展示出来了
  canvas.setBackgroundImage(
    'https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/27d1b4e5f8824198b6d51a2b1c2d0d75~tplv-k3u1fbpfcp-zoom-crop-mark:400:400:400:400.awebp',
    canvas.renderAll.bind(canvas),
    {
      angle: 15 // 旋转背景图
    }
  )
}

onMounted(() => {
  init()
})
</script>

setBackgroundImage 还有第三个参数,嘿嘿嘿没想到吧

第三个参数除了旋转,还可以设置 scaleXscaleY 之类的操作。

更多设置可以查看 『文档』

但这个例子存在一个问题,如果图片的尺寸没 canvas 容器大,就填不满,否则就溢出(只显示图片的局部)。

解决方案请看下一个案例。



拉伸背景图

<template>
  <canvas width="400" height="400" id="canvas" style="border: 1px solid #ccc;"></canvas>
</template>

<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'

function init() {
  const canvas = new fabric.Canvas('canvas')

  // fabric.Image.fromURL:加载图片的api
  // 第一个参数:图片地址(可以是本地的,也可以是网络图)
  // 第二个参数:图片加载的回调函数
  fabric.Image.fromURL(
    'https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/27d1b4e5f8824198b6d51a2b1c2d0d75~tplv-k3u1fbpfcp-zoom-crop-mark:400:400:400:400.awebp',
    (img) => {
      // 设置背景图
      canvas.setBackgroundImage(
        img,
        canvas.renderAll.bind(canvas),
        {
          scaleX: canvas.width / img.width, // 计算出图片要拉伸的宽度
          scaleY: canvas.height / img.height // 计算出图片要拉伸的高度
        }
      )
    }
  )
}

onMounted(() => {
  init()
})
</script>

这个例子使用了 fabric.Image.fromURL 这个 api 来加载图片,第一个参数是图片地址,第二个参数是回调函数。

拿到图片的参数和画布的宽高进行计算,从而使图片充满全屏。



重复背景图

<template>
  <canvas width="400" height="400" id="canvas" style="border: 1px solid #ccc;"></canvas>
</template>

<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'

function init() {
  const canvas = new fabric.Canvas('canvas')

  canvas.setBackgroundColor({
    source: 'https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/27d1b4e5f8824198b6d51a2b1c2d0d75~tplv-k3u1fbpfcp-zoom-crop-mark:40:40:40:40.awebp',
    repeat: 'repeat'
  }, canvas.renderAll.bind(canvas))
}

onMounted(() => {
  init()
})
</script>

这个例子使用的图片尺寸是比较小的,所以在 setBackgroundColor 的第3个参数中设置了 repeat: 'repeat' ,表示重复渲染图片。



重叠影象

<template>
  <canvas width="400" height="375" id="canvas" style="border: 1px solid #ccc;"></canvas>
</template>

<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
import jailCellBars from '@/assets/images/jail_cell_bars.png' // 引入背景图

function init() {
  const canvas = new fabric.Canvas('canvas')

  canvas.add(
    new fabric.Circle({
      radius: 30, // 圆形半径
      fill: '#f55',
      top: 70,
      left: 70
    })
  )

  // 设置覆盖图像的画布
  canvas.setOverlayImage( // setOverlayImage(image, callback, optionsopt)
    jailCellBars, // 图片,script开头import进来的
    canvas.renderAll.bind(canvas)
  )
}

onMounted(() => {
  init()
})
</script>

值得注意的2点:

  1. 使用 canvas.setOverlayImage 代替原本的 canvas.setBackgroundImage
  2. 所使用的图片最好是带透明层的 png ,这样就能展示案例所示的效果,背景图叠在图案元素上面。

🎁 本例所使用的图片地址





更多推荐

Fabric.js 从入门到__

Fabric.js渐变(Gradient)效果,包括径向渐变radial

console.log也能插图!!!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,254评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,875评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,682评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,896评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,015评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,152评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,208评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,962评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,388评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,700评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,867评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,551评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,186评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,901评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,142评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,689评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,757评论 2 351

推荐阅读更多精彩内容