context.putImageData() 在 React 中不起作用
context.putImageData() Not working in React
我正在尝试在 React 中创建一个绘图应用程序,它的大部分工作正常。但是当我尝试添加一个撤消按钮时它不起作用。
我尝试使用此 finishDrawing()
函数制作撤消按钮,我在其中使用 getImageData 并将其存储在名为 restore_array
的数组中
const finishDrawing = () => {
//console.log(contextRef.current)
contextRef.current.closePath()
setIsDrawing(false)
//restore_array.push(contextRef.current.getImageData(0, 0,400,256+80))
setIndex_array(index_array + 1)
setRestore_Array((prevState) => { return [...prevState, contextRef.current.getImageData(0, 0,400,256+80)]})
console.log(restore_array, restore_array.length)
}
然后,当单击“撤消”按钮时,我尝试使用 useEffect
在 restore_array
中重新加载此图像,这应该使用之前的图像 [=] 重新渲染主菜 canvas 20=]
function undoLast() {
console.log(restore_array[index_array], index_array, restore_array)
if (index_array > -1) {
setIndex_array(index_array-1)
restore_array.pop()
setLines(!lines)
}
//contextRef.current.putImageData(restore_array[index_array-1], 0, 0)
}
和
useEffect(() => {
console.log('use effect 3c')
console.log(restore_array)
const canvas = canvasRef.current;
const context = canvas.getContext("2d")
context.lineWidth = thick
context.lineCap = "round"
context.strokeStyle = colour
if (restore_array.length === 0) {
console.log('empty')
return
}
//context.clearRect(0,0,400,256+80)
//context.fillRect(0,0,400,256+80)
context.putImageData(restore_array[index_array], 0, 0, 0, 0, 400, 256+80)
contextRef.current = context
}, [lines])
有谁知道为什么我的 putImageData
在这种情况下不起作用?
这是我的全部代码供参考
import React, { useEffect, useRef, useState } from "react";
function DrawCanvas() {
const canvasRef = useRef(null)
const contextRef = useRef(null)
const [isDrawing, setIsDrawing] = useState(false)
const [colour, setColour] = useState('black')
const [prcolour, setPrColour] = useState(null)
const [thick, setThick] = useState(3)
const [image, setImage] = useState(null)
const [restore_array, setRestore_Array] = useState([])
const [index_array, setIndex_array] = useState(-1)
const [clear_, setClear_] = useState(true)
const [lines, setLines] = useState(true)
//let restore_array = []
useEffect(() => {
const canvas = canvasRef.current;
canvas.width = window.innerWidth/1.5 ;
canvas.height = window.innerHeight/1.5 ;
canvas.style.width = `${window.innerWidth/3}px`;
canvas.style.height = `${window.innerHeight/3}px`;
const context = canvas.getContext("2d")
context.scale(2,2)
context.lineCap = "round"
context.lineWidth = 3
context.strokeStyle = "black"
//const img = DogImage
context.fillStyle = 'gray'
context.fillRect(0,0,400,256+80)
contextRef.current = context
}, [])
useEffect(() => {
console.log('use effect 1a')
const canvas = canvasRef.current;
const context = canvas.getContext("2d")
context.lineWidth = thick
context.lineCap = "round"
context.strokeStyle = colour
contextRef.current = context
document.getElementById(colour).style.borderColor = 'gray'
if(prcolour === null) {
return
}
document.getElementById(prcolour).style.borderColor = 'black'
document.getElementById(prcolour).style.borderWidth = '3px'
}, [colour])
useEffect(() => {
console.log('use effect 2b')
const canvas = canvasRef.current;
const context = canvas.getContext("2d")
context.lineWidth = thick
context.lineCap = "round"
context.strokeStyle = colour
const Dogimage = new Image();
Dogimage.src = '../../images/dog-without-labels.png'
Dogimage.onLoad = () => {
console.log('load image')
context.current.drawImage(Dogimage, 0, 0,400,256+80);
}
contextRef.current = context
}, [thick])
useEffect(() => {
console.log('use effect 3c')
console.log(restore_array)
const canvas = canvasRef.current;
const context = canvas.getContext("2d")
context.lineWidth = thick
context.lineCap = "round"
context.strokeStyle = colour
if (restore_array.length === 0) {
console.log('empty')
return
}
//context.clearRect(0,0,400,256+80)
//context.fillRect(0,0,400,256+80)
context.putImageData(restore_array[index_array], 0, 0, 0, 0, 400, 256+80)
contextRef.current = context
}, [lines])
useEffect(() => {
console.log('use effect 4d')
const canvas = canvasRef.current;
const context = canvas.getContext("2d")
//contextRef.fillStyle = 'gray'
context.lineWidth = thick
context.lineCap = "round"
context.strokeStyle = colour
context.clearRect(0,0,400,256+80)
context.fillRect(0,0,400,256+80)
contextRef.current = context
}, [clear_])
function undoLast() {
console.log(restore_array[index_array], index_array, restore_array)
if (index_array > -1) {
setIndex_array(index_array-1)
restore_array.pop()
setLines(!lines)
}
//contextRef.current.putImageData(restore_array[index_array-1], 0, 0)
}
const clearCanvas = () => {
setClear_(!clear_)
}
const startDrawing = ({nativeEvent}) => {
const {offsetX, offsetY} = nativeEvent
contextRef.current.beginPath()
contextRef.current.moveTo(offsetX, offsetY)
setIsDrawing(true)
}
const finishDrawing = () => {
//console.log(contextRef.current)
contextRef.current.closePath()
setIsDrawing(false)
//restore_array.push(contextRef.current.getImageData(0, 0,400,256+80))
setIndex_array(index_array + 1)
setRestore_Array((prevState) => { return [...prevState, contextRef.current.getImageData(0, 0,400,256+80)]})
console.log(restore_array, restore_array.length)
}
const draw = ({nativeEvent}) => {
if (!isDrawing) {
return
}
const {offsetX, offsetY} = nativeEvent;
contextRef.current.lineTo(offsetX, offsetY)
contextRef.current.stroke()
}
const colourChange = (value) => {
setPrColour(colour)
setColour(value)
}
const thickChange = (event) => {
setThick(event)
}
return (
<div>
<div className="left">
<canvas className="canvas" onMouseDown={startDrawing}
onMouseUp={finishDrawing}
onMouseMove={draw}
ref={canvasRef}/>
</div>
<div className="right">
<h5><dt>Chart Draw</dt></h5>
<p>Use your finger or your mouse to draw directly on the chart opposite.</p>
<button className="draw">Draw</button>
<button className="select">Select</button>
<p><dt>Line thickness: {thick} </dt> </p>
<input className="slider" type="range" min="1" max="19" value={thick} class="slider" id="myRange" step="1" onChange={(event)=>thickChange(event.target.value)}></input>
<button className='red' id='red'onClick={() => colourChange('red')}> </button>
<button className='black' id='black' onClick={() => colourChange('black')}> </button>
<button className='yellow' id='rgba(204,153,0,255)' onClick={() => colourChange('rgba(204,153,0,255)')}> </button>
<button className='blue' id='rgba(1,102,255,255)' onClick={() => colourChange('rgba(1,102,255,255)')}> </button>
<button className="undoButton" onClick={()=>undoLast()}> <dt> Undo/Back a step</dt></button>
<button className="undoButton" onClick={()=>clearCanvas()}> <dt> Clear canvas</dt></button>
<button className="savecloseButton"> <dt>Save and Close</dt></button>
</div>
</div>
)
}
export default DrawCanvas;
你的代码对我来说“没问题”...
我认为很明显你的 putImageData
函数 undoLast 被注释了。
我假设这是故意的,而不是实际问题。
我们可以看到它在这里工作:
是的,只有一部分是撤消。
那是因为您在 getImageData:
中有硬编码值
setRestore_Array((prevState) => {
return [...prevState, contextRef.current.getImageData(0, 0,400,256+80)]
})
那只获得了 canvas 的一部分,所以只有那部分正在恢复...
如果您需要整个 canvas,请将其更改为使用 canvas 维度。
类似于:
setRestore_Array((prevState) => {
return [...prevState, contextRef.current.getImageData(0, 0, canvasRef.current.width, canvasRef.current.height)]
})
另外你应该看看提到的,他有一个很好的观点:
storing an Array of drawing commands will cause your memory to explode
对于使用图像数据的方法,我的建议是将撤消操作限制在一个固定数量,例如 10 次并丢弃旧的,这将保证内存消耗上限并防止任何内存不足错误。
我正在尝试在 React 中创建一个绘图应用程序,它的大部分工作正常。但是当我尝试添加一个撤消按钮时它不起作用。
我尝试使用此 finishDrawing()
函数制作撤消按钮,我在其中使用 getImageData 并将其存储在名为 restore_array
const finishDrawing = () => {
//console.log(contextRef.current)
contextRef.current.closePath()
setIsDrawing(false)
//restore_array.push(contextRef.current.getImageData(0, 0,400,256+80))
setIndex_array(index_array + 1)
setRestore_Array((prevState) => { return [...prevState, contextRef.current.getImageData(0, 0,400,256+80)]})
console.log(restore_array, restore_array.length)
}
然后,当单击“撤消”按钮时,我尝试使用 useEffect
在 restore_array
中重新加载此图像,这应该使用之前的图像 [=] 重新渲染主菜 canvas 20=]
function undoLast() {
console.log(restore_array[index_array], index_array, restore_array)
if (index_array > -1) {
setIndex_array(index_array-1)
restore_array.pop()
setLines(!lines)
}
//contextRef.current.putImageData(restore_array[index_array-1], 0, 0)
}
和
useEffect(() => {
console.log('use effect 3c')
console.log(restore_array)
const canvas = canvasRef.current;
const context = canvas.getContext("2d")
context.lineWidth = thick
context.lineCap = "round"
context.strokeStyle = colour
if (restore_array.length === 0) {
console.log('empty')
return
}
//context.clearRect(0,0,400,256+80)
//context.fillRect(0,0,400,256+80)
context.putImageData(restore_array[index_array], 0, 0, 0, 0, 400, 256+80)
contextRef.current = context
}, [lines])
有谁知道为什么我的 putImageData
在这种情况下不起作用?
这是我的全部代码供参考
import React, { useEffect, useRef, useState } from "react";
function DrawCanvas() {
const canvasRef = useRef(null)
const contextRef = useRef(null)
const [isDrawing, setIsDrawing] = useState(false)
const [colour, setColour] = useState('black')
const [prcolour, setPrColour] = useState(null)
const [thick, setThick] = useState(3)
const [image, setImage] = useState(null)
const [restore_array, setRestore_Array] = useState([])
const [index_array, setIndex_array] = useState(-1)
const [clear_, setClear_] = useState(true)
const [lines, setLines] = useState(true)
//let restore_array = []
useEffect(() => {
const canvas = canvasRef.current;
canvas.width = window.innerWidth/1.5 ;
canvas.height = window.innerHeight/1.5 ;
canvas.style.width = `${window.innerWidth/3}px`;
canvas.style.height = `${window.innerHeight/3}px`;
const context = canvas.getContext("2d")
context.scale(2,2)
context.lineCap = "round"
context.lineWidth = 3
context.strokeStyle = "black"
//const img = DogImage
context.fillStyle = 'gray'
context.fillRect(0,0,400,256+80)
contextRef.current = context
}, [])
useEffect(() => {
console.log('use effect 1a')
const canvas = canvasRef.current;
const context = canvas.getContext("2d")
context.lineWidth = thick
context.lineCap = "round"
context.strokeStyle = colour
contextRef.current = context
document.getElementById(colour).style.borderColor = 'gray'
if(prcolour === null) {
return
}
document.getElementById(prcolour).style.borderColor = 'black'
document.getElementById(prcolour).style.borderWidth = '3px'
}, [colour])
useEffect(() => {
console.log('use effect 2b')
const canvas = canvasRef.current;
const context = canvas.getContext("2d")
context.lineWidth = thick
context.lineCap = "round"
context.strokeStyle = colour
const Dogimage = new Image();
Dogimage.src = '../../images/dog-without-labels.png'
Dogimage.onLoad = () => {
console.log('load image')
context.current.drawImage(Dogimage, 0, 0,400,256+80);
}
contextRef.current = context
}, [thick])
useEffect(() => {
console.log('use effect 3c')
console.log(restore_array)
const canvas = canvasRef.current;
const context = canvas.getContext("2d")
context.lineWidth = thick
context.lineCap = "round"
context.strokeStyle = colour
if (restore_array.length === 0) {
console.log('empty')
return
}
//context.clearRect(0,0,400,256+80)
//context.fillRect(0,0,400,256+80)
context.putImageData(restore_array[index_array], 0, 0, 0, 0, 400, 256+80)
contextRef.current = context
}, [lines])
useEffect(() => {
console.log('use effect 4d')
const canvas = canvasRef.current;
const context = canvas.getContext("2d")
//contextRef.fillStyle = 'gray'
context.lineWidth = thick
context.lineCap = "round"
context.strokeStyle = colour
context.clearRect(0,0,400,256+80)
context.fillRect(0,0,400,256+80)
contextRef.current = context
}, [clear_])
function undoLast() {
console.log(restore_array[index_array], index_array, restore_array)
if (index_array > -1) {
setIndex_array(index_array-1)
restore_array.pop()
setLines(!lines)
}
//contextRef.current.putImageData(restore_array[index_array-1], 0, 0)
}
const clearCanvas = () => {
setClear_(!clear_)
}
const startDrawing = ({nativeEvent}) => {
const {offsetX, offsetY} = nativeEvent
contextRef.current.beginPath()
contextRef.current.moveTo(offsetX, offsetY)
setIsDrawing(true)
}
const finishDrawing = () => {
//console.log(contextRef.current)
contextRef.current.closePath()
setIsDrawing(false)
//restore_array.push(contextRef.current.getImageData(0, 0,400,256+80))
setIndex_array(index_array + 1)
setRestore_Array((prevState) => { return [...prevState, contextRef.current.getImageData(0, 0,400,256+80)]})
console.log(restore_array, restore_array.length)
}
const draw = ({nativeEvent}) => {
if (!isDrawing) {
return
}
const {offsetX, offsetY} = nativeEvent;
contextRef.current.lineTo(offsetX, offsetY)
contextRef.current.stroke()
}
const colourChange = (value) => {
setPrColour(colour)
setColour(value)
}
const thickChange = (event) => {
setThick(event)
}
return (
<div>
<div className="left">
<canvas className="canvas" onMouseDown={startDrawing}
onMouseUp={finishDrawing}
onMouseMove={draw}
ref={canvasRef}/>
</div>
<div className="right">
<h5><dt>Chart Draw</dt></h5>
<p>Use your finger or your mouse to draw directly on the chart opposite.</p>
<button className="draw">Draw</button>
<button className="select">Select</button>
<p><dt>Line thickness: {thick} </dt> </p>
<input className="slider" type="range" min="1" max="19" value={thick} class="slider" id="myRange" step="1" onChange={(event)=>thickChange(event.target.value)}></input>
<button className='red' id='red'onClick={() => colourChange('red')}> </button>
<button className='black' id='black' onClick={() => colourChange('black')}> </button>
<button className='yellow' id='rgba(204,153,0,255)' onClick={() => colourChange('rgba(204,153,0,255)')}> </button>
<button className='blue' id='rgba(1,102,255,255)' onClick={() => colourChange('rgba(1,102,255,255)')}> </button>
<button className="undoButton" onClick={()=>undoLast()}> <dt> Undo/Back a step</dt></button>
<button className="undoButton" onClick={()=>clearCanvas()}> <dt> Clear canvas</dt></button>
<button className="savecloseButton"> <dt>Save and Close</dt></button>
</div>
</div>
)
}
export default DrawCanvas;
你的代码对我来说“没问题”...
我认为很明显你的 putImageData
函数 undoLast 被注释了。
我假设这是故意的,而不是实际问题。
我们可以看到它在这里工作:
是的,只有一部分是撤消。
那是因为您在 getImageData:
setRestore_Array((prevState) => {
return [...prevState, contextRef.current.getImageData(0, 0,400,256+80)]
})
那只获得了 canvas 的一部分,所以只有那部分正在恢复...
如果您需要整个 canvas,请将其更改为使用 canvas 维度。
类似于:
setRestore_Array((prevState) => {
return [...prevState, contextRef.current.getImageData(0, 0, canvasRef.current.width, canvasRef.current.height)]
})
另外你应该看看
storing an Array of drawing commands will cause your memory to explode
对于使用图像数据的方法,我的建议是将撤消操作限制在一个固定数量,例如 10 次并丢弃旧的,这将保证内存消耗上限并防止任何内存不足错误。