Canvas中的曲线分为两种:标准圆弧曲线、贝塞尔曲线
1. 标准圆弧曲线
(1)弧线
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>弧线</title>
</head>
<body>
<script>
// 1. 创建 canvas 画布
const canvas = document.createElement('canvas')
// 设置宽高
canvas.width = 500
canvas.height = 500
document.body.append(canvas)
// 2. 获取 context 对象(画笔)
const context = canvas.getContext('2d')
// 画圆弧
/*
参数:圆心x, 圆心y, 弧度,圆弧起点,圆弧终点,是否逆时针(默认为false)
*/
context.arc(200, 200, 50, 90 * (Math.PI / 180), 180 * (Math.PI / 180), true)
context.stroke()
</script>
</body>
</html>
(2)画一个笑脸
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>笑脸</title>
</head>
<body>
<script>
// 1. 创建 canvas 画布
const canvas = document.createElement('canvas')
// 设置宽高
canvas.width = 500
canvas.height = 500
document.body.append(canvas)
// 2. 获取 context 对象(画笔)
const context = canvas.getContext('2d')
// 3.画笑脸
// 3.1 外圈大圆
context.arc(200, 200, 100, 0, 360 * (Math.PI / 180))
context.stroke()
// 3.2 左眼
// 重新生成新的路径(即在两个不相关的图形之间要加上开始路径,闭合路径,取消两个图形之间的连线)
context.beginPath()
context.arc(150, 150, 20, 0, 360 * (Math.PI / 180))
context.stroke()
context.closePath()
// 3.3 右眼
context.beginPath()
context.arc(250, 150, 20, 0, 360 * (Math.PI / 180))
context.stroke()
context.closePath()
// 3.4 鼻子
context.beginPath()
context.arc(200, 195, 8, 0, 360 * (Math.PI / 180))
context.stroke()
context.closePath()
// 3.5 嘴巴
context.beginPath()
context.arc(200, 200, 80, 0, 180 * (Math.PI / 180))
context.stroke()
context.closePath()
</script>
</body>
</html>
(3)椭圆
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>椭圆</title>
</head>
<body>
<script>
// 1. 创建 canvas 画布
const canvas = document.createElement('canvas')
// 设置宽高
canvas.width = 500
canvas.height = 500
document.body.append(canvas)
// 2. 获取 context 对象(画笔)
const context = canvas.getContext('2d')
// 画椭圆
/*
参数:圆心x,圆心y,x半径,y半径,椭圆旋转的角度(弧度),圆弧起点,圆弧终点,是否逆时针(默认为false)
*/
context.ellipse(300, 300, 200, 100, 0, 0, 360 * (Math.PI / 180))
context.stroke()
</script>
</body>
</html>
(4)使用fill填充图形
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>使用fill填充图形</title>
</head>
<body>
<script>
// 1. 创建 canvas 画布
const canvas = document.createElement('canvas')
// 设置宽高
canvas.width = 500
canvas.height = 500
document.body.append(canvas)
// 2. 获取 context 对象(画笔)
const context = canvas.getContext('2d')
// 3.填充
context.moveTo(100, 100)
context.lineTo(90, 220)
context.lineTo(220, 150)
// 调用fill方法时,路径会自动连接起始位置
// context.lineTo(100, 100)
// context.fill()
// 填充指定颜色
// context.fillStyle = 'lightblue'
// context.fill()
// 使用线性渐变填充
// const gradient = context.createLinearGradient(0, 0, 500, 500)
// gradient.addColorStop(0, 'lightblue')
// gradient.addColorStop(1, 'red')
// context.fillStyle = gradient
// context.fill()
// 使用径向渐变填充
const gradient = context.createRadialGradient(150, 150, 0, 150, 150, 100)
gradient.addColorStop(0, 'lightblue')
gradient.addColorStop(1, 'orange')
context.fillStyle = gradient
context.fill()
</script>
</body>
</html>
(5)五子棋
(5)五子棋
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>五子棋</title>
<style>
canvas {
background-color: green;
display: block;
margin: 0 auto;
}
#tip {
text-align: center;
padding: 20px;
}
</style>
</head>
<body>
<div id="tip">游戏开始</div>
<script>
// 1.创建 canvas 画布
const canvas = document.createElement('canvas')
// 设置宽高
canvas.width = 700
canvas.height = 700
document.body.append(canvas)
// 2.获取 context 对象(画笔)
const context = canvas.getContext('2d')
const tip = document.getElementById('tip')
// 3.棋盘
for (i = 0; i < 14; i++) {
context.moveTo(50, 50 * i)
context.lineTo(650, 50 * i)
context.stroke()
context.moveTo(50 * i, 50)
context.lineTo(50 * i, 650)
context.stroke()
}
// 5.棋子颜色判断标志位
let isBlackChess = true
// 6.使用二维数组存储棋子
let circles = []
for(i = 0; i < 14; i ++) {
circles[i] = []
}
// 7.游戏结束判断标志位
let gameOver = false
// 4.落子
canvas.addEventListener('click', e => {
if (gameOver) {
return
}
let { offsetX, offsetY } = e
// 判断棋子不超出棋盘
if (offsetX < 25 || offsetY < 25 || offsetX > 675 || offsetY > 675) {
return
}
// 6.1 格子位置
let gridX = Math.floor((offsetX + 25) / 50)
let gridY = Math.floor((offsetY + 25) / 50)
// 6.3 判断是否重复落子
if (circles[gridX][gridY]) {
return
}
// 4.1 棋子位置
let x = gridX * 50
let y = gridY * 50
context.beginPath()
context.arc(x, y, 20, 0, 2 * Math.PI)
// 6.2 存储棋子
circles[gridX][gridY] = isBlackChess ? 'black' : 'white'
// 5.1 设置棋子颜色
let chessGradientX = isBlackChess ? x - 10 : x + 10
let chessGradientY = isBlackChess ? y - 10 : y + 10
let gradient = context.createRadialGradient(chessGradientX, chessGradientY, 0, chessGradientX, chessGradientY, 30)
gradient.addColorStop(0, isBlackChess ? 'gray' : '#666')
gradient.addColorStop(1, isBlackChess ? 'black' : 'white')
context.fillStyle = gradient
// 5.2 设置棋子阴影
context.shadowColor = '#333'
context.shadowOffsetX = 2.5
context.shadowOffsetY = 2
context.fill()
context.closePath()
// 7.判断当前是否有人获胜
gameOver = checkVertical(circles[gridX][gridY], gridX, gridY) || checkHorizontal(circles[gridX][gridY], gridX, gridY) || checkWn2Es(circles[gridX][gridY], gridX, gridY) || checkEn2Ws(circles[gridX][gridY], gridX, gridY)
if (gameOver) {
tip.innerText = `${isBlackChess ? '黑' : '白'}棋获胜,游戏结束!`
//console.log(circles)
return
}
tip.innerText = isBlackChess ? '请白棋落子' : '请黑棋落子'
isBlackChess = !isBlackChess
})
// 纵向查找是否有五个连续相同的棋子
function checkVertical(currentChess, row, col) {
let count = 1
return checkUp(currentChess, row, col, count) + checkDown(currentChess, row, col, count) - 1 >= 5
}
function checkUp(currentChess, row, col, count) {
// 向上查找的次数
let up = 0
while (true) {
// 向上查找
up++
// 角
// 左上角
if (row === 1 && col === 1) {
return count
}
// 右上角
if (row + up === circles.length && col === 1) {
return count
}
// 边
// 上
if (col === 1) {
return count
}
// 右 pass
// 下 pass
// 左 pass
// 超出边界
if (row - up < 0) {
return count
}
if (circles[row][col - up] && circles[row][col - up] === currentChess) {
count++
}
// 棋子不连续
if (col === 1) {
if (count >= 5 || (circles[row][col + up] !== currentChess)) {
break
}
} else if (col + up >= circles.length) {
if (count >= 5 || (circles[row][col - up] !== currentChess)) {
break
}
} else {
if (count >= 5 || (circles[row][col - up] !== currentChess && circles[row][col + up] !== currentChess)) {
break
}
}
}
return count
}
function checkDown(currentChess, row, col, count) {
// 向下查找的次数
let down = 0
while (true) {
// 向下查找
down++
// 角
// 右下角
if (row + down === circles.length && col + down === circles.length) {
return count
}
// 左下角
if (row === 1 && col + down === circles.length) {
return count
}
// 边
// 上 pass
// 右 pass
// 下
if (col + down === circles.length) {
return count
}
// 左 pass
// 超出边界
if (row + down > circles.length) {
return count
}
if (circles[row][col + down] && circles[row][col + down] === currentChess) {
count++
}
// 棋子不连续
if (col === 1) {
if (count >= 5 || (circles[row][col - down] !== currentChess)) {
break
}
} else if (col + down >= circles.length) {
if (count >= 5 || (circles[row][col - down] !== currentChess)) {
break
}
} else {
if (count >= 5 || (circles[row][col - down] !== currentChess && circles[row][col + down] !== currentChess)) {
break
}
}
}
return count
}
// 横向查找是否有五个连续相同的棋子
function checkHorizontal(currentChess, row, col) {
let count = 1
return checkLeft(currentChess, row, col, count) + checkRight(currentChess, row, col, count) - 1 >= 5
}
function checkLeft(currentChess, row, col, count) {
// 向左查找的次数
let left = 0
while (true) {
// 向左查找
left++
// 角
// 左上角
if (row === 1 && col === 1) {
return count
}
// 左下角
if (row === 1 && col + left === circles.length) {
return count
}
// 边
// 上 pass
// 右 pass
// 下 pass
// 左
if (row === 1) {
return count
}
// 超出边界
if (row - left < 0) {
return count
}
if (circles[row - left][col] && circles[row - left][col] === currentChess) {
count++
}
// 棋子不连续
if (col === 1 && row + left < circles.length) {
if (count >= 5 || (circles[row + left][col] !== currentChess)) {
break
}
} else if (row + left >= circles.length) {
if (count >= 5 || (circles[row - left][col] !== currentChess)) {
break
}
} else {
if (count >= 5 || (circles[row - left][col] !== currentChess && circles[row + left][col] !== currentChess)) {
break
}
}
}
return count
}
function checkRight(currentChess, row, col, count) {
// 向右查找的次数
let right = 0
while (true) {
// 向右查找
right++
// 角
// 右上角
if (row + right === circles.length && col === 1) {
return count
}
// 右下角
if (row + right === circles.length && col + right === circles.length) {
return count
}
// 边
// 上 pass
// 右
if (row + right === circles.length) {
return count
}
// 下 pass
// 左 pass
if (circles[row + right][col] && circles[row + right][col] === currentChess) {
count++
}
// 超出边界
if (row + right > circles.length) {
return count
}
// 同色棋子大于5 || 棋子不连续
if (col === 1 && row + right < circles.length) {
if (count >= 5 || (circles[row + right][col] !== currentChess)) {
break
}
} else if (row + right >= circles.length) {
if (count >= 5 || (circles[row - right][col] !== currentChess)) {
break
}
} else {
if (count >= 5 || (circles[row - right][col] !== currentChess && circles[row + right][col] !== currentChess)) {
break
}
}
}
return count
}
// 左上到右下查找是否有五个连续相同的棋子
function checkWn2Es(currentChess, row, col) {
// 连续同色棋子的数量
let count = 1
return checkWn(currentChess, row, col, count) + checkEs(currentChess, row, col, count) - 1 >= 5
}
function checkWn(currentChess, row, col, count) {
// 左上查找的次数
let leftUp = 0
while (true) {
// 向左上查找
leftUp++
// 角
// 左上角
if (row === 1 && col === 1) {
return count
}
// 右上角
if (row + leftUp === circles.length && col === 1) {
return count
}
// 左下角
if (row === 1 && col + leftUp === circles.length) {
return count
}
// 边
// 上
if (col === 1) {
return count
}
// 右 pass
// 下 pass
// 左
if (row === 1) {
return count
}
// 超出边界
if (row - leftUp < 0 || col - leftUp < 0) {
return count
}
if (circles[row - leftUp][col - leftUp] && circles[row - leftUp][col - leftUp] === currentChess) {
count++
}
// 同色棋子大于5 || 棋子不连续
if (row === 1 || col === 1) {
if (count >= 5 || (circles[row + leftUp][col + leftUp] !== currentChess)) {
break
}
} else if (row + leftUp >= circles.length || col + leftUp >= circles.length) {
if (count >= 5 || circles[row - leftUp][col - leftUp] !== currentChess) {
break
}
} else {
if (count >= 5 || (circles[row - leftUp][col - leftUp] !== currentChess && circles[row + leftUp][col + leftUp] !== currentChess)) {
break
}
}
}
return count
}
function checkEs(currentChess, row, col, count) {
// 右下查找的次数
let rightDown = 0
while (true) {
// 向右下查找
rightDown++
// 角
// 右上角
if (row + rightDown === circles.length && col === 1) {
return count
}
// 右下角
if (row + rightDown === circles.length && col + rightDown === circles.length) {
return count
}
// 左下角
if (row === 1 && col + rightDown === circles.length) {
return count
}
// 边
// 上 pass
// 右
if (row + rightDown === circles.length) {
return count
}
// 下
if (col + rightDown === circles.length) {
return count
}
// 左 pass
// 超出边界
if (row + rightDown > circles.length || col + rightDown > circles.length) {
return count
}
if (circles[row + rightDown][col + rightDown] && circles[row + rightDown][col + rightDown] === currentChess) {
count++
}
// 同色棋子大于5 || 棋子不连续
if (row === 1 || col === 1) {
if (count >= 5 || (circles[row + rightDown][col + rightDown] !== currentChess)) {
break
}
} else if (row + rightDown >= circles.length || col + rightDown >= circles.length) {
if (count >= 5 || circles[row - rightDown][col - rightDown] !== currentChess) {
break
}
} else {
if (count >= 5 || row - rightDown < 0) {
break
}
if (count >= 5 || (circles[row - rightDown][col - rightDown] !== currentChess && circles[row + rightDown][col + rightDown] !== currentChess)) {
break
}
}
}
return count
}
// 右上到左下查找是否有五个连续相同的棋子
function checkEn2Ws(currentChess, row, col) {
// 连续同色棋子的数量
let count = 1
return checkEn(currentChess, row, col, count) + checkWs(currentChess, row, col, count) - 1 >= 5
}
function checkEn(currentChess, row, col, count) {
// 右上查找的次数
let rightUp = 0
while (true) {
// 向右上查找
rightUp++
// 角
// 左上角
if (row === 1 && col === 1) {
return count
}
// 右上角
if (row + rightUp === circles.length && col === 1) {
return count
}
// 右下角
if (row + rightUp === circles.length && col + rightUp === circles.length) {
return count
}
// 边
// 上
if (col === 1) {
return count
}
// 右
if (row + rightUp >= circles.length) {
return count
}
// 下 pass
// 左 pass
// 超出边界
if (row + rightUp > circles.length || col - rightUp < 0) {
return count
}
if (circles[row + rightUp][col - rightUp] && circles[row + rightUp][col - rightUp] === currentChess) {
count++
}
// 同色棋子大于5 || 棋子不连续
if (row === 1 || col + rightUp >= circles.length) {
if (count >= 5 || (circles[row + rightUp][col - rightUp] !== currentChess)) {
break
}
} else if (row + rightUp >= circles.length || col === 1) {
if (count >= 5 || (circles[row - rightUp][col + rightUp] !== currentChess)) {
break
}
} else {
if (count >= 5 || row - rightUp < 0) {
break
}
if (count >= 5 || (circles[row + rightUp][col - rightUp] !== currentChess && circles[row - rightUp][col + rightUp] !== currentChess)) {
break
}
}
}
return count
}
function checkWs(currentChess, row, col, count) {
// 左下查找的次数
let leftDown = 0
while (true) {
// 向左下查找
leftDown++
// 角
// 左上角
if (row === 1 && col === 1) {
return count
}
// 左下角
if (row === 1 && col + leftDown === circles.length) {
return count
}
// 右下角
if (row + leftDown === circles.length && col + leftDown === circles.length) {
return count
}
// 边
// 上 pass
// 右 pass
// 下
if (col === col + leftDown === circles.length) {
return count
}
// 左
if (row === 1) {
return count
}
// 超出边界
if (row - leftDown < 0 || col + leftDown > circles.length) {
return count
}
if (circles[row - leftDown][col + leftDown] && circles[row - leftDown][col + leftDown] === currentChess) {
count++
}
// 同色棋子大于5 || 棋子不连续
if (row + leftDown >= circles.length || col === 1) {
if (count >= 5 || circles[row - leftDown][col + leftDown] !== currentChess) {
break
}
} else if (row === 1 || col + leftDown >= circles.length) {
if (count >= 5 || (circles[row + leftDown][col - leftDown] !== currentChess)) {
break
}
} else {
if (count >= 5 || (circles[row - leftDown][col + leftDown] !== currentChess && circles[row + leftDown][col - leftDown] !== currentChess)) {
break
}
}
}
return count
}
</script>
</body>
</html>
(6)阴影
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>阴影</title>
</head>
<body>
<script>
// 1.创建 canvas 画布
const canvas = document.createElement('canvas')
// 设置宽高
canvas.width = 500
canvas.height = 500
document.body.append(canvas)
// 2.获取 context 对象(画笔)
const context = canvas.getContext('2d')
context.strokeStyle = 'green'
context.lineWidth = 6
// 设置图像的阴影
context.shadowColor = 'gray'
context.shadowOffsetX = 6
context.shadowOffsetY = 3
context.shadowBlur = 5
context.moveTo(100, 100)
context.lineTo(260, 260)
context.stroke()
</script>
</body>
</html>
评论 (0)