embiem / react-canvas-draw

React Component for drawing in canvas
https://embiem.github.io/react-canvas-draw/
MIT License
902 stars 315 forks source link

Is there a way to access canvas context methods? #68

Closed ps2-controller closed 4 years ago

ps2-controller commented 4 years ago

Hi, thanks so much for making this library! I was wondering - is there a way to access methods such as beginDraw() on the underlying canvas context? Ideally I'd like to do something like this

let canvasRef = useRef()
let c = canvas.[[something here?]] -- similar to let c = document.getElementById("canvas")
let context = c.getContext('2d')

let someFunction = (x0, y0, x1, y1, color, radius) => {
    context.beginPath();
    context.moveTo(x0, y0); // x0 and y0 are starting coordinates
    context.lineTo(x1, y1); // x1 and y1 are coordinates to draw
    context.strokeStyle = color;
    context.lineWidth = radius;
    context.stroke();
    context.closePath();
}

// some trigger to call the function
return (
    <CanvasDraw ref={canvasRef} />
)

reference: https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/beginPath

ps2-controller commented 4 years ago

Figured it out :) accessing context.handleMouseDown and context.handlePointerMove gets the job mostly done for me.

petedejoy commented 4 years ago

Hey @ps2-controller - can you give some more context on what you did to make this work? I'm trying to access the default onDoubleClick prop of the canvas that you can otherwise access by baking a vanilla canvas tag into a React component. Something like:

  <CanvasDraw
          ref={(canvasDraw) => (this.saveableCanvas = canvasDraw)}
          brushColor={strokeStyle}
          brushRadius={8}
          imgSrc={path}
          lazyRadius={10}
          canvasWidth={parseInt(width, 10)}
          canvasHeight={parseInt(height, 10)}
          disabled={disabled}
          onDoubleClick={this.onDoubleClick}
      />

Any idea how I'd go about setting that up so that I can access that method? Note that it works when I pass that onDoubleClick prop directly to a tag.

ps2-controller commented 4 years ago

Hmm, not sure - My workaround actually involves calling react-canvas-draw's own implemented wrapper functions such as this one

I call that as follows:

const callUnderlyingMethod = () => {

  let context = canvasRef.current

  // literally empty, as react-canvas-draw's function requires a preventDefault fxn as a param
  let someFunction = () => { } 

  context.handleMouseDown({preventDefault: someFunction})
}

return (
              <CanvasDraw 
                    ref={canvasRef}
                    brushRadius={brushRadius}
                    brushColor={brushColor}
                />
)

This works for my use-case since I'm using websockets to draw an image based on events instead of the user's manual mouse clicks, so I'm using the same functions react-canvas-draw already exposes. (You can check it out at https://demondoodle.com, but the source code isn't public yet)

However, it looks like you want to go a layer lower and call a directly unexposed method on the canvas itself. I'm not sure how that works with this library. It's especially complicated because react-canvas-draw seems to be using four html canvases under the hood. One slightly tacky option might be wrapping your in a tag and calling onDoubleClick when the span is doubleclicked:

<span onDoubleClick={() => this.onDoubleClick()} >
  <CanvasDraw
          ref={(canvasDraw) => (this.saveableCanvas = canvasDraw)}
          brushColor={strokeStyle}
          brushRadius={8}
          imgSrc={path}
          lazyRadius={10}
          canvasWidth={parseInt(width, 10)}
          canvasHeight={parseInt(height, 10)}
          disabled={disabled}
          onDoubleClick={this.onDoubleClick}
      />
</span>

Otherwise, not sure :( Hope that's helpful!

petedejoy commented 4 years ago

That is helpful- thanks a bunch! Ended up wrapping the CanvasDraw component in a div that takes my onDoubleClick custom event. Seems to be working alright.

ps2-controller commented 4 years ago

Awesome, glad to hear it :)