I have a pixi canvas with pointer handlers. You can click on a point on a ‘sequence’ and move it.
The mouse handlers had stale state. To fix it I am recreating the handlers whenever the sequence is modified, so that they always have fresh state. This fixed the state bug. But it doesn’t work if the state is modified on mouse up. Creating new handlers from a within a handler understandably preserves the stale state, even via a callback timer. So now all the bugs are fixed except that you can't drag a point twice :)
I am new to React and feel like I am going about this all wrong. Any suggestions?
This is how I get the sequence state:
const SequenceCanvas = React.forwardRef((props: any, ref) => {
const canvasRef = useRef(null)
const sequence: Sequence = useSequenceStore(state => { return state.sequence} )
Here is now I recreate the handlers:
const addHandlers = () : void => {
console.log(`new mouse handlers: numsteps ${sequence.numSteps}`)
parentContainer.removeAllListeners()
parentContainer.on('pointerdown', (e: any) => {
handlePointerDown(e)
})
parentContainer.on('dblclick', (e: any) => {
handleDoubleClick(e)
})
parentContainer.on('pointerup', (e: any) => {
handlePointerUp(e)
})
parentContainer.on('mouseupoutside', (e: any) => {
handlePointerUp(e)
})
parentContainer.on('pointermove', (e: any) => {
handlePointerMove(e)
})
}
useEffect(() => {
if (!mouseIsDown) {
// Recreate mouse handlers each time the sequence changes. Otherwise the sequence state is stale
addHandlers()
}
}, [sequence]);
const handlePointerUp = (e: any) => {
console.log(`handlePointerUp ${mouseIsDown}`)
mouseIsDown = false;
dragStepNum = -1
isDraggingVertical = false;
isDraggingHorizontal = false;
setTimeout(() => {
addHandlers()
}, 100)
}
Here is an example of stale state. The sequence
object here is stale unless I recreate the pointer handler each time the sequence changes.
const handlePointerMoveImp = (e: any) => {
const sequence = useSequenceStore.getState().sequence
if (mouseIsDown) {
var x = e.data.global.x
var y = e.data.global.y
if (x !== null && y !== null && x !== Infinity && y !== Infinity) {
// console.log(`drag ${JSON.stringify(e.data)}`)
if (dragTarget === DragTargets.EnvelopePoint) {
console.log(`handlePointerMoveImp - drag target is EnvelopePoint - tapPointNum ${tapPointNum}`)
const midiOutputDeviceName : string = sequence.midiSettings.midiOutputDeviceName
const midiChart:MidiChart = findMidiChart(midiOutputDeviceName, midiMaps)
const envelope = findEnvelope(sequence.currentEnvelopeId);
if (envelope) {
// const point = envelope.points[tapPointNum]
const controllerInfo: ControllerInfo = MidiDeviceDataService.getControllerInfo(midiChart, envelope.controller)
const time = Math.max(getXTime(sequence, x), 0)
const value: number = getYValue(sequence, y, controllerInfo.min, controllerInfo.max)
console.log(`handlePointerMoveImp - drag EnvelopePoint to ${time}/${value} - envelope <${sequence.currentEnvelopeId}>`)
moveEnvelopePoint(sequence.currentEnvelopeId, tapPointNum, time, value)
}
}