#3 型エラー対応

This commit is contained in:
2025-08-10 06:08:37 +09:00
parent 22a55f265c
commit 235814aff7
@@ -17,11 +17,11 @@ type Layer = {
image?: ImageItem } image?: ImageItem }
type Line = type Line =
| { mode: Mode.Pen | Mode.Rubber | { mode: typeof Mode.Pen | typeof Mode.Rubber
points: number[] points: number[]
stroke: string stroke: string
strokeWidth: number } strokeWidth: number }
| { mode: Mode.Paint | { mode: typeof Mode.Paint
points: number[] points: number[]
stroke: string, stroke: string,
imageSrc: string } imageSrc: string }
@@ -29,7 +29,6 @@ type Line =
const Mode = { const Mode = {
Pen: 'Pen', Pen: 'Pen',
Rubber: 'Rubber', Rubber: 'Rubber',
Image: 'Image',
Paint: 'Paint' } as const Paint: 'Paint' } as const
type Mode = (typeof Mode)[keyof typeof Mode] type Mode = (typeof Mode)[keyof typeof Mode]
@@ -51,7 +50,7 @@ const floodFill = (
const start = getRGBA (data, sx, sy, W) const start = getRGBA (data, sx, sy, W)
const visited = new Uint8Array (W * H) const visited = new Uint8Array (W * H)
if (colourDiffMax (start, [fill.r, flil.g, fill.b, fill.a]) <= tolerance) if (colourDiffMax (start, [fill.r, fill.g, fill.b, fill.a]) <= tolerance)
return return
const stack: [number, number][] = [[sx, sy]] const stack: [number, number][] = [[sx, sy]]
@@ -99,7 +98,7 @@ const getRGBA = (data: Uint8ClampedArray, x: number, y: number, w: number) => {
const hexToRgba = (hex: string, alpha = 255): [number, number, number, number] => { const hexToRgba = (hex: string, alpha = 255): [number, number, number, number] => {
const m = /^#?([0-9a-f]{6})$/i.exec (hex) const m = /^#?([0-9a-f]{6})$/i.exec (hex)
const n = parseInt (m[1], 16) const n = parseInt (m![1], 16)
return [(n >> 16) & 255, (n >> 8) & 255, n & 255, alpha] return [(n >> 16) & 255, (n >> 8) & 255, n & 255, alpha]
} }
@@ -110,21 +109,10 @@ const isLayer = (obj: unknown): obj is Layer => (
&& typeof (obj as Layer).id === 'string' && typeof (obj as Layer).id === 'string'
&& typeof (obj as Layer).name === 'string' && typeof (obj as Layer).name === 'string'
&& Array.isArray ((obj as Layer).lines) && Array.isArray ((obj as Layer).lines)
&& (obj as Layer).lines.every (isLine)
&& Array.isArray ((obj as Layer).history) && Array.isArray ((obj as Layer).history)
&& Array.isArray ((obj as Layer).future)) && Array.isArray ((obj as Layer).future))
const isLine = (obj: unknown): obj is Line => (
typeof obj === 'object'
&& obj !== null
&& Array.isArray ((obj as Line).points)
&& (obj as Line).points.every (n => typeof n === 'number')
&& typeof (obj as Line).stroke === 'string'
&& typeof (obj as Line).strokeWidth === 'number'
&& Object.values (Mode).includes ((obj as Line).mode))
export default () => { export default () => {
const drawingRef = useRef (false) const drawingRef = useRef (false)
const fileInputRef = useRef<HTMLInputElement> (null) const fileInputRef = useRef<HTMLInputElement> (null)
@@ -143,7 +131,7 @@ export default () => {
const activeLayer = layers.find (l => l.id === activeLayerId) const activeLayer = layers.find (l => l.id === activeLayerId)
const handleMouseDown = (ev: Konva.KonvaEventObject<MouseEvent | TouchEvent>) => { const handleMouseDown = (ev: Konva.KonvaEventObject<MouseEvent | TouchEvent>) => {
if (!(activeLayer)) if (!(activeLayer) || (mode !== Mode.Pen && mode !== Mode.Rubber))
return return
drawingRef.current = true drawingRef.current = true
@@ -222,7 +210,7 @@ export default () => {
fileInputRef.current.value = '' fileInputRef.current.value = ''
} }
const handlePaint = async (ev: Konva.KonvaEventObject<MouseEvent | TouchEvent>) => { const handlePaint = async () => {
const layer = activeLayer const layer = activeLayer
if (!(layer) || !(stageRef.current)) if (!(layer) || !(stageRef.current))
return return
@@ -245,14 +233,13 @@ export default () => {
$off.width = stageWidth $off.width = stageWidth
$off.height = stageHeight $off.height = stageHeight
const ctx = $off.getContext ('2d') const ctx = $off.getContext ('2d')
ctx.drawImage (img, 0, 0, stageWidth, stageHeight) ctx!.drawImage (img, 0, 0, stageWidth, stageHeight)
const imgData = ctx.getImageData (0, 0, stageWidth, stageHeight) const imgData = ctx!.getImageData (0, 0, stageWidth, stageHeight)
const [r, g, b, a] = hexToRgba (colour, 255) const [r, g, b, a] = hexToRgba (colour, 255)
floodFill (imgData, Math.floor (pos.x), Math.floor (pos.y), { r, g, b, a }) floodFill (imgData, Math.floor (pos.x), Math.floor (pos.y), { r, g, b, a })
ctx.putImageData (imgData, 0, 0) ctx!.putImageData (imgData, 0, 0)
const prevImageSrc = layer.image?.src
const nextSrc = $off.toDataURL ('image/png') const nextSrc = $off.toDataURL ('image/png')
updateActiveLayerHistory ([...layer.history, layer.lines]) updateActiveLayerHistory ([...layer.history, layer.lines])
@@ -347,11 +334,7 @@ export default () => {
if (!(Array.isArray (parsed))) if (!(Array.isArray (parsed)))
throw new Error throw new Error
const restored: Layer[] = parsed.filter (isLayer).map (l => ({ const restored: Layer[] = parsed.filter (isLayer)
...l, lines: l.lines.map (s => ({
...s, mode: (Object.values (Mode).includes (s.mode)
? s.mode
: Mode.Pen) })) }))
if (restored.length === 0) if (restored.length === 0)
throw new Error throw new Error