avioli / react-native-signature-pad

React Native wrapper around szimek's Canvas based Signature Pad
MIT License
1 stars 0 forks source link

How do you call undocumented clear signature function? #1

Open JamesMcIntosh opened 5 years ago

JamesMcIntosh commented 5 years ago

Hi Evo,

I've also borrowed part of your pattern of sending messages into the component to clear the canvas. I implemented the communication into the SignaturePad component as follows, is this how you accomplished it also? It would be good to add it to your Readme.md as an example.

<View style={wrapperStyle}>
    <SignaturePad
        ref={ref => {
            this.signature = ref;
        }}
        onError={(e) => console.error(e)}
        onChange={(data) => {
            input.onChange(data.base64DataUrl)
        }}
        style={componentStyle}
        useFont={false}
        name={''}
        dataURL={input.value || ''} />
    <TouchableOpacity 
        onPress={() => {
            this.signature.clear();
            input.onChange('');
        }}
        style={[buttonStyle]}>
        <Text style={buttonTextStyle}>Clear</Text>
    </TouchableOpacity>
    { errorMessage(meta, errorStyle) }
</View>

I also made some changes to a fork of react-native-signature-pad, you may be interested in some of my changes to help it perform better on Android.

https://github.com/JamesMcIntosh/react-native-signature-pad/commits/master

Kind regards James

avioli commented 5 years ago

Thanks James, I'll take a look at your fork and let you know or just steal it.

My usage is only for iOS (for now), so the Android performance is irrelevant to me (for now).

I don't use the onChange callback, since it fires too often and may miss a change event if the signature pad doesn't cover the whole screen and the user "draws" off its canvas.

This is how I use my component:

  _renderSignaturePad = () => {
    return (
      <View style={styles.sigPadContainer}>
        <Text style={styles.sigPadHeading}>Draw your signature below</Text>
        <SignaturePad
          ref={(ref) => { this._sigPad = ref }}
          onError={this._handleSignaturePadError}
          style={styles.sigPadBg}
          backgroundColor={this.state.penColor}
          _pixelRatio={1}
          webViewBackgroundColor='#eee'
          useFont={false}
        />
        <View style={styles.sigPadBaseline} />
      </View>
    )
  }

Then I've got my own Modal component that renders the above:

  render () {
    /// ...
    const sigPadButtons = [
      [
        {
          text: 'Clear',
          type: 'subtle-warning',
          onPress: this._handleClearSigPad
        }
      ], [
        {
          text: 'Cancel'
        },
        {
          text: 'Use',
          onPress: this._handleUseSignature,
          type: 'primary'
        }
      ]
    ]
    // ...
        <Modal
          ref={(ref) => { this._modal = ref }}
          visible={false}
          renderWhenVisible={this._renderSignaturePad}
          width={600}
          buttonsContainerStyle={layoutStyles.flex0}
          buttons={sigPadButtons}
        />
    // ...

So the buttons' callbacks are:

  _handleClearSigPad = () => {
    this._sigPad.clear()
  }

  _handleUseSignature = async () => {
    // NOTE: check if signature is empty
    try {
      const isEmpty = await this._sigPad.isEmpty()
      if (isEmpty) {
        Alert.alert('Signature is empty!')
        return
      }
    } catch (err) {
      if (__DEBUG__) {
        console.error('AdminInspectorDetails:_handleUseSignature - isEmpty', err.message)
      }
    }

    // NOTE: get signature data
    let data
    try {
      data = await this._sigPad.getBase64Data()
    } catch (err) {
      if (__DEBUG__) {
        console.error('AdminInspectorDetails:_handleUseSignature - getBase64Data', err.message)
      }
      Alert.alert('Error getting signature data')
      return
    }

    const toStrip = 'data:image/png;base64,'
    data = data.substr(toStrip.length)

    // NOTE: write signature data to file
    const filename = `signature-${guid()}.png`
    const path = `${docPath}/${filename}`
    const uri = `file://${path}`
    if (__DEBUG__) {
      console.warn('path', path)
    }

    let stat
    let dim
    try {
      await RNFS.writeFile(path, data, 'base64')
      stat = await RNFS.stat(path)
      dim = await new Promise((resolve, reject) => { Image.getSize(uri, (width, height) => resolve({ width, height }), reject) })
    } catch (err) {
      Alert.alert('Error writing signature file')
      return
    }

    // NOTE: fake the signature submit
    const value = {
      bytes: stat.size,
      filename,
      path: '',
      width: dim.width,
      height: dim.height
    }

    await this._handleValueSubmit({
      key: 'signature',
      value
    }, { FAKE_VALUES: 'FAKE_VALUES' })

    // NOTE: update UI
    this._inputsController.setValues({
      signature: value
    })

    await this._modal.hide()
  }

The fake signature submit is just an implementation detail that's not important.

JamesMcIntosh commented 5 years ago

Wow, thanks for the awesome feedback!