Search code examples
reactjscreateelementrescript

Rescript-react: Creating a hidden canvas element


I am creating a simple react app (HTML) that allows a user to browse to an image on their local pc, and then displays it in an image tag. I want to take a data-url and dynamically create a hidden canvas tag (open to a different approach, but I want to resize the image, not set size contraints on the tag displaying the image). Here is my resize code

MyComponent.res (offending code)

let resize = dataUrl => {
    let canvas = React.createElement(_ => React.string("canvas"), {"style": "display: none;"})
    canvas.getContext("2d");
    dataUrl
}

The error

  We've found a bug for you!
  /Users/n0321437/projects/rescript-react/from-local-template/src/Upload.res:14:12-21

  12 │     let canvas = React.createElement(_ => React.string("canvas"), {"sty
     │ le": "display: none;"})
  13 │     //let myCanvas = canvas([React.null])
  14 │     canvas.getContext("2d");
  15 │     dataUrl
  16 │ }

The record field getContext can't be found.

I haven't found a much documentation or postings on using createElement or createElementVariadic - so I am guessing here. It looks as though createElement returns an object of type element but there are no associated methods:

React.res

type element
external createElement: (component<'props>, 'props) => element = "createElement"

So I guess there are a couple of questions

  1. Have i infact created an element that would represent the HTML Object of Canvas?
  2. If I have done so, how do I call methods on that code?
  3. If I have not, how do I create a hidden Canvas object?
  4. FInally how might one navigate the documentation and source to discover this on their own?

Solution

  • React is a library that provides a declarative API for creating, inserting and updating the DOM by way of a virtual DOM. React.createElement is an internal API used to create virtual DOM elements.

    What you seem to want is to create an actual DOM element, and then NOT insert it into DOM. React is not designed to do this.

    Instead what you want is bindings to the DOM API, which you could make yourself if you only need a few of its features, or you could use a full-blown set of DOM bindings such as rescript-webapi, which conveniently also includes bindings for Canvas.

    This is how you'd create a canvas element:

    open Webapi.Dom
    
    let canvas = document->Document.createElement("canvas")
    

    then to get the canvas context you'd use:

    open Webapi.Canvas
    let context = canvas->CanvasElement.getContext2d
    

    then use the functions in Canvas2d to do what you want:

    let image = context->Canvas2d.createImageDataCoords(~width=100, ~height=100)
    ...
    context->Canvas2d.putImage(image, ~dx=0, ~dy=0)