前言
上周六有個群友@我說Gitee的反饋模塊新增了截圖功能,我就去體驗了下肤寝,發(fā)現(xiàn)他們用的就是我的插件??育苟,本文就跟大家分享下這個插件筹裕,歡迎各位感興趣的開發(fā)者閱讀本文醋闭。
插件地址與實(shí)現(xiàn)原理
本插件采用原生js實(shí)現(xiàn),可以集成在任意一個web項目中朝卒,插件npm地址與GitHub地址請移步:
插件的實(shí)現(xiàn)原理請移步:
在線體驗本插件证逻,可移步我的開源項目chat-system進(jìn)行體驗,插件的運(yùn)行效果視頻請移步實(shí)現(xiàn)web端自定義截屏功能-效果視頻抗斤。
Gitee產(chǎn)品經(jīng)理的青睞
月初的時候囚企,Gitee的產(chǎn)品經(jīng)理在掘金看到我的截圖插件js-screen-shot覺得還不錯,他們最近在做這方面的功能豪治,就打算將我的插件直接集成進(jìn)去洞拨,跟我溝通了下版權(quán)相關(guān)的事情。
溝通完成后负拟,他問我要不要把插件在Gitee也放一份,可以幫我推薦下歹河,我毫不猶豫的抱住了大腿掩浙,就把插件搬過去了,得到一波首頁推薦??
Gitee的反饋模塊需要登錄后秸歧,點(diǎn)頁面右側(cè)的發(fā)送反饋圖標(biāo)厨姚。
影響體驗的一些小問題
上周二,從GitHub來了個網(wǎng)友键菱,加了我微信谬墙,給我的插件提了兩個issues,因為周內(nèi)沒時間處理這些問題经备,就計劃周末統(tǒng)一處理下插件的issues拭抬。
整理有效的issues
時間回到上周六早上,我打開GitHub瞅了一眼issues侵蒙,許久不看居然已經(jīng)有19條了造虎。
經(jīng)過一番整理,去掉一些無用的和已經(jīng)修改好了的纷闺,最終確定了4條:
- 調(diào)用者可以在框選區(qū)域外繪制問題
- 截圖區(qū)域工具欄首次點(diǎn)擊時刪除裁剪框的8個可操作點(diǎn)
- 修復(fù)框選完成后算凿,鼠標(biāo)點(diǎn)擊其他位置截圖工具欄跟著移動問題
- 添加可選參數(shù)支持單擊截全屏功能
解決issues
問題整理完成,接下來就是解決問題環(huán)節(jié)了犁功。
選區(qū)外繪制問題
正常情況下氓轰,截圖區(qū)域確立后,用戶都會在裁剪框區(qū)域內(nèi)進(jìn)行繪制浸卦,所以我就沒考慮這個邊界情況??署鸡,插件用的人多了后,自然就有人發(fā)現(xiàn)了這個問題,我們拿gitee的反饋模塊舉例(gitee目前用的還是我的舊版插件储玫,肯定存在這個問題)侍筛,如下所示,我們繪制的4個紅色方框都超出裁剪框了:
實(shí)現(xiàn)思路
這個問題解決起來比較簡單撒穷,裁剪框已經(jīng)繪制好了匣椰,知道它的坐標(biāo)信息,我們在進(jìn)行繪制時端礼,只需要判斷當(dāng)前鼠標(biāo)位置是否超出裁剪框的坐標(biāo)點(diǎn)區(qū)域即可禽笑。部分實(shí)現(xiàn)代碼如下所示:
// 獲取裁剪框位置信息
const cutBoxPosition = this.data.getCutOutBoxPosition();
// 繪制中工具的起始x、y坐標(biāo)不能小于裁剪框的起始坐標(biāo)
// 繪制中工具的起始x蛤奥、y坐標(biāo)不能大于裁剪框的結(jié)束坐標(biāo)
// 當(dāng)前鼠標(biāo)的x坐標(biāo)不能小于裁剪框起始x坐標(biāo)佳镜,不能大于裁剪框的結(jié)束坐標(biāo)
// 當(dāng)前鼠標(biāo)的y坐標(biāo)不能小于裁剪框起始y坐標(biāo),不能大于裁剪框的結(jié)束坐標(biāo)
if (
!getDrawBoundaryStatus(startX, startY, cutBoxPosition) ||
!getDrawBoundaryStatus(currentX, currentY, cutBoxPosition)
)
return;
getDrawBoundaryStatus
函數(shù)實(shí)現(xiàn)如下所示:
/**
* 獲取工具欄工具邊界繪制狀態(tài)
* @param startX x軸繪制起點(diǎn)
* @param startY y軸繪制起點(diǎn)
* @param cutBoxPosition 裁剪框位置信息
*/
export function getDrawBoundaryStatus(
startX: number,
startY: number,
cutBoxPosition: positionInfoType
): boolean {
if (
startX < cutBoxPosition.startX ||
startY < cutBoxPosition.startY ||
startX > cutBoxPosition.startX + cutBoxPosition.width ||
startY > cutBoxPosition.startY + cutBoxPosition.height
) {
// 無法繪制
return false;
}
// 可以繪制
return true;
}
具體代碼請移步提交記錄: fix: 修復(fù)插件調(diào)用者可以在框選區(qū)域外繪制問題
實(shí)現(xiàn)效果
實(shí)現(xiàn)后的效果如下所示:
工具欄跟隨鼠標(biāo)移動問題
這個問題可以描述為:裁剪框確定后凡桥,工具欄尚未點(diǎn)擊蟀伸,此時鼠標(biāo)點(diǎn)其他位置,截圖工具欄就跟著鼠標(biāo)重新計算了位置缅刽,我們繼續(xù)用Gitee來舉例啊掏,如下所示:
實(shí)現(xiàn)思路
當(dāng)鼠標(biāo)左鍵抬起時,如果工具欄尚未被點(diǎn)擊衰猛,則會根據(jù)當(dāng)前鼠標(biāo)的位置結(jié)合裁剪框的大小確立截圖工具欄的位置迟蜜。用戶只是單純的點(diǎn)擊了裁剪框區(qū)域的任意位置,工具欄就跟著移動了啡省。
解決這個問題也很簡單娜睛,我們只需要在鼠標(biāo)移動時添加一個標(biāo)識,鼠標(biāo)抬起時判斷這個標(biāo)識是否為true即可卦睹。部分代碼如下所示:
// 鼠標(biāo)拖動狀態(tài)
private dragFlag = false;
// 鼠標(biāo)移動事件
private mouseMoveEvent = (event: MouseEvent) => {
// 工具欄未選擇且鼠標(biāo)處于按下狀態(tài)時
if (!this.data.getToolClickStatus() && this.data.getDragging()) {
// 修改拖動狀態(tài)為true;
this.dragFlag = true;
}
}
// 鼠標(biāo)抬起事件
private mouseUpEvent = () => {
// 鼠標(biāo)尚未拖動且工具欄未選擇則不修改工具欄位置
if (!this.dragFlag && !this.data.getToolClickStatus()) {
// 復(fù)原裁剪框的坐標(biāo)
this.drawGraphPosition.startX = this.drawGraphPrevX;
this.drawGraphPosition.startY = this.drawGraphPrevY;
// 顯示截圖工具欄
this.data.setToolStatus(true);
return;
}
}
具體代碼請移步提交記錄:fix: 修復(fù)框選完成后畦戒,鼠標(biāo)點(diǎn)擊其他位置截圖工具欄跟著移動問題
實(shí)現(xiàn)結(jié)果
修復(fù)后的效果如下所示:
刪除8個可操作點(diǎn)
去年截圖插件剛寫好時,我就發(fā)現(xiàn)這個問題了分预,當(dāng)截圖工具欄點(diǎn)擊后裁剪框就不允許更改了兢交,如果8個可操作點(diǎn)依然存在的話,看起來很奇怪笼痹,當(dāng)時想到的思路是直接刪除邊框的8點(diǎn)配喳,但是這8個點(diǎn)都是繪制上去的,折騰了挺久沒找到方案就擱置了凳干,這個問題如下圖所示:
實(shí)現(xiàn)思路
一年后的今天晴裹,我知道刪除那8個點(diǎn)的思路肯定行不通,我就一遍又一遍的體驗QQ的截圖救赐,觀察他是怎么做的涧团,突然只磷,我靈感驚現(xiàn)??,我既然有裁剪框的坐標(biāo)和大小信息泌绣,我重新繪制一下這個裁剪框不就好了??钮追,裁剪框四周的8個可操作點(diǎn)刪除后,我就可以刪掉生成圖片時優(yōu)化那8個點(diǎn)的計算邏輯阿迈,導(dǎo)致范圍不精確問題元媚,從而實(shí)現(xiàn)完美截圖。部分實(shí)現(xiàn)代碼如下所示:
// 工具欄尚未點(diǎn)擊苗沧,當(dāng)前屬于首次點(diǎn)擊刊棕,重新繪制一個無像素點(diǎn)的裁剪框
if (!data.getToolClickStatus()) {
// 獲取裁剪框位置信息
const cutBoxPosition = data.getCutOutBoxPosition();
// 開始繪制無像素點(diǎn)裁剪框
drawCutOutBox(
cutBoxPosition.startX,
cutBoxPosition.startY,
cutBoxPosition.width,
cutBoxPosition.height,
screenShortCanvas,
data.getBorderSize(),
screenShortController as HTMLCanvasElement,
ScreenShortImageController,
false
);
}
具體代碼請移步提交記錄:fix: 截圖區(qū)域工具欄首次點(diǎn)擊時刪除裁剪框的8個可操作點(diǎn)
實(shí)現(xiàn)效果
實(shí)現(xiàn)單擊截全屏功能
給我提issues的那個網(wǎng)友希望截圖插件加載完畢后,用戶不拖拽生成選框待逞,直接鼠標(biāo)左鍵單擊就能截取整個屏幕甥角,我覺得這個需求需要的人不多,就將其做成了可選參數(shù)识樱。
實(shí)現(xiàn)思路
這個也很簡單嗤无,鼠標(biāo)抬起時,如果開啟了單擊截全屏牺荠,則從坐標(biāo)(0翁巍,0)位置繪制一個與畫布同等大小的裁剪框即可,部分代碼如下所示:
// 鼠標(biāo)抬起事件
private mouseUpEvent = () => {
if (
cutBoxPosition.width === 0 &&
cutBoxPosition.height === 0 &&
cutBoxPosition.startX === 0 &&
cutBoxPosition.startY === 0 &&
!this.dragFlag &&
this.clickCutFullScreen
) {
// 設(shè)置裁剪框位置為全屏
this.tempGraphPosition = drawCutOutBox(
0,
0,
this.screenShortImageController.width,
this.screenShortImageController.height,
this.screenShortCanvas,
this.data.getBorderSize(),
this.screenShortController,
this.screenShortImageController
) as drawCutOutBoxReturnType;
}
}
具體代碼請移步提交記錄:feat: 添加可選參數(shù)支持單擊截全屏功能
寫在最后
至此休雌,文章就分享完畢了。
我是神奇的程序員肝断,一位前端開發(fā)工程師杈曲。
如果你對我感興趣,請移步我的個人網(wǎng)站胸懈,進(jìn)一步了解担扑。
- 文中如有錯誤,歡迎在評論區(qū)指正趣钱,如果這篇文章幫到了你涌献,歡迎點(diǎn)贊和關(guān)注??
- 本文首發(fā)于神奇的程序員公眾號,未經(jīng)許可禁止轉(zhuǎn)載??