開場白
雖然在實際的開發中我們很少去繪製流程圖
就算需要,我們也會透過第3方外掛去實現
下面我們來簡單實現流程圖中很小的一部分
手動繪製矩形
繪製一個矩形的思路
我們這裡繪製矩形
會使用到canvas.strokeRect(x,y, w, h)方法繪製一個描邊矩形
x:矩形起點的 x 軸座標。
y:矩形起點的 y 軸座標。
width:矩形的寬度。正值在右邊,負值在左邊。
height:矩形的高度。正值下降,負值上升。
注意一下w,h這兩個引數的正直和負值。
如果w,h是負數,會出現了2個斜著對稱的矩形
繪製一個靜態矩形
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
html,body{
/* 去除瀏覽器內建的margin */
margin: 0;
/* 整個頁面鋪滿 */
height: 100%;
width: 100%;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
</body>
<script>
// 獲取canvas元素
let canvasEle = document.getElementById('canvas')
// 獲取canvas的上下文
const ctx = canvasEle.getContext('2d')
// 設定canvas的大小(寬高) 與螢幕一樣寬高
const screenSize = document.documentElement
canvasEle.width = window.screen.availWidth
canvasEle.height = window.screen.availHeight
// 給矩形的設定顏色,設定顏色一定要在繪製之前,否則將會不生效
ctx.strokeStyle = '#a0a'
// 繪製一個路徑模式是的矩形,起始座標100,100, 寬300,高280
ctx.strokeRect(100,100,300,280)
</script>
</html>
手動繪製矩形的基本思路
透過上面我們實現了靜態繪製矩形。
如果我們想要手動畫一個矩形,需要實現以下幾個步驟
1.給canvas註冊滑鼠按下事件,在按下的時候記錄矩形的起始座標(x,y)
與此同時,還需要在按下時註冊滑鼠移動事件和抬起事件。
2.在滑鼠移動的時候,透過計算得到矩形的寬和高。
計算矩形的寬度和高度時,我們要使用絕對值進行計算。
計算後立即繪製矩形
3.在滑鼠抬起時,移除之前註冊的滑鼠移動事件和抬起事件
手動繪製矩形
<script>
// 獲取canvas元素 oCan
let canvasEle = document.getElementById('canvas')
// 獲取canvas的上下文
const ctx = canvasEle.getContext('2d')
// 設定canvas的大小(寬高) 與螢幕一樣寬高
const screenSize = document.documentElement
canvasEle.width = window.screen.availWidth
canvasEle.height = window.screen.availHeight
// 所有的矩形資訊
let rectArr = []
// 給canvas註冊事件按下事件
canvasEle.addEventListener('mousedown',canvasDownHandler)
function canvasDownHandler(e){
console.log('按下', e)
rectArr = [e.clientX,e.clientY ]
// 按下的時候需要註冊移動事件
canvasEle.addEventListener('mousemove', canvasMoveHandler)
// 抬起事件
canvasEle.addEventListener('mouseup', canvasMouseUpHandler)
}
// 移動的時候我們需要記錄起始點和結束點,然後就可以繪製矩形了
function canvasMoveHandler(e){
console.log('我們在移動了', e)
// 在移動的時候就開始繪製矩形
drawRect(rectArr[0], rectArr[1], e.clientX, e.clientY)
}
function drawRect(x1,y1,x2,y2){
// 在計算矩形的寬高時,我們需要使用絕對值來進行計算
// 此時此刻移動的座標減去最初按下的座標就是矩形的寬和高
// 如果不用絕對值,可能會出現2個矩形
let rectWidth = Math.abs(x2-x1)
let rectHeight = Math.abs(y2-y1)
// 儲存矩形的座標資訊
rectArr = [x1,y1,rectWidth,rectHeight]
ctx.strokeRect(...rectArr)
}
// 當我們滑鼠抬起的時候要移除之前註冊移動事件和抬起事件
function canvasMouseUpHandler(){
canvasEle.removeEventListener('mousemove', canvasMoveHandler)
canvasEle.removeEventListener('mouseup', canvasMouseUpHandler)
}
</script>
發現問題出現多餘的路徑
透過上面這張圖片,我們雖然繪製手動繪製出了矩形。
但是出現了重複的路徑。
我們先分析一下出現重複路徑的原因。
我們在每次移動的過程中,都會繪製矩形。
只要我們在繪製前,清空矩形是不是就可以解決這個問題
我們來嘗試一下
在繪之前清除多餘的路徑
function drawRect(x1,y1,x2,y2){
// 在計算矩形的寬高時,我們需要使用絕對值來進行計算
// 此時此刻移動的座標減去最初按下的座標就是矩形的寬和高
let rectWidth = Math.abs(x2-x1)
let rectHeight = Math.abs(y2-y1)
// 儲存矩形的座標資訊
rectArr = [x1,y1,rectWidth,rectHeight]
// 在繪製矩形前,我們將矩形清空,然後在繪製,就不會出現多餘的路徑了
ctx.clearRect(0,0, canvasEle.width, canvasEle.height)
// 重新繪製矩形
ctx.strokeRect(...rectArr)
}
機智的小夥伴發現問題了?
有些機智的小夥伴發現:
如果我起始點是右下角,終點是左上角。
即:使用者從(900, 1000)拖動到(50, 50)這種情況
按照這樣的方向繪製矩形,是不是會出現問題呢?
確實會出現問題。
此時繪製的矩形不會隨著我們的方向進行繪製。請看下面的圖
如何處理這個問題呢?
主角閃亮登場 canvas.rect
canvas.rect(x,y,w,h)該方法建立一個矩形路徑
x:矩形起點的 x 軸座標。
y:矩形起點的 y 軸座標。
width:矩形的寬度。正值在右邊,負值在左邊。
height:矩形的高度。正值下降,負值上升。
這個方法是建立一個矩形路徑,建立的路徑並不會直接繪製在畫布上。
需要呼叫stroke()或fill()才能顯示在畫布上。
使用canvas.rect 繪製矩形路徑
function drawRect(x1,y1,x2,y2){
let rectWidth = Math.abs(x2-x1)
let rectHeight = Math.abs(y2-y1)
// 繪製之前先清空之前實時移動產生的多餘的矩形路徑
ctx.clearRect(0,0, canvasEle.width, canvasEle.height)
// 開始畫線
ctx.beginPath();
// 繪製路徑矩形
ctx.rect(Math.min(x1, x2), Math.min(y1, y2), rectWidth, rectHeight);
// 繪製形狀的輪廓。
ctx.stroke();
}
canvas.strokeRect與canvas.rect的異同
區別1功能性: canvas.strokeRect:繪製的是邊框。canvas.rect建立矩形的路徑(不繪立即繪製在矩形上)
區別2即時性: canvas.strokeRect是立即繪製。canvas.rect不是立即繪製,需要呼叫stroke()或fill()才能繪製
相同點:
1.都是繪製矩形
2.接受的引數相同
3.都是透過strokeStyle(顏色)和lineWidth(線的粗細)等來設定樣式
連續繪製多個矩形
function drawRect(x1,y1,x2,y2){
let rectWidth = Math.abs(x2-x1)
let rectHeight = Math.abs(y2-y1)
let endX = Math.min(x1, x2)
let endY = Math.min(y1, y2)
// 繪製之前先清空之前實時移動產生的多餘的矩形路徑
ctx.clearRect(0,0, canvasEle.width, canvasEle.height)
// 繪製之前那些儲存在 beforeRectArr 陣列中的矩形
allRectInfoArr = [endX, endY, rectWidth, rectHeight]
ctx.clearRect(0,0, canvasEle.width, canvasEle.height)
beforeRectArr.forEach(element => {
ctx.beginPath();
ctx.strokeRect(...element)
ctx.stroke();
});
// 開始本次路徑
ctx.beginPath();
// 繪製本次的矩形路徑
ctx.rect(...allRectInfoArr);
// 開始填充矩形
ctx.stroke();
}
// 當我們滑鼠抬起的時候要移除之前註冊移動事件和抬起事件
function canvasMouseUpHandler(){
savaBeforeRect()
canvasEle.removeEventListener('mousemove', canvasMoveHandler)
canvasEle.removeEventListener('mouseup', canvasMouseUpHandler)
}
function savaBeforeRect(){
beforeRectArr.push(allRectInfoArr)
}
全部程式碼
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
html,body{
/* 去除瀏覽器內建的margin */
margin: 0;
/* 整個頁面鋪滿 */
height: 100%;
width: 100%;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
</body>
<script>
// 獲取canvas元素 oCan
let canvasEle = document.getElementById('canvas')
// 獲取canvas的上下文
const ctx = canvasEle.getContext('2d')
// 設定canvas的大小(寬高) 與螢幕一樣寬高
const screenSize = document.documentElement
canvasEle.width = window.screen.availWidth
canvasEle.height = window.screen.availHeight
// 給矩形的設定顏色
// ctx.strokeStyle = '#a0a'
// // 繪製一個路徑模式是的矩形,起始座標100,100, 寬300,高280
// ctx.strokeRect(100,100,400,280)
// 矩形資訊
let rectArr = []
// 所有的矩形資訊
allRectInfoArr = []
let beforeRectArr =[]
// 給canvas註冊事件按下事件
canvasEle.addEventListener('mousedown',canvasDownHandler)
function canvasDownHandler(e){
rectArr = [e.clientX,e.clientY ]
// 按下的時候需要註冊移動事件
canvasEle.addEventListener('mousemove', canvasMoveHandler)
// 抬起事件
canvasEle.addEventListener('mouseup', canvasMouseUpHandler)
}
// 移動的時候我們需要記錄起始點和結束點,然後就可以繪製矩形了
function canvasMoveHandler(e){
// 在移動的時候就開始繪製矩形
drawRect(rectArr[0], rectArr[1], e.clientX, e.clientY)
}
function drawRect(x1,y1,x2,y2){
let rectWidth = Math.abs(x2-x1)
let rectHeight = Math.abs(y2-y1)
let endX = Math.min(x1, x2)
let endY = Math.min(y1, y2)
// 繪製之前先清空之前實時移動產生的多餘的矩形路徑
ctx.clearRect(0,0, canvasEle.width, canvasEle.height)
// 繪製之前那些儲存在 beforeRectArr 陣列中的矩形
allRectInfoArr = [endX, endY, rectWidth, rectHeight]
beforeRectArr.forEach(element => {
ctx.beginPath();
ctx.strokeRect(...element)
ctx.stroke();
});
// 開始本次路徑
ctx.beginPath();
// 繪製本次的矩形路徑
ctx.rect(...allRectInfoArr);
// 開始填充矩形
ctx.stroke();
}
// 當我們滑鼠抬起的時候要移除之前註冊移動事件和抬起事件
function canvasMouseUpHandler(){
savaBeforeRect()
canvasEle.removeEventListener('mousemove', canvasMoveHandler)
canvasEle.removeEventListener('mouseup', canvasMouseUpHandler)
}
function savaBeforeRect(){
beforeRectArr.push(allRectInfoArr)
}
</script>
</html>
尾聲
如果小夥伴覺得我寫的不錯的話
可以給我點個贊嗎?感謝了。
後面會繼續寫:
如何選中矩形,更改矩形大小。
如何在矩形上新增文字。
如何繪製圓,箭頭符號等