GithubHelp home page GithubHelp logo

agilgur5 / react-signature-canvas Goto Github PK

View Code? Open in Web Editor NEW

This project forked from blackjk3/react-signature-pad

517.0 5.0 115.0 1.21 MB

A React wrapper component around signature_pad (in < 150 LoC). Unopinionated and heavily updated fork of react-signature-pad

Home Page: https://agilgur5.github.io/react-signature-canvas/

License: Other

JavaScript 13.66% HTML 0.84% CSS 2.34% TypeScript 83.16%
react signature pad canvas trim whitespace sign e-signature e-sign signature-pad wrapper react-signature-pad

react-signature-canvas's Introduction

react-signature-canvas

package-json releases commits
dt dy dm dw
typings build status code coverage

A React wrapper component around signature_pad.

Originally, this was just an unopinionated fork of react-signature-pad that did not impose any styling or wrap any other unwanted elements around your canvas -- it's just a wrapper around a single canvas element! Hence the naming difference. Nowadays, this repo / library has significantly evolved, introducing new features, fixing various bugs, and now wrapping the upstream signature_pad to have its updates and bugfixes baked in.

This fork also allows you to directly pass props to the underlying canvas element, has new, documented API methods you can use, has new, documented props you can pass to it, has a live demo, has a CodeSandbox playground, has 100% test coverage, and is written in TypeScript.

Installation

npm i -S react-signature-canvas

Usage

import React from 'react'
import ReactDOM from 'react-dom'
import SignatureCanvas from 'react-signature-canvas'

ReactDOM.render(
  <SignatureCanvas penColor='green'
    canvasProps={{width: 500, height: 200, className: 'sigCanvas'}} />,
  document.getElementById('react-container')
)

Props

The props of SignatureCanvas mainly control the properties of the pen stroke used in drawing. All props are optional.

  • velocityFilterWeight : number, default: 0.7
  • minWidth : number, default: 0.5
  • maxWidth : number, default: 2.5
  • minDistance: number, default: 5
  • dotSize : number or function, default: () => (this.minWidth + this.maxWidth) / 2
  • penColor : string, default: 'black'
  • throttle: number, default: 16

There are also two callbacks that will be called when a stroke ends and one begins, respectively.

  • onEnd : function
  • onBegin : function

Additional props are used to control the canvas element.

  • canvasProps: object
    • directly passed to the underlying <canvas /> element
  • backgroundColor : string, default: 'rgba(0,0,0,0)'
    • used in the API's clear convenience method (which itself is called internally during resizes)
  • clearOnResize: bool, default: true
    • whether or not the canvas should be cleared when the window resizes

Of these props, all, except for canvasProps and clearOnResize, are passed through to signature_pad as its options. signature_pad's internal state is automatically kept in sync with prop updates for you (via a componentDidUpdate hook).

API

All API methods require a ref to the SignatureCanvas in order to use and are instance methods of the ref.

<SignatureCanvas ref={(ref) => { this.sigCanvas = ref }} />
  • isEmpty() : boolean, self-explanatory
  • clear() : void, clears the canvas using the backgroundColor prop
  • fromDataURL(base64String, options) : void, writes a base64 image to canvas
  • toDataURL(mimetype, encoderOptions): base64string, returns the signature image as a data URL
  • fromData(pointGroupArray): void, draws signature image from an array of point groups
  • toData(): pointGroupArray, returns signature image as an array of point groups
  • off(): void, unbinds all event handlers
  • on(): void, rebinds all event handlers
  • getCanvas(): canvas, returns the underlying canvas ref. Allows you to modify the canvas however you want or call methods such as toDataURL()
  • getTrimmedCanvas(): canvas, creates a copy of the canvas and returns a trimmed version of it, with all whitespace removed.
  • getSignaturePad(): SignaturePad, returns the underlying SignaturePad reference.

The API methods are mostly just wrappers around signature_pad's API. on() and off() will, in addition, bind/unbind the window resize event handler. getCanvas(), getTrimmedCanvas(), and getSignaturePad() are new.

Example

You can interact with the example in a few different ways:

  1. Run npm start and navigate to http://localhost:1234/.
    Hosted locally via the example/ directory
  2. View the live demo here.
    Hosted via the gh-pages branch, a standalone version of the code in example/
  3. Play with the CodeSandbox here.
    Hosted via the cra-example branch, a standalone version using Create React App.

react-signature-canvas's People

Contributors

agilgur5 avatar blackjk3 avatar joemcelroy avatar kbrabrand avatar lopis avatar randallknutson avatar remotezygote avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

react-signature-canvas's Issues

Add a modal example

Hi there,

I'm sorry if there was an abusive comment here #44 but after a few days working on a project with react-signature-canvas I have to say that this example by far helped me the most.

Especially the whole useRef({}) thing was hard to figure out, and tbh by now I did not really get why I need to provide a runction for the ref property (measuredref in the example)

Took me quite a while to find this - so probably reconsider adding it to the docs?!

Cheers,
Benedikt

`time` attribute only present in last stroke

When a signature is given that consists of multiple strokes, the strokes array returned by toData() include the time attribute only in the last element.

Expected: All strokes should contain time information.

Example:

[
  [
    { "x": 68.33331298828125, "y": 110.61669921875 },
    { "x": 76.33331298828125, "y": 107.61669921875 },
    { "x": 84.33331298828125, "y": 105.61669921875 },
    
  ],
  [
    { "x": 164.33331298828125, "y": 103.61669921875 },
    { "x": 170.33331298828125, "y": 103.61669921875 },
    { "x": 176.33331298828125, "y": 102.61669921875 },
    
  ],
  [
    { "x": 317.33331298828125, "y": 100.61669921875, "time": 1646737591539 },
    { "x": 327.33331298828125, "y": 96.61669921875, "time": 1646737591584 },
    { "x": 333.33331298828125, "y": 95.61669921875, "time": 1646737591601 },
    
  ]
]

Version: 1.0.5, on Firefox 97.0.2 (64-bit) ubuntu (snap)

resize does not respect `backgroundColor`

I get why the canvas is cleared on a resize, but if you call the .clear() api, it persists the backgroundColor whereas, if you do a resize, the backgroundColor is wiped out.

How to keep or restore the backgroundColor on a resize?

`getTrimmedCanvas` function doesn't fully support `backgroundColor` prop

Hi i kinda try the example code. Everything work fine. But when i tried to get the trimmed version
why is it still giving me the original one?

console.log(this.sigPad.getTrimmedCanvas().toDataURL('image/png'));
console.log(this.sigPad.toDataURL('image/png'));

the base64 string for both command it's giving me the same string
am i missing something? thanks

First time drawing a signature disappears

Hi,

I'm using this component for some time but I realized that the first time I sign into the component, the drawing disappears while the second time it does not.

This is the code I use to include the component:

<SignatureCanvas
  penColor="black"
  canvasProps={{
    height: canvasHeight,
    width: canvasWidth,
  }}
  ref={(elem) => {
    this.signatureCanvas = elem;
  }}
  onEnd={() => {
    this.saveSignature();
  }}
/>

and on saveSignature I just get the base64 encoded image and store it in the state. Am I doing something wrong?

Width and Height change cause de-sync

If you change the height and width using a css class it just zooms in the canvas and the pointer is defaced, but when you change it using the width and height props it works correctly, but clears the canvas every time i change the size when i implement a onMouseOver and onMouseOut.

Update to `signature_pad` v4 for "passive" events?

package.json seems to lock us into using version 2.3.2 of signature_pad, rather than the latest 4.0.2. I noticed because I encountered this error:

[Violation] Added non-passive event listener to a scroll-blocking 'touchstart' event. Consider marking event handler as 'passive' to make the page more responsive. See https://www.chromestatus.com/feature/5745543795965952

and upon searching, found it has already been fixed in szimek/signature_pad#308 years ago . Are we able to take advantage of the upstream fixes?

How to check if a dataURL is empty?

Hi :)
Dose any way to check if image is empty ?
First I try to

let str = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAAtJREFUGFdjYAACAAAFAAGq1chRAAAAAElFTkSuQmCC";
console.log( image === str )

It can work on my local , but not work for other computer .

So, i wonder if there have another solution.

Thanks.

Placing a single dot throws an error

Clicking the canvas without dragging throws an error. I believe this to be caused by this line. The default value for dotSize is defined as an arrow-function, using this to access props. However, the function is defined staticly, which means there is no this to speak of. Babel transforms the line to

return ((void 0).props.minWidth + (void 0).props.maxWidth) / 2

The result is Uncaught TypeError: Cannot read property 'props' of undefined.

There is a pull request attempting to fix this, but unfortunately it basically just hardcodes the default dotSize to 2.

Perhaps passing the minWidth and maxWidth to the dotSize-function could be a solution?

Signature Pad does not follow cursor

When I make use Chrome Dev tools to use size of a mobile, the signature pad doesnt follow the cursor of the mouse. I saw something like
canvasResize() { let canvas = document.querySelector('canvas'); this.signaturePad.set('minWidth', 1); this.signaturePad.set('canvasWidth', canvas.offsetWidth); this.signaturePad.set('canvasHeight', canvas.offsetHeight); }

But I cant get it to work

Add tests

Place for notes as I'm implementing tests on the tests branch.

Some initial notes:

  • Will need to use enzyme for component testing as we actually do need the ref in this library's case to test instance methods, so can't use react-testing-library. We also do need to test actually mounting to the DOM (due to canvas usage), so react-test-renderer doesn't really suffice either.
  • Thought I would also need something to support canvas like the canvas package or canvas-prebuilt, but apparently need full jsdom support for enzyme (https://airbnb.io/enzyme/docs/guides/jsdom.html). The set-up for jsdom for enzyme however seems equivalent to what browser-env does, so that can be a replacement.

`isEmpty` is not working as expected

isEmpty is set as true when canvas is clicked.

This causes troubles in cases when there is already something drawn on to the canvas and the last strokes length is less than 2.

So isEmpty shouldn't be set as true when there is already some content on the canvas.

Example with modal, aspect ratio, hooks, validation, and name

I have worked through some of the deficiencies in the prior react hooks example posted, so please find an updated version with the following changes which I think is worthy of posting for some of the reasons below:

  • It's now a "controlled" component, eg. rather than handling both the button, modal and preview, this component just handles the modal. This lets you customise the appearance easily, and I have provided an example of this at the bottom.
  • I've added a "signee name" input, which makes sense for most use cases, but is toggle-able via the displayNameInput prop.
  • I've added validation ensuring you can't hit "save" without filling in the required fields. This is tricky, and thus my main reasoning for posting this example. It's tricky because using hooks you don't get access to an easy lifecycle event to know what the internal state of the signaturepad is. You could call isEmpty() inside a poll, but this example uses onDrawEnd which I think is elegant.

You'll note I've left bootstrap classes in. If you're on Bootstrap it'll look nice out of the box, otherwise you'll want to drop in your own utility classes.

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

const ModalSignatureCanvas = ({onSave, onHide, widthRatio, canvasProps, displayNameInput = false}) => {
  const [signatureResult, setSignatureResult] = useState('')
  const [name, setName] = useState('')
  const sigCanvas = useRef({})
  const sigPad = useRef({})

  const setNameOnChange = (event) => {
    setName(event.target.value)
  }

  const setSignatureOnChange = () => {
    const dataURL = sigCanvas.current.toDataURL()
    setSignatureResult(dataURL)
  }

  const saveInput = () => {
    onSave({dataURL: signatureResult, name: name})
  }

  const clearInput = () => {
    sigPad.current.clear()
    setSignatureResult('')
  }

  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 isNameValidIfRequired = (displayNameInput && !!name) || !displayNameInput
  const isSignatureValid = !!signatureResult
  const isFormValid = isNameValidIfRequired && isSignatureValid

  return (
    <Modal
      title="Enter your signature"
      onHide={onHide}
    >
      <div className="canvasWrapper">
        <SignatureCanvas
          canvasProps={canvasProps}
          ref={measuredRef}
          onEnd={setSignatureOnChange}
        />
      </div>
      {displayNameInput &&
        <div className="nameInput">
          <label>Name of person entering signature:</label>
          <input type="text" className="form-control" onChange={setNameOnChange} value={name} />
        </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} disabled={!isFormValid}>Save</button>
        </div>
      </Footer>
    </Modal>
  )
}
ModalSignatureCanvas.propTypes = {
  canvasProps: PropTypes.object,
  widthRatio: PropTypes.number.isRequired,
  onSave: PropTypes.func,
  onHide: PropTypes.func,
  displayNameInput: PropTypes.bool,
}

export default ModalSignatureCanvas

Example: Show signature and a change button

const SignatureCaptureInput = ({signature, signee, onClick, onHide, onSave, isModalOpen}) => {
  const buttonText = signature ? 'Change signature' : 'Collect signature'
  return (
    <>
      {signature &&
        <img className="img-fluid border mb-2" src={signature} />}
      {signee && <div className="blockquote-footer mb-2">{signee}</div>}
      <button type="button" className={classNames('btn btn-block', {'btn-secondary': signature, 'btn-primary': !signature})} onClick={onClick}>{buttonText}</button>
      {isModalOpen && <ModalSignatureCanvas widthRatio={3} onSave={onSave} onHide={onHide} displayNameInput />}
    </>
  )
}
SignatureCaptureInput.propTypes = {
  signature: PropTypes.string,
  signee: PropTypes.string,
  onClick: PropTypes.func,
  onHide: PropTypes.func,
  onSave: PropTypes.func,
  isModalOpen: PropTypes.bool,
}

// Usage
const [isModalOpen, setModalOpen] = useState(false)
const handleSignatureChange({dataURL, name}) => { ... }

<SignatureCaptureInput
  onSave={handleSignatureChange}
  signee={clientSignee}
  signature={clientSignature}
  onClick={() => setModalOpen(true})}
  onHide={() => setModalOpen(false})}
  isModalOpen={isModalOpen}
/>

Which looks like:

Prompt for collection:

Screen Shot 2020-03-06 at 2 51 22 pm

Modal open:

Screen Shot 2020-03-06 at 2 46 09 pm

Preview on completion:

Screen Shot 2020-03-06 at 2 45 58 pm

Apologies if this isn't in the right place to post this, but the docs just don't cover the intricacies of implementing this component. Hope this helps someone!

setting `clearOnResize` prop to `false`

Hi! I am trying to set clearOnResize to false, because my canvas pops out as a modal, and the screen resizes itself every time the modal is initiated, clearing the canvas. Can't seen to get clearOnResize = false working. Am I passing the props for clearOnResize correctly? Thanks

<div className="drawing-canvas"> <SignatureCanvas clearOnResize={false} minWidth={0.9} maxWidth={0.9} canvasProps={{ width: size.width, height: size.width * 1.2941, className: "sigCanvas" }} ref={ref => { this.sigPad = ref; }} /> </div>

`h.default is not a constructor`

"react": "^16.4.2",

index.js:1 Uncaught TypeError: h.default is not a constructor
    at t.value (index.js:1)
    at commitLifeCycles (react-dom.development.js:19814)
    at commitLayoutEffects (react-dom.development.js:22803)
    at HTMLUnknownElement.callCallback (react-dom.development.js:188)
    at Object.invokeGuardedCallbackDev (react-dom.development.js:237)
    at invokeGuardedCallback (react-dom.development.js:292)
    at commitRootImpl (react-dom.development.js:22541)
    at unstable_runWithPriority (scheduler.development.js:653)
    at runWithPriority$1 (react-dom.development.js:11039)
    at commitRoot (react-dom.development.js:22381)
    at finishSyncRender (react-dom.development.js:21807)
    at performSyncWorkOnRoot (react-dom.development.js:21793)
    at react-dom.development.js:11089
    at unstable_runWithPriority (scheduler.development.js:653)
    at runWithPriority$1 (react-dom.development.js:11039)
    at flushSyncCallbackQueueImpl (react-dom.development.js:11084)
    at flushSyncCallbackQueue (react-dom.development.js:11072)
    at discreteUpdates$1 (react-dom.development.js:21893)
    at discreteUpdates (react-dom.development.js:806)
    at dispatchDiscreteEvent (react-dom.development.js:4168)

has anyone managed to get this working with TypeScript?

I tried creating a declaration file index.d.ts:

declare module 'react-signature-canvas'
{
    import * as React from 'react';
    
    interface ISignatureCanvasProps
    {
        velocityFilterWeight?: number;
        minWidth?: number;
        maxWidth?: number;
        dotSize?: number;
        penColor?: string;
        backgroundColor?: string;
        onEnd?: () => void;
        onBegin?: () => void;
        canvasProps?: any;
    }
    
    export class SignatureCanvas extends React.Component<ISignatureCanvasProps, any>
    {
        constructor(p: ISignatureCanvasProps, s: any);
    }
    
    namespace SignatureCanvas {}
}

And then importing via: import * as SignatureCanvas from 'react-signature-canvas';.

But when I use the <SignatureCanvas /> in my react component I get
React.createElement: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: object

Any ideas?

Example with modal, aspect ratio, and hooks

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.

Add CodeSandbox

Having a CodeSandbox in the docs would be very useful as a quick example folks can use to try it out and use it in real code simultaneously.

I was hoping to easily hook it up to the gh-pages branch last week, but this is not quite so easy, so will document/note down some things here

`TypeError: Cannot read property 'off' of null`

Selection_815
Hi!
Following the installation of your package, I am getting the error "TypeError: Cannot read property 'off' of null". Here is a minimal code to reproduce:

import React from 'react';
import SignaturePad from 'react-signature-canvas';

const TOKEN_PARAM = 'token';
class ConsentForm extends React.Component{

    constructor(props) {
        super(props);
    }

    render() {
        return (
            <SignaturePad />
        );
    }
}
export default ConsentForm;

I am using Chrome and react-signature-canvas 1.0.3. Also, It does the same error if I copy the code in your codepen.

[RFC] Use/wrap upstream signature_pad

When I originally forked react-signature-pad, I did not particularly diff the code with the original signature_pad and just made changes downstream as needed. Having looked more closely at signature_pad in recent months (due to the discussion in #8 ), it looks like all of the code is backward-compatible (even the 2.0.0 release is just a dist change which does not break the API).

I propose that this library import signature_pad and effectively just act as a wrapper implementing certain helper functions like trimming and resizing (as it currently does). All props would be passed directly to the signature_pad instance. In order to preserve auto-updating props, a componentWillReceiveProps hook would need to be made that updates the instance's internal variables. I don't think there would be anything backwards-incompatible this way, but I may be wrong (there may be some gimmicks in resize). It may need to pin to patch versions only for now as minor version changes could break the wrapping layer due to internal usage (e.g. opts.ratio, opts.width, opts.height).

This would add a whole host of new functionality, such as adding an SVG option as requested in #12 , as well as fix lots of bugs, such as the isEmpty bug in #16 , and would overall reduce maintenance burden and the general surface area of this library and its API.

Convert raw array data (`toData`) to image so it can be scaled?

For the last few years i've used this component to get signatures, i've been saving the data in its raw array form instead of a PNG

on load from the server is there any way I can use this component to convert the data to a PNG? i'm having a lot of trouble trying to figure out how to get the signature to scale down from its original size

the original signature was signed with a hit-box of 160px x 650px and , but now I need to scale it down to 160px x 288px

// ... what i'm doing now

componentDidMount () {
  // ...
  this.setState({ record }, () => {
    const signature = this.refs.mySignature
    if (record.signature && record.signature.length > 0) 
      signature.fromData(record.signature)
      signature.off()
    }
  })
}

render () {
  return (
    <SignatureCanvas
       ref={'mySignature'}
       penColor={'var(--default-font-color)'}
       canvasProps={{
         width: 650,
         height: 160,
        className: 'mySignature'
      }}
    />
  )
}

`toDataURL` / `fromDataURL` scaling with device pixel ratios > 1

When serializing the canvas data with toDataURL and then again de-serializing the same data with fromDataURL, the canvas content is not scaled correctly on device with a device pixel ratio larger than 1. The drawing is duplicated in the top left corner, scaled down:
image

Here is a repro sandbox: https://codesandbox.io/s/elated-cookies-50yg2?file=/src/App.js
Try it on a device with pixel ratio 1, works fine, but on a retina screen or iphone you can observe the effect above. You can even use the iPhone emulator in chrome desktop.

if `clearOnResize` false, CSS resize causes de-sync

First, Thank you for your job ;)
I'm trying to develope a form that users will fill from smartphone and then sign.
I set clearOnResize to false on Signature and once I rotate the phone the signature changes size properly. If i try to add something to the signature, then the drawing happen somewhere else in the screen than expected.
Also if i clear the signature and try to write keeping the phone in this new position, the problem keep showing off.

Won't draw when Pointer Lock activated

After implementing pointer locker on canvas you can't draw anymore, trying to focus on the canvas because i'm trying to capture input from a drawing pad, the reason being that without pointer locker the user is everywhere on screen.

Canvas resize causes de-sync when clearOnResize=false

Hi,

I'm trying to use your library but I'm having 2 issues:

  1. The line appears to the right of where the mouse is when adding a signature.

  2. When resizing the browser window, the canvas takes over the whole screen and then breaks.

Is there any way to fix these issues?

black image returned by `toDataURL('image/jpeg')`

Hi,

Currently capturing the content of the signature canvas with signature.toDataURL("image/jpeg", 0.5);. This seems to return a base64. Whenever I try to return with signature.fromDataURL(base64) I get a fully blacked out canvas?

`h.default is not a constructor`

Hello i'v have this error "h.default is not a constructor" when i want to test the package.
import SignatureCanvas from 'react-signature-canvas';

in render :

Data given to `fromData` is mutated by the component

To reproduce,

  • pass some points to the component with fromData:
const signaturePoints = [
  [
    { x: 54.002685546875, y: 130.68206787109375, time: 1596180140938 },
    { x: 87.002685546875, y: 86.68206787109375, time: 1596180141056 },
    { x: 114.002685546875, y: 66.68206787109375, time: 1596180141072 },
    { x: 130.002685546875, y: 60.68206787109375, time: 1596180141088 },
    { x: 143.002685546875, y: 60.68206787109375, time: 1596180141104 },
    { x: 150.002685546875, y: 61.68206787109375, time: 1596180141120 },
  ],
];

canvasRef.current.fromData(signaturePoints);
  • draw a line on the canvas
  • log the content of signaturePoints, it'll contain the line you just draw:
console.log(signaturePoints);
// [
//   [
//     {x: 54.002685546875, y: 130.68206787109375, time: 1596180140938 },
//     {x: 87.002685546875, y: 86.68206787109375, time: 1596180141056 },
//     {x: 114.002685546875, y: 66.68206787109375, time: 1596180141072 },
//     {x: 130.002685546875, y: 60.68206787109375, time: 1596180141088 },
//     {x: 143.002685546875, y: 60.68206787109375, time: 1596180141104 },
//     {x: 150.002685546875, y: 61.68206787109375, time: 1596180141120 },
//   ],
//   [
//     {x: 132.002685546875, y: 110.68206787109375, time: 1596185355643 },
//     {x: 135.002685546875, y: 106.68206787109375, time: 1596185355725 },
//     {x: 146.002685546875, y: 98.68206787109375, time: 1596185355741 },
//     {x: 153.002685546875, y: 94.68206787109375, time: 1596185355757 },
//     {x: 157.002685546875, y: 91.68206787109375, time: 1596185355790 },
//     {x: 146.002685546875, y: 98.68206787109375, time: 1596185355741 },
//   ],
// ]

signaturePoints has been modified by the component.

A workaround to prevent this is to clone the data before passing it to fromData:

canvasRef.current.fromData(R.clone(signaturePoints));

R being Ramda. EDIT: or use [].concat(signaturePoints), or [...signaturePoints], which doesn't require a third-party library, to clone the data as agilgur5 recommends below.

how to pre-populate the canvas?

<SignatureCanvas 
  penColor='green'
  canvasProps={{width: 500, height: 200, className: 'sigCanvas'}}
  ref={(ref) => { this.sigPad = ref }} />

when this is rendered the ref variable is still the default {}
how can we set a value when it is rendered?

`h.default is not a constructor` error after adding unofficial TS definitions

Hi there, I'm facing this error where ts definitions is not found. I have followed the step in #21 but still not working. This error appears in the console.

Uncaught TypeError: h.default is not a constructor
    at t.value (index.js:1)
    at commitLifeCycles (react-dom.development.js:22101)
    at commitLayoutEffects (react-dom.development.js:25344)
    at HTMLUnknownElement.callCallback (react-dom.development.js:336)
    at Object.invokeGuardedCallbackDev (react-dom.development.js:385)
    at invokeGuardedCallback (react-dom.development.js:440)
    at commitRootImpl (react-dom.development.js:25082)
    at unstable_runWithPriority (scheduler.development.js:697)
    at runWithPriority$2 (react-dom.development.js:12149)
    at commitRoot (react-dom.development.js:24922)
    at finishSyncRender (react-dom.development.js:24329)
    at performSyncWorkOnRoot (react-dom.development.js:24307)
    at react-dom.development.js:12199
    at unstable_runWithPriority (scheduler.development.js:697)
    at runWithPriority$2 (react-dom.development.js:12149)
    at flushSyncCallbackQueueImpl (react-dom.development.js:12194)
    at flushSyncCallbackQueue (react-dom.development.js:12182)
    at discreteUpdates$1 (react-dom.development.js:24423)
    at discreteUpdates (react-dom.development.js:1438)
    at dispatchDiscreteEvent (react-dom.development.js:5881)
Uncaught TypeError: Cannot read property 'off' of null
    at t.r.off (index.js:1)
    at t.value (index.js:1)
    at callComponentWillUnmountWithTimer (react-dom.development.js:21896)
    at HTMLUnknownElement.callCallback (react-dom.development.js:336)
    at Object.invokeGuardedCallbackDev (react-dom.development.js:385)
    at invokeGuardedCallback (react-dom.development.js:440)
    at safelyCallComponentWillUnmount (react-dom.development.js:21903)
    at commitUnmount (react-dom.development.js:22392)
    at commitNestedUnmounts (react-dom.development.js:22486)
    at unmountHostComponents (react-dom.development.js:22810)
    at commitUnmount (react-dom.development.js:22429)
    at commitNestedUnmounts (react-dom.development.js:22486)
    at unmountHostComponents (react-dom.development.js:22810)
    at commitDeletion (react-dom.development.js:22896)
    at commitMutationEffects (react-dom.development.js:25323)
    at HTMLUnknownElement.callCallback (react-dom.development.js:336)
    at Object.invokeGuardedCallbackDev (react-dom.development.js:385)
    at invokeGuardedCallback (react-dom.development.js:440)
    at commitRootImpl (react-dom.development.js:25050)
    at unstable_runWithPriority (scheduler.development.js:697)
    at runWithPriority$2 (react-dom.development.js:12149)
    at commitRoot (react-dom.development.js:24922)
    at finishSyncRender (react-dom.development.js:24329)
    at performSyncWorkOnRoot (react-dom.development.js:24307)
    at react-dom.development.js:12199
    at unstable_runWithPriority (scheduler.development.js:697)
    at runWithPriority$2 (react-dom.development.js:12149)
    at flushSyncCallbackQueueImpl (react-dom.development.js:12194)
    at flushSyncCallbackQueue (react-dom.development.js:12182)
    at discreteUpdates$1 (react-dom.development.js:24423)
    at discreteUpdates (react-dom.development.js:1438)
    at dispatchDiscreteEvent (react-dom.development.js:5881)

where index.js refers to index in build folder.

`fromDataURL()` scaling issue

When I restore using fromDataURL(), the restored signature is about 1/4 size it was drawn in.

render the Signature Pad like this:

    public render(): JSX.Element
    {
        return (
            <div className="signature-modal-container">
                <div className="signature-modal">
                    <SignatureCanvas canvasProps={{ width: 600, height: 300 }} penColor="rgb(40,66,131)" ref={(r) => { this._signatureCanvas = r;}} />
                    <div className="signature-footer">
                        <span className="sign-above">sign above</span>
                        <div className="buttons">
                            <a onClick={this.clearClicked}>clear</a>
                            <Button bsStyle="primary" bsSize="xs" onClick={this.doneClicked}>Save</Button>
                        </div>
                    </div>
                </div>
            </div>
        );
    }

And my save method looks like this:

    @action.bound
    private doneClicked(): void
    {
        this.log('saving signature');
        this.props.delivery.SignatureData = this._signatureCanvas.getCanvas().toDataURL('image/png', 1.0);
        this._signatureCanvas.clear();
        this._signatureCanvas.fromDataURL(this.props.delivery.SignatureData);
    }

For testing purposes, I am just doing toDataURL(), clearing canvas, then restoring the contents. The restored drawing is shrunked by a factor of DPR. For example in the Chrome device emulator the iPhone 6 has a DPR of 2.0, so on save/restore the result is half ths size I drew it.

How do I handle this situation so the sigature remains the same size on save/restore on a phone?

Read-only, disabled Canvas?

Is there a simple way to make this readonly, or non-editable? I know that I can simply not save the data in a database, however the user can still draw over the existing canvas.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.