Fabric.js 拖拽平移畫布方法示例
正文
使用 fabric.js 創(chuàng)建出來的畫布默認(rèn)是不能拖拽移動的。
不過我們可以利用一些小技巧讓畫布具有被拖拽的能力,fabric.js 官網(wǎng)也提供了一個 demo ,但文檔上并沒有詳細(xì)的講解拖拽畫布的實(shí)現(xiàn)原理。
本文就粗略分析一下這個原理。

原理解析
鼠標(biāo)拖拽的原理其實(shí)很簡單,主要就3步:
- 鼠標(biāo)點(diǎn)擊元素
- 移動鼠標(biāo)
- 松開鼠標(biāo)
在鼠標(biāo)移動時,獲取鼠標(biāo)當(dāng)前位置,然后修改被拖拽元素的位置。
當(dāng)松開鼠標(biāo)時,也要獲取松手那刻鼠標(biāo)所在位置,然后設(shè)置元素的位置。
先看看官方給出的例子再逐步分析

<canvas id="c" width="500" height="500" style="border: 1px solid #ccc;"></canvas>
<script src="../js/fabric.js"></script>
<script>
// 創(chuàng)建畫布
let canvas = new fabric.Canvas('c', {
allowTouchScrolling: true
})
// 矩形
const rect = new fabric.Rect({
width: 100,
height: 100,
left: 10,
top: 10,
fill: 'pink'
})
// 三角形
const triangle = new fabric.Triangle({
top: 100,
left: 100,
width: 80, // 底邊長度
height: 100, // 底邊到對角的距離
fill: 'blue'
})
// 將矩形和三角形添加到畫布中
canvas.add(rect, triangle)
// 按下鼠標(biāo)事件
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
}
})
// 移動鼠標(biāo)事件
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
}
})
// 松開鼠標(biāo)事件
canvas.on('mouse:up', function (opt) {
this.setViewportTransform(this.viewportTransform)
this.isDragging = false
})
</script>
拖拽畫布的代碼來自官方案例。我刪減了部分元素。
從上面的代碼可以看出,主要事件是 mouse:down、mouse:move、mouse:up。
按下鼠標(biāo)時
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
}
})
通過 mouse:down 事件,設(shè)置了按住 alt 鍵時再按下鼠標(biāo)左鍵,才能觸發(fā)拖拽事件(開始)。
自定義3個屬性:
isDragging: 拖拽狀態(tài),true表示可拖拽lastPosX: 畫布上一個x坐標(biāo)lastPosY: 畫布上一個y坐標(biāo)
為什么要記錄 lastPosX 和 lastPosY 呢?
把鼠標(biāo)點(diǎn)擊時,鼠標(biāo)所在的位置記錄下來。之后移動時,再通過鼠標(biāo)新出現(xiàn)的位置和點(diǎn)擊時的位置對比,就能計(jì)算出鼠標(biāo)移動了多少距離,然后再調(diào)整畫布移動的距離即可。
移動鼠標(biāo)時
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
}
})
通過 mouse:move 可以監(jiān)聽鼠標(biāo)的移動。
此時就要通過 isDragging 判斷是否進(jìn)入拖拽狀態(tài)。
viewportTransform 是 fabric.js 在畫布上的一個屬性。
官方文檔是這樣介紹的:
The transformation (a Canvas 2D API transform matrix) which focuses the viewport
上面的代碼,修改了 viewportTransform 下標(biāo)為 4 和 5 的元素。
viewportTransform[4]: 水平位移(x軸)viewportTransform[5]: 垂直位移(y軸)
e.clientX - this.lastPosX 就是鼠標(biāo)移動的x軸方向的距離,e.clientY - this.lastPosY 可以計(jì)算出鼠標(biāo)移動的y軸方向的距離。
如果想了解 viewportTransform 每個元素代表什么,可以看看 《Fabric.js 變換視窗》
requestRenderAll() 是在每次移動完畫布就刷新一下。
刷新完畫布,就把上一個點(diǎn)(x和y坐標(biāo))改成最新的:this.lastPosX = e.clientX 和 this.lastPosY = e.clientY ,給下次移動鼠標(biāo)時提供一個參考值,方便計(jì)算。
松開鼠標(biāo)時
canvas.on('mouse:up', function (opt) {
this.setViewportTransform(this.viewportTransform)
this.isDragging = false
})
使用 setViewportTransform 設(shè)置畫布的視圖。
并退出拖拽模式:isDragging = false 。
以上就是在 fabric.js 中拖拽畫布的方法。
代碼倉庫
以上就是Fabric.js 拖拽平移畫布方法示例的詳細(xì)內(nèi)容,更多關(guān)于Fabric.js 拖拽平移畫布的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
javascript實(shí)現(xiàn)字典Dictionary示例基礎(chǔ)
這篇文章主要為大家介紹了javascript實(shí)現(xiàn)字典Dictionary基礎(chǔ)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-08-08
微信小程序?qū)崿F(xiàn)給循環(huán)列表添加點(diǎn)擊樣式實(shí)例
這篇文章主要介紹了微信小程序?qū)崿F(xiàn)給循環(huán)列表添加點(diǎn)擊樣式實(shí)例的相關(guān)資料,需要的朋友可以參考下2017-04-04
JavaScript的function函數(shù)詳細(xì)介紹
這篇文章主要介紹了JavaScript的function函數(shù)詳細(xì),而我們的JavaScript腳本語言比較特殊,相對于C語言,它的參數(shù)是不需要數(shù)據(jù)類型加持的。返回值return,我就不過多描述,他是和 C語言通的,如果沒寫他就會自動返回undefined,下面一起來看看文章內(nèi)容,需要的朋友可以參考一下2021-11-11
微信小程序 scroll-view組件實(shí)現(xiàn)列表頁實(shí)例代碼
這篇文章主要介紹了微信小程序 scroll-view組件實(shí)現(xiàn)列表頁實(shí)例代碼的相關(guān)資料,scroll-view組件介紹scroll-view是微信小程序提供的可滾動視圖組件,其主要作用是可以用來做手機(jī)端經(jīng)常會看到的上拉加載 ,需要的朋友可以參考下2016-12-12
JavaScript執(zhí)行機(jī)制詳細(xì)介紹
這篇文章主要介紹了JavaScript執(zhí)行機(jī)制,想要搞懂JavaScript執(zhí)行機(jī)制,便與進(jìn)程與線程的概念脫不了干系,下面我們就來看看這JavaScript執(zhí)行機(jī)制的具體介紹吧,需要的朋友可以參考一下2021-12-12
Svelte嵌套組件preventDefault構(gòu)建Web應(yīng)用
這篇文章主要介紹了Svelte嵌套組件preventDefault構(gòu)建Web應(yīng)用,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12
讓chatGPT教你如何使用taro創(chuàng)建mbox
這篇文章主要為大家介紹了讓chatGPT教你如何使用taro創(chuàng)建mbox實(shí)現(xiàn)實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03

