(x: number, y: number, isStart: boolean)
| 479 | } |
| 480 | |
| 481 | const draw = (x: number, y: number, isStart: boolean) => { |
| 482 | const canvas = canvasRef.current |
| 483 | if (!canvas) return |
| 484 | |
| 485 | const ctx = canvas.getContext('2d') |
| 486 | if (!ctx) return |
| 487 | |
| 488 | if (drawMode === 'mosaic') { |
| 489 | // 马赛克效果 |
| 490 | const mosaicSize = brushSize |
| 491 | const halfSize = mosaicSize / 2 |
| 492 | |
| 493 | const startX = Math.max(0, Math.floor(x - halfSize)) |
| 494 | const startY = Math.max(0, Math.floor(y - halfSize)) |
| 495 | const width = Math.min(mosaicSize, canvas.width - startX) |
| 496 | const height = Math.min(mosaicSize, canvas.height - startY) |
| 497 | |
| 498 | if (width > 0 && height > 0) { |
| 499 | const imageData = ctx.getImageData(startX, startY, width, height) |
| 500 | const data = imageData.data |
| 501 | |
| 502 | let r = 0, |
| 503 | g = 0, |
| 504 | b = 0 |
| 505 | const pixelCount = width * height |
| 506 | |
| 507 | for (let i = 0; i < data.length; i += 4) { |
| 508 | r += data[i] |
| 509 | g += data[i + 1] |
| 510 | b += data[i + 2] |
| 511 | } |
| 512 | |
| 513 | r = Math.floor(r / pixelCount) |
| 514 | g = Math.floor(g / pixelCount) |
| 515 | b = Math.floor(b / pixelCount) |
| 516 | |
| 517 | ctx.fillStyle = `rgb(${r}, ${g}, ${b})` |
| 518 | ctx.fillRect(startX, startY, width, height) |
| 519 | } |
| 520 | } else if (drawMode === 'draw') { |
| 521 | // 绘图模式 |
| 522 | ctx.strokeStyle = drawColor |
| 523 | ctx.lineWidth = brushSize |
| 524 | ctx.lineCap = 'round' |
| 525 | ctx.lineJoin = 'round' |
| 526 | ctx.globalAlpha = 1 |
| 527 | |
| 528 | if (isStart || !lastDrawPoint) { |
| 529 | ctx.beginPath() |
| 530 | ctx.moveTo(x, y) |
| 531 | } else { |
| 532 | ctx.beginPath() |
| 533 | ctx.moveTo(lastDrawPoint.x, lastDrawPoint.y) |
| 534 | ctx.lineTo(x, y) |
| 535 | ctx.stroke() |
| 536 | } |
| 537 | setLastDrawPoint({ x, y }) |
| 538 | } else if (drawMode === 'eraser') { |
no test coverage detected