Appearance
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
html,
body {
width: 100vw;
height: 100vh;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
</style>
</head>
<body>
<form id="form">
Stroke Style:
<select id="strokeStyleSelect">
<option value="#5470c6">#5470c6</option>
<option value="#91cc75">#91cc75</option>
<option value="#fac858">#fac858</option>
<option value="#ee6666">#ee6666</option>
<option value="#73c0de">#73c0de</option>
<option value="#3ba272">#3ba272</option>
<option value="#fc8452">#fc8452</option>
<option value="#9a60b4">#9a60b4</option>
<option value="#ea7ccc">#ea7ccc</option>
</select>
<br />
Guild Wires:
<input type="checkbox" id="guildWiresCheckbox">
</form>
<canvas id="canvas"></canvas>
<script>
const canvas = document.getElementById('canvas')
const context = canvas.getContext('2d')
canvas.width = 600
canvas.height = 600
canvas.style.background = '#ddd'
context.strokeStyle = strokeStyleSelect.value
// 选择颜色
strokeStyleSelect.addEventListener('change', e => {
context.strokeStyle = e.target.value
})
let isDragging = false
let isDrawguildWires = false
let drawingSurface = null
const rect = {
startX: null,
startY: null,
endX: null,
endY: null
}
guildWiresCheckbox.addEventListener('change', e => {
isDrawguildWires = e.target.checked
})
// 在视口中的坐标转化为在 canvas 中的坐标
const windowToCanvas = (x, y) => {
const { left, top } = canvas.getBoundingClientRect()
return {
x: x - left,
y: y - top
}
}
// 保存绘图表面
const saveDrawingSurface = () => {
const { width, height } = canvas
drawingSurface = context.getImageData(0, 0, width, height)
}
// 恢复绘图表面
const restoreDrawingSurface = () => {
context.putImageData(drawingSurface, 0, 0)
}
canvas.addEventListener('mousedown', e => {
const { x, y } = windowToCanvas(e.clientX, e.clientY)
rect.startX = rect.endX = x
rect.startY = rect.endY = y
isDragging = true
// 保存绘图表面,在 mousemove 中恢复绘图表面,这样鼠标每次移动就会擦除上一次的线段。
saveDrawingSurface()
})
canvas.addEventListener('mousemove', e => {
if (isDragging) {
restoreDrawingSurface()
const { x, y } = windowToCanvas(e.clientX, e.clientY)
rect.endX = x
rect.endY = y
drawWires()
if (isDrawguildWires) {
drawRect()
}
}
})
canvas.addEventListener('mouseup', e => {
restoreDrawingSurface()
isDragging = false
})
// 画对角线
const drawWires = () => {
context.beginPath()
context.moveTo(rect.startX, rect.startY)
context.lineTo(rect.endX, rect.endY)
context.stroke()
}
// 画矩形边框
const drawRect = () => {
context.beginPath()
// 两条横线
context.moveTo(rect.startX, rect.startY)
context.lineTo(rect.endX, rect.startY)
context.moveTo(rect.startX, rect.endY)
context.lineTo(rect.endX, rect.endY)
// 两条竖线
context.moveTo(rect.startX, rect.startY)
context.lineTo(rect.startX, rect.endY)
context.moveTo(rect.endX, rect.startY)
context.lineTo(rect.endX, rect.endY)
context.stroke()
}
</script>
</body>
</html>