圖形編輯器中JS實(shí)現(xiàn)防誤操作之拖拽阻塞
圖形編輯器中
在圖形編輯器中,想象這么一個(gè)場(chǎng)景,我們撤銷(xiāo)了一些重要的操作,然后想選中一個(gè)圖形,看看它的屬性。你點(diǎn)了上去,然后你發(fā)現(xiàn)你再也無(wú)法重做了。
你以為你點(diǎn)了一下,但其實(shí)你點(diǎn)擊的時(shí)候,鼠標(biāo)還是小小移動(dòng)了一點(diǎn),飄了一個(gè)像素點(diǎn)。對(duì)編輯器來(lái)說(shuō),它識(shí)別到讓圖形移動(dòng)一個(gè)像素點(diǎn)的操作,就生成了一個(gè)新的版本,然后重做棧(redoStack)被清空了,你退回前的操作就沒(méi)了。
為了解決這類(lèi)用戶(hù)微小操作的問(wèn)題,我們可以巧妙地給拖拽行為加一個(gè) 阻塞閾值。具體就是就是按下鼠標(biāo)后,移動(dòng)鼠標(biāo)的距離要大于某個(gè)值,我們才認(rèn)為發(fā)生了拖拽,并執(zhí)行對(duì)應(yīng)工具的邏輯。
下面為我們要實(shí)現(xiàn)的效果。此處為了更好地演示效果,將閾值設(shè)置得很大。通常設(shè)置個(gè) 4px 就夠了。

可以看到,按下鼠標(biāo)然后移動(dòng),如果移動(dòng)的位移太小,矩形是不會(huì)被移動(dòng)的,直到達(dá)到一定位移閾值后,矩形才會(huì)乖乖聽(tīng)話(huà)跟隨鼠標(biāo)進(jìn)行移動(dòng)。
閾值表示位移距離,使用的是視口坐標(biāo)系,而不是場(chǎng)景坐標(biāo)系。
代碼改造
原來(lái)的邏輯:
let isPressing = false;
let currentTool = null; // 當(dāng)前工具對(duì)象
// 鼠標(biāo)按下
function handleDown(e) {
isPressing = true;
currentTool.start(e);
}
// 鼠標(biāo)移動(dòng)
function handleMove(e) {
if (isPressing) {
currentTool.drag(e);
} else {
// 非拖拽的移動(dòng)事件
// 比如選擇工具停留在圖形上,圖形要高亮,此時(shí)沒(méi)發(fā)生拖拽
currentTool.move(e);
}
}
// 鼠標(biāo)釋放
function handleUp(e) {
currentTool.end(e);
isPressing = false;
}
鼠標(biāo)按下時(shí),isPressing 設(shè)置為 true,表示發(fā)生了鼠標(biāo)按下事件。
此時(shí)鼠標(biāo)再移動(dòng),我們就能知道這是一個(gè) “拖拽” 的行為,即按下鼠標(biāo)不放然后移動(dòng)鼠標(biāo)的行為。此時(shí)調(diào)用工具對(duì)象的 drag 方法。
最后鼠標(biāo)釋放,將狀態(tài) isPressing 重置。
現(xiàn)在我們進(jìn)行改造。
let isPressing = false;
let currentTool = null; // 當(dāng)前工具對(duì)象
let isEnableDragging = false; // 是否調(diào)用工具對(duì)象的 drag 方法
let startPos = null; // 保存鼠標(biāo)按下時(shí)的坐標(biāo)
const blockStep = 4; // 閾值
function handleDown(e) {
isPressing = true;
isEnableDragging = false;
startPos = { x: e.clientX, y: e.clientY };
currentTool.start(e);
}
function handleMove(e) {
// 判斷位移是否突破閾值,是的話(huà)更新?tīng)顟B(tài)為 “可拖拽”
if (
!isEnableDragging &&
(Math.abs(e.clientX - startPos.x) > blockStep ||
Math.abs(e.clientX - startPos.x) > blockStep)
) {
isEnableDragging = true;
}
if (isPressing) {
if (isEnableDragging) {
// “可拖拽” 狀態(tài),調(diào)用工具的 drag 方法
currentTool.drag(e);
}
} else {
currentTool.move(e);
}
}
function handleUp(e) {
currentTool.end(e);
// 初始化狀態(tài)
isPressing = false;
isEnableDragging = false;
startPos = null;
}
核心思路是引入 isEnableDragging 狀態(tài),表示鼠標(biāo)移動(dòng)時(shí),是否達(dá)到移動(dòng)的條件。
我們?cè)谑髽?biāo)移動(dòng)事件中,計(jì)算鼠標(biāo)按下和鼠標(biāo)移動(dòng)之間的距離是否超過(guò)某個(gè)值,如果超過(guò)閾值,就將 isEnableDragging 狀態(tài)轉(zhuǎn)換為 true。
然后判斷 isEnableDragging 為 true,就調(diào)用工具對(duì)象的 drag 方法。
需要注意的是,不要只用位移距離來(lái)判斷是否可以拖拽,要配合狀態(tài)。否則突破閾值后,又移動(dòng)回來(lái),你會(huì)發(fā)現(xiàn)你又卡住了,因?yàn)榇藭r(shí)閾值因?yàn)樵俅斡?jì)算,沒(méi)能達(dá)到閾值。
所以加了個(gè) isEnableDragging 狀態(tài),在第一次突破閾值設(shè)置為 true 后,就再也不用計(jì)算位移了,之后一直都是可拖拽狀態(tài),直到鼠標(biāo)釋放重置狀態(tài)。
結(jié)尾
拖拽阻塞是開(kāi)發(fā)圖形編輯器的一點(diǎn)小細(xì)節(jié),并不復(fù)雜,但能帶來(lái)很好的用戶(hù)體驗(yàn)。
以上就是圖形編輯器中JS實(shí)現(xiàn)防誤操作之拖拽阻塞的詳細(xì)內(nèi)容,更多關(guān)于JS 拖拽阻塞的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
JS實(shí)現(xiàn)的數(shù)組全排列輸出算法
這篇文章主要介紹了JS實(shí)現(xiàn)的數(shù)組全排列輸出算法,實(shí)例分析了全排列的原理與相關(guān)的javascript實(shí)現(xiàn)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-03-03
js仿蘋(píng)果iwatch外觀(guān)的計(jì)時(shí)器代碼分享
這篇文章主要介紹了JS+CSS3實(shí)現(xiàn)的類(lèi)似于蘋(píng)果iwatch計(jì)時(shí)器特效,很實(shí)用的代碼,推薦給大家,有需要的小伙伴可以參考下。2015-08-08
JavaScript高級(jí)程序設(shè)計(jì) 閱讀筆記(十二) js內(nèi)置對(duì)象Math
js內(nèi)置對(duì)象Math使用介紹, 需要的朋友可以參考下2012-08-08
JavaScript?進(jìn)階問(wèn)題列表(各種js代碼段108-155)
從基礎(chǔ)到進(jìn)階,測(cè)試你有多了解?JavaScript,刷新你的知識(shí),或者幫助你的?coding?面試!?:muscle:?:rocket:?我每周都會(huì)在這個(gè)倉(cāng)庫(kù)下更新新的問(wèn)題2024-11-11
一個(gè)簡(jiǎn)單的JS鼠標(biāo)懸停特效具體方法
這個(gè)特效最終實(shí)現(xiàn)效果就是當(dāng)鼠標(biāo)移動(dòng)到鏈接上,文字會(huì)橫向移動(dòng)一定距離,貌似總有人喜歡這些花花草草。添加此效果方法很簡(jiǎn)單。2013-06-06
原生js實(shí)現(xiàn)類(lèi)似fullpage的單頁(yè)/全屏滾動(dòng)
這篇文章主要介紹了利用原生js實(shí)現(xiàn)類(lèi)似fullpage的全屏滾動(dòng)的實(shí)現(xiàn)方法,文中給出了完整的實(shí)例代碼,相信對(duì)大家的理解和學(xué)習(xí)具有一定的參考價(jià)值,需要的朋友們可以參考借鑒,下面來(lái)一起看看吧。2017-01-01
JS構(gòu)造函數(shù)與原型prototype的區(qū)別介紹
下面小編就為大家?guī)?lái)一篇JS構(gòu)造函數(shù)與原型prototype的區(qū)別介紹。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-07-07

