Skip to content

Example with modal, aspect ratio, and hooks #44

@aidanlister

Description

@aidanlister

Here's an example of using this package with react hooks, in case it helps someone:

import React, { useState, useRef, useCallback } from 'react'
import PropTypes from 'prop-types'
import SignatureCanvas from 'react-signature-canvas'
import Modal, { Footer } from 'apps/core/frontend/widgets/modal'

const ModalSignatureCanvas = ({onSave, widthRatio, canvasProps}) => {
  const [isVisible, setIsVisible] = useState(false)
  const [signatureResult, setSignatureResult] = useState('')
  const sigCanvas = useRef({})
  const sigPad = useRef({})

  const saveInput = () => {
    const dataURL = sigCanvas.current.toDataURL()
    setSignatureResult(dataURL)
    onSave(dataURL)
    setIsVisible(!isVisible)
  }
  const clearInput = () => sigPad.current.clear()

  const measuredRef = useCallback(node => {
    const resizeCanvas = (signaturePad, canvas) => {
      canvas.width = canvas.parentElement.clientWidth // width of the .canvasWrapper
      canvas.height = canvas.parentElement.clientWidth / widthRatio
      signaturePad.clear()
    }

    if (node !== null) {
      sigCanvas.current = node.getCanvas()
      sigPad.current = node.getSignaturePad()
      resizeCanvas(node.getSignaturePad(), node.getCanvas())
    }
  }, [widthRatio])

  const buttonText = signatureResult ? 'Signature changed' : 'Change signature'

  return (
    <>
      <button type="button" className="btn btn-secondary btn-sm" onClick={() => setIsVisible(true)}>{buttonText}</button>
      {isVisible &&
        <Modal
          title="Enter your signature"
          onHide={() => setIsVisible(false)}
        >
          <div className="canvasWrapper">
            <SignatureCanvas canvasProps={canvasProps} ref={measuredRef} />
          </div>
          <Footer>
            <div className="btn-group btn-block">
              <button type="button" className="btn btn-secondary w-50" onClick={clearInput}>Clear</button>
              <button type="button" className="btn btn-primary w-50" onClick={saveInput}>Save</button>
            </div>
          </Footer>
        </Modal>}
    </>
  )
}
ModalSignatureCanvas.propTypes = {
  canvasProps: PropTypes.object,
  widthRatio: PropTypes.number.isRequired,
  onSave: PropTypes.func,
}

export default ModalSignatureCanvas

You can see there's some tricky bits, eg I had to use useCallback for the ref instead of just passing a ref, so that I could call resizeCanvas() immediately after the first render.

I wanted the canvas to have the same aspect ratio no matter what the container, so rather than specifying a canvas width I specify an aspect ratio.

Additionally, calling canvas.getContext('2d').scale(ratio, ratio) seemed to cause scaling issues rather than solving those scaling issues, so I disabled it here.

Finally, for some reason, sigCanvas.current.toDataURL('image/svg+xml') just exports PNG not SVG ... any tips on that would be handy.

Metadata

Metadata

Assignees

No one assigned

    Labels

    abusivecontains abusive contentkind: supportAsking for support with something or a specific use casescope: exampleAn example or examples could be improved

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions