19

I made a color picker with React and Canvas. Currently the components are rendered in React and canvas is done with vanilla javascript. I'd like to two to mesh more, so I want the click events to be handled with React.

For example, this

colorStrip.addEventListener("click", click, false);

function click(e) {
  x = e.offsetX;
  y = e.offsetY;
  var imageData = context.getImageData(x, y, 1, 1).data;
  rgbaColor = 'rgba(' + imageData[0] + ',' + imageData[1] + ',' + imageData[2] + ',1)';
  fillGradient();
}

I would hope would be able to translate to this

var ColorPicker = React.createClass({
  colorStripClick: function() {
    //handle click events here
  },
  render: function() {
    var styles = {
      opacity: this.props.isVisible ? '1' : '0'
    };
    return(
      <div id="color-picker" style={styles}>
        <canvas id="color-block" height="150" width="150"></canvas>
        <canvas id="color-strip" height="150" width="30" onClick={this.colorStripClick}></canvas>
      </div>
    );
  }
});

But that doesn't work because I don't know how to access context. How can I get access to the canvas properties with React? Is there a way to access it before the click?

UPDATE

I used David's answer but I was getting errors by putting a function in ref so I did ref="canvasBlock" and ref="canvasStrip" instead and then assigned the context in componentDidMount

cocoa
  • 3,636
  • 7
  • 28
  • 56
  • I made a similar project https://github.com/gibbok/react-color-picker-palette you can look on how to access your context in this example for function getDrawingContex() {: https://github.com/gibbok/react-color-picker-palette/blob/master/ColorPickerPalette.jsx – GibboK Jul 06 '16 at 06:42
  • in the function by David you have to add "if (c == null)" I guess because you get the element reference just once on mount, not on rerenders. – Aus Jul 27 '16 at 08:59

6 Answers6

31

In accordance to React16 You can use React.createRef()

class ColorPicker extends React.Component {
constructor(props) {
   super(props);

   this.colorPickerRef = React.createRef();
}

componentDidMount() {
   this.context = this.colorPickerRef.current.getContext('2d');
}

render() {
   return (
      <canvas ref={this.colorPickerRef} />
   )
}
}
Alex S
  • 451
  • 4
  • 6
20

You can add a ref function attribute on the canvas element:

<canvas id="color-strip" ref={(c) => this.context = c.getContext('2d')} height="...

Then you’ll have access to the context through this.context:

colorStripClick: function() {
    var imageData = this.context.getImageData(x, y, 1, 1).data
}

You can also use the event object to access to DOM node as already pointed out, but this way you’ll have access from anywhere, not just event handlers.

David Hellsing
  • 102,045
  • 43
  • 170
  • 208
12

Here is the answer with react hooks:

import { useEffect, useRef } from 'react'

export default function Canvas() {
  const ref = useRef()

  useEffect(() => {
    const canvas = ref.current.getContext('2d')

    // do something here with the canvas
  }, [])

  return <canvas ref={ref} />
}
Fernando Rojo
  • 1,533
  • 14
  • 16
1

It should just be accessing the target of the click

colorStripClick: function(e) {
  var ctx = e.target.getContext('2d')
}
PhilVarg
  • 4,613
  • 2
  • 18
  • 34
1

Like this

colorStripClick: function (e) {
    var context = e.currentTarget.getContext('2d');
    // your code
}

Example

Oleksandr T.
  • 73,526
  • 17
  • 164
  • 143
1

Here's the React way to remove a canvas from your component:

const canvas = ReactDOM.findDOMNode(this.refs.canvas); const context = canvas.getContext('2d'); ctx.clearRect(0, 0, canvas.width, canvas.height);

As long as you can target the DOM Node the react way, you can pretty much access the Canvas Rendering API.

Tamizaan
  • 11
  • 2