Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: don't clear canvas on mobile browsers' height change #66

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 25 additions & 3 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ import React, { Component } from 'react'
import SignaturePad from 'signature_pad'
import trimCanvas from 'trim-canvas'

const userAgent = window.navigator.userAgent
const isTouchDevice = userAgent.indexOf("iPhone") >= 0 || userAgent.indexOf("iPad") >= 0 || userAgent.indexOf("Android") >= 0
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is fully inclusive of all mobile browsers. This SO answer lists quite a bit more.

isMobile is also probably better naming as laptops can have touchscreens too.

But while I like the DX of auto-detection, I'm not sure this is foolproof enough to work consistently. A prop isMobile might make more sense... but the developer might use the same method to set that prop 😅

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

detect-it can also be used to check device support for touch screen and if the touch screen is the primary input method (which should filter out laptop touchscreens I think? though I'm not sure the compatibility of both checks).

There are still some edge cases not covered there, for instance, multi-tasking mode on mobile where you split the screen... 😕

Adding a clearOnOrientationChange prop may make things more clear for developers and be fully backward-compatible as well. Then they can decide whether to use that for their users, e.g. clearOnResize={false} clearOnOrientationChange, and each developer should know their users best.

That's probably the easiest solution, though I do prefer the DX of auto-detection


export default class SignatureCanvas extends Component {
static propTypes = {
// signature_pad's props
Expand All @@ -26,6 +29,8 @@ export default class SignatureCanvas extends Component {

_sigPad = null

_windowSize = { width: window.innerWidth, height: window.innerHeight }

_excludeOurProps = () => {
const { canvasProps, clearOnResize, ...sigPadProps } = this.props
return sigPadProps
Expand Down Expand Up @@ -67,11 +72,28 @@ export default class SignatureCanvas extends Component {
return this._sigPad
}

_checkClearOnResize = () => {
if (!this.props.clearOnResize) {
_handleResize = (callback) => {
if (this._windowSize.width === window.innerWidth &&
/**
* For touch devices, only compare width as the browser height
* might constantly change as user scrolls/touches like on iOS Safari.
*/
(this._windowSize.height === window.innerHeight || isTouchDevice)
) {
return
}
this._resizeCanvas()
// Update window size
this._windowSize = { width: window.innerWidth, height: window.innerHeight }
callback()
}

_checkClearOnResize = () => {
this._handleResize(() => {
if (!this.props.clearOnResize) {
return
}
this._resizeCanvas()
})
Comment on lines +91 to +96
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These methods can get called very frequently during each frame of a resize (esp. as they're not throttled), so instead of creating anonymous closures each time, it's better to have another helper method for this. That optimization is also why the rest of the code is written as such

}

_resizeCanvas = () => {
Expand Down