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>
</head>
<body>
<form id="form">
Edges:
<select id="sidesSelect">
<option value="4">4</option>
<option value="5">5</option>
<option value="6">6</option>
</select>
<br>
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>
<input type="checkbox" id="fillCheckbox">
Fill Checkbox
<br>
<input type="checkbox" id="editCheckbox">
Edit Checkbox
</form>
<canvas id="canvas"></canvas>
<script src="../lib/plain-canvas.min.js"></script>
<script>
const canvas = document.getElementById('canvas')
const context = canvas.getContext('2d')
const c = new Canvas(canvas, {
lineWidth: 1,
fillStyle: strokeStyleSelect.value,
strokeStyle: strokeStyleSelect.value
})
canvas.width = 600
canvas.height = 600
canvas.style.background = '#ddd'
context.strokeStyle = context.fillStyle = strokeStyleSelect.value
// 选择颜色
strokeStyleSelect.addEventListener('change', e => {
context.strokeStyle = context.fillStyle = e.target.value
})
let dragging = false
let filling = false
let editing = false
let edges = 4
let drawingSurface = null
let draggingOffsetX = null
let draggingOffsetY = null
let draggingPolygon = null
const polygons = []
let point = {
x: null,
y: null
}
sidesSelect.addEventListener('change', e => {
edges = e.target.value
})
fillCheckbox.addEventListener('change', e => {
filling = e.target.checked
})
editCheckbox.addEventListener('change', e => {
editing = e.target.checked
})
// 保存绘图表面
const saveDrawingSurface = () => {
const { width, height } = canvas
drawingSurface = context.getImageData(0, 0, width, height)
}
// 恢复绘图表面
const restoreDrawingSurface = () => {
context.putImageData(drawingSurface, 0, 0)
}
const drawPolygons = () => {
polygons.forEach((polygon) => {
polygon.createPath()
polygon.stroke(polygon.strokeStyle)
})
}
canvas.addEventListener('mousedown', e => {
const { clientX, clientY } = e
point = c.windowToCanvas(clientX, clientY)
if (editing) {
for (let i = 0, l = polygons.length; i < l; i++) {
const polygon = polygons[i]
// 绘制路径
polygon.createPath()
// 绘制完成后通过 isPointInPath 判断鼠标按下时是否在路径内
if (context.isPointInPath(point.x, point.y)) {
// 记录被拖拽的多边形
draggingPolygon = polygon
// 鼠标一定在多边形内部,鼠标释放时需要保持鼠标和多边形的相对位置一致
draggingOffsetX = point.x - polygon.x
draggingOffsetY = point.y - polygon.y
break
}
}
} else {
// 保存绘图表面,在 mousemove 中恢复绘图表面,这样鼠标每次移动就会擦除上一次的线段。
saveDrawingSurface()
}
dragging = true
})
let polygon = null
canvas.addEventListener('mousemove', e => {
if (!dragging) {
return
}
const { x, y } = c.windowToCanvas(e.clientX, e.clientY)
if (editing) {
if (draggingPolygon) {
// 拖动时确定多边形新的位置
draggingPolygon.x = x - draggingOffsetX
draggingPolygon.y = y - draggingOffsetY
// 重新绘制
context.clearRect(0, 0, canvas.width, canvas.height)
drawPolygons()
}
} else {
restoreDrawingSurface()
const { x: _x, y: _y } = point
const radius = Math.sqrt(Math.pow((x - _x), 2) + Math.pow((y - _y), 2))
polygon = c.polygon(_x, _y, radius, edges)
if (filling) {
polygon.fill()
}
}
})
canvas.addEventListener('mouseup', e => {
dragging = false
point.x = point.y = null
draggingPolygon = null
if (!editing) {
polygons.push(polygon)
}
polygon = null
})
</script>
</body>
</html>