【JS】928- 用 Canvas 編輯你的圖片

寫在前面
最近接到一個(gè)需求:線下質(zhì)檢時(shí)根據(jù)上傳的圖片和實(shí)物進(jìn)行對(duì)比檢測(cè),需要在圖片上的動(dòng)態(tài)標(biāo)記出有瑕疵或污點(diǎn)等位置,便于后續(xù)流程檢測(cè)和記錄。
想到了之前用過的
canvas可以實(shí)現(xiàn)這個(gè)功能,話不多說,讓我們一起認(rèn)識(shí)一下canvas。
canvas 自我介紹
大家好,我是 canvas ,我能讓大家通過 canvas 標(biāo)簽,用JavaScript來繪制圖形。除此之外,動(dòng)畫,游戲圖形,數(shù)據(jù)可視化,照片處理和實(shí)時(shí)視頻處理都難不倒我噢~
一、我的兼容性(心有多大,舞臺(tái)就有多大)
大家使用前端技術(shù)前可以在Can I Use上查詢一下兼容性噢~ 我就在里面找到了自己呢:

二、我能做什么**(能力越大,責(zé)任越大)
我來告訴大家我是怎么工作的,從簡(jiǎn)單的開始噢(hello world~)
1、拿起紙和筆
// .html
<canvas id="tutorial" width="150" height="150"></canvas>
// .js
const canvas = document.getElementById('tutorial');
// ctx就是我的紙了
const ctx = canvas.getContext('2d');
// 準(zhǔn)備一下我的筆(就拿個(gè)紅色吧~)
ctx.strokeStyle = 'red';
// 填充顏色
ctx.fillStyle = 'red';
2、基本用法
我自己總結(jié)了一些方法,大家用起來就快多了
畫線

ctx.beginPath();
ctx.lineWidth="5";
ctx.strokeStyle="red"; // 紅色路徑
ctx.moveTo(0,75);
ctx.lineTo(250,75);
ctx.stroke(); // 進(jìn)行繪制
ctx.beginPath();
ctx.strokeStyle="blue"; // 藍(lán)色路徑
ctx.moveTo(50,0);
ctx.lineTo(150,130);
ctx.stroke(); // 進(jìn)行繪制
畫個(gè)圈圈

ctx.beginPath();
// ctx.arc(x,y,r,sAngle,eAngle,counterclockwise);
// x: 圓的中心的 x 坐標(biāo)。
// y: 圓的中心的 y 坐標(biāo)。
// r: 圓的半徑。
// sAngle: 起始角,以弧度計(jì)。(弧的圓形的三點(diǎn)鐘位置是 0 度)。
// eAngle: 結(jié)束角,以弧度計(jì)。
// counterclockwise: 可選。規(guī)定應(yīng)該逆時(shí)針還是順時(shí)針繪圖。False = 順時(shí)針,true = 逆時(shí)針。
ctx.arc(100,75,50,0,2*Math.PI);
ctx.stroke();
畫個(gè)框框

arc
// x: 矩形左上角的 x 坐標(biāo)
// y: 矩形左上角的 y 坐標(biāo)
// width: 矩形的寬度,以像素計(jì)
// height: 矩形的高度,以像素計(jì)
// 填充矩形
ctx.fillRect(x: 20, y: 20, width: 150, height: 100);
// 無填充矩形
ctx.strokeRect(20,20,150,100);
好啦,以上是我的基本技能,有興趣的話可以在MDN WEB上查看我的全部技能噢~
回歸到需求上,我們開發(fā)者應(yīng)該如何使用 canvas 完成需求功能呢?
實(shí)踐
結(jié)合 canvas 技能,方案設(shè)計(jì)思路如下:
獲取適配的圖片 轉(zhuǎn)換圖片:按照?qǐng)D片 1:1 繪制畫布 動(dòng)態(tài)編輯:在畫布上標(biāo)記操作,可進(jìn)行增刪改 生成圖片:畫布轉(zhuǎn)換為圖片
1、獲取并轉(zhuǎn)換圖片 drawImage
<img
style={{ width: 100px, height: 100px }}
src="https://test.jpg"
onLoad={onLoad}
/>
<canvas></canvas>
function onLoad() {
// 設(shè)置canvas為圖片大小
canvas.height = img.height;
canvas.width = img.width;
// 繪制圖片 (0,0)開始1:1繪制img
// ctx.drawImage(img,x,y,width,height);
ctx.drawImage(img, 0, 0, img.width, img.height);
}
2、編輯功能 (此處主要實(shí)現(xiàn)框選功能)
canvas.addEventListener("mousedown", onMouseDown);
canvas.addEventListener("mousemove", onMouseMove);
function getPointOnCanvas() {
// canvas相對(duì)于視窗的位置集合
const rect = canvas.getBoundingClientRect();
return {
x: x - rect.left * (canvas.width / rect.width),
y: y - rect.top * (canvas.height / rect.height)
}
}
function onMouseDown(event) {
var x = event.pageX;
var y = event.pageY;
// 獲取起點(diǎn)
startPoint = getPointOnCanvas(canvas, x, y);
ctx.beginPath();
ctx.moveTo(startPoint.x, startPoint.y);
}
function getRectParam(curPoint) => {
const _w = curPoint.x - startPoint.x;
const _h = curPoint.y - startPoint.y;
const _startPoint = _w < 0 || _h < 0 ? curPoint : startPoint;
return {
_startPoint,
_w,
_h
};
};
function drawRect() {
// 獲取繪制矩形需要的參數(shù)
const newRect = getRectParam(curPoint)
// 繪制矩形
ctx.beginPath();
ctx.rect(
newRect._startPoint.x,
newRect._startPoint.y,
Math.abs(newRect._w),
Math.abs(newRect._h)
);
ctx.stroke();
}
function mousemove(event) {
const x = event.pageX;
const y = event.pageY;
// 獲取
const curPoint = getPointOnCanvas(canvas, x, y);
drawRect();
};
3、canvas 轉(zhuǎn)圖片
const dataURL = canvas.toDataURL('image/png')
以上是部分代碼,來看看編輯效果:

目前需求已順利上線,質(zhì)檢師的使用反饋很不錯(cuò)。
寫在后面
希望通過本文給大家?guī)硪环N前端處理圖片的思路,有興趣的同學(xué)可以嘗試一下 canvas 的其他功能,如:添加文字,編輯的撤回等等。
接下來,會(huì)陸續(xù)推出三無項(xiàng)目重構(gòu)的踩坑之旅、跨應(yīng)用的拖拽能力實(shí)踐等。每天進(jìn)步一點(diǎn)點(diǎn),質(zhì)變從關(guān)注 大轉(zhuǎn)轉(zhuǎn) FE 開始!

回復(fù)“加群”與大佬們一起交流學(xué)習(xí)~
點(diǎn)擊“閱讀原文”查看 120+ 篇原創(chuàng)文章
