This commit is contained in:
@@ -116,6 +116,7 @@ const isLayer = (obj: unknown): obj is Layer => (
|
||||
export default () => {
|
||||
const drawingRef = useRef (false)
|
||||
const fileInputRef = useRef<HTMLInputElement> (null)
|
||||
const layersRef = useRef<Record<string, Konva.Layer>> ({ })
|
||||
const stageRef = useRef<Konva.Stage | null> (null)
|
||||
|
||||
const [activeLayerId, setActiveLayerId] = useState<string | null> (null)
|
||||
@@ -125,6 +126,7 @@ export default () => {
|
||||
const [layers, setLayers] = useState<Layer[]> ([])
|
||||
const [mode, setMode] = useState<Mode> (Mode.Pen)
|
||||
const [pointSize, setPointSize] = useState (3)
|
||||
const [singleLayer, setSingleLayer] = useState (false)
|
||||
const [stageHeight, setStageHeight] = useState (480)
|
||||
const [stageWidth, setStageWidth] = useState (480)
|
||||
|
||||
@@ -210,37 +212,31 @@ export default () => {
|
||||
fileInputRef.current.value = ''
|
||||
}
|
||||
|
||||
const handlePaint = async () => {
|
||||
const handlePaint = (ev: Konva.KonvaEventObject<PointerEvent | MouseEvent | TouchEvent>) => {
|
||||
const layer = activeLayer
|
||||
if (!(layer) || !(stageRef.current))
|
||||
if (!(layer) || !(layersRef.current?.[layer.id]))
|
||||
return
|
||||
|
||||
const stage = stageRef.current
|
||||
const pos = stage.getPointerPosition ()
|
||||
const pos = ev.target.getStage ()?.getPointerPosition ()
|
||||
if (!(pos))
|
||||
return
|
||||
|
||||
const dataURL = stage.toDataURL ({ mimeType: 'image/png', pixelRatio: 1 })
|
||||
const stage = layersRef.current[layer.id]
|
||||
if (!(stage))
|
||||
return
|
||||
|
||||
const img = new window.Image
|
||||
img.crossOrigin = 'anonymous'
|
||||
await new Promise<void> (res => {
|
||||
img.onload = () => res ()
|
||||
img.src = dataURL
|
||||
})
|
||||
if (drawingRef.current)
|
||||
return
|
||||
|
||||
const $off = document.createElement ('canvas')
|
||||
$off.width = stageWidth
|
||||
$off.height = stageHeight
|
||||
const ctx = $off.getContext ('2d')
|
||||
ctx!.drawImage (img, 0, 0, stageWidth, stageHeight)
|
||||
drawingRef.current = true
|
||||
|
||||
const off = stage.toCanvas ({ pixelRatio: 1 })
|
||||
const ctx = off.getContext ('2d')!
|
||||
const imgData = ctx.getImageData (0, 0, off.width, off.height)
|
||||
|
||||
const imgData = ctx!.getImageData (0, 0, stageWidth, stageHeight)
|
||||
const [r, g, b, a] = hexToRgba (colour, 255)
|
||||
floodFill (imgData, Math.floor (pos.x), Math.floor (pos.y), { r, g, b, a })
|
||||
ctx!.putImageData (imgData, 0, 0)
|
||||
|
||||
const nextSrc = $off.toDataURL ('image/png')
|
||||
ctx.putImageData (imgData, 0, 0)
|
||||
|
||||
updateActiveLayerHistory ([...layer.history, layer.lines])
|
||||
updateActiveLayerFuture ([])
|
||||
@@ -251,7 +247,9 @@ export default () => {
|
||||
{ mode: Mode.Paint,
|
||||
points: [pos.x, pos.y],
|
||||
stroke: colour,
|
||||
imageSrc: nextSrc }] }) : l))
|
||||
imageSrc: off.toDataURL ('image/png') }] }) : l))
|
||||
|
||||
drawingRef.current = false
|
||||
}
|
||||
|
||||
const updateActiveLayerLines = (lines: Line[]) => {
|
||||
@@ -537,11 +535,19 @@ export default () => {
|
||||
追加
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<label>
|
||||
<input type="checkbox"
|
||||
checked={singleLayer}
|
||||
onChange={ev => setSingleLayer (ev.target.checked)} />
|
||||
レイアを分けて表示
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div className="w-full flex items-center justify-center mb-16">
|
||||
<div className="border border-black dark:border-white">
|
||||
<Stage ref={node => {
|
||||
<Stage className="touch-none"
|
||||
ref={node => {
|
||||
stageRef.current = node
|
||||
}}
|
||||
width={stageWidth}
|
||||
@@ -561,8 +567,11 @@ export default () => {
|
||||
listening={false} />
|
||||
</Layer>
|
||||
|
||||
{layers.map (layer => (
|
||||
<Layer key={layer.id}>
|
||||
{layers.map (layer => (!(singleLayer) || layer.id === activeLayerId) && (
|
||||
<Layer key={layer.id} ref={node => {
|
||||
if (node)
|
||||
layersRef.current = { ...layersRef.current, [layer.id]: node }
|
||||
}}>
|
||||
{images[layer.id] && (
|
||||
<Image image={images[layer.id]}
|
||||
x={0}
|
||||
@@ -587,7 +596,8 @@ export default () => {
|
||||
: 'source-over'} />)
|
||||
case Mode.Paint:
|
||||
return (
|
||||
<Image image={images[line.imageSrc]}
|
||||
<Image key={i}
|
||||
image={images[line.imageSrc]}
|
||||
x={0}
|
||||
y={0}
|
||||
scaleX={1}
|
||||
|
||||
Reference in New Issue
Block a user