Skip to content

Instantly share code, notes, and snippets.

@nsfmc
Last active October 13, 2015 02:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nsfmc/2970ae3e64da17814b81 to your computer and use it in GitHub Desktop.
Save nsfmc/2970ae3e64da17814b81 to your computer and use it in GitHub Desktop.
force sketch components

omg this is so horrible, but it was illuminating for figuring out how to do x-platform force touch events

a few things to note:

  • touches.force in mobilesafari is just a 0-1 float that only gets updated onTouchMove
  • trackpad force is much easier to reason about because it doesn't require the movement, it's just part of the click handler. As a result, it's not possible to mock peek/pop gestures in mobile safari (that i can tell, at least)
  • i have no idea how to fake eventhandlers in react, it's annoying having to manually bind them. ╮(. ❛ ᴗ ❛.)╭

more about force touch apis at apple's dev docs

import React, {Component} from 'react'
export default class Force extends Component {
componentDidMount () {
this.refs.parent.addEventListener('webkitmouseforcewillbegin',
this.handleForceWillBegin.bind(this))
this.refs.parent.addEventListener('webkitmouseforcedown',
this.handleForceDown.bind(this))
this.refs.parent.addEventListener('webkitmouseforceup',
this.handleForceUp.bind(this))
this.refs.parent.addEventListener('webkitmouseforcechanged',
this.handleForceChanged.bind(this))
}
componentWillUnmount () {
this.refs.parent.removeEventListener('webkitmouseforcewillbegin',
this.handleForceWillBegin)
this.refs.parent.removeEventListener('webkitmouseforcedown',
this.handleForceDown)
this.refs.parent.removeEventListener('webkitmouseforceup',
this.handleForceUp)
this.refs.parent.removeEventListener('webkitmouseforcechanged',
this.handleForceChanged)
}
render () {
return (<div ref='parent'
className='force-component'
{...this.props}>
{this.props.children}
</div>)
}
handleForceWillBegin (evt) {
if (this.props.onForceWillBegin) {
this.props.onForceWillBegin(evt)
}
}
handleForceDown (evt) {
if (this.props.onForceDown) {
this.props.onForceDown(evt)
}
}
handleForceUp (evt) {
if (this.props.onForceUp) {
this.props.onForceUp(evt)
}
}
handleForceChanged (evt) {
if (this.props.onForceChanged) {
this.props.onForceChanged(evt)
}
}
}
Force.defaultProps = {
onClick: () => {},
onTouchStart: () => {},
onTouchMove: () => {},
onMouseUp: () => {}
}
Force.propTypes = {
children: React.PropTypes.node,
onForceWillBegin: React.PropTypes.func,
onForceDown: React.PropTypes.func,
onForceUp: React.PropTypes.func,
onForceChanged: React.PropTypes.func,
onClick: React.PropTypes.func,
onTouchStart: React.PropTypes.func,
onTouchMove: React.PropTypes.func
}
import React, {Component} from 'react'
import Force from './force.jsx'
export default class Main extends Component {
constructor (props) {
super(props)
this.state = {forcePct: 0, forceRaw: 0}
}
render () {
return (
<Force onForceWillBegin={this.handleForceWillBegin}
onForceChanged={this.handleForceChanged.bind(this)}
onForceDown={this.handleForceDown}
onForceUp={this.handleForceUp.bind(this)}
onTouchStart={this.handleTouchStart.bind(this)}
onTouchMove={this.handleTouchMove.bind(this)}
onClick={this.handleClick}
onMouseUp={this.handleMouseUp.bind(this)}
>
<StatusBar pct={this.state.forcePct} raw={this.state.forceRaw} />
</Force>
)
}
handleClick (evt) {
console.log('clicky!')
}
handleMouseUp (evt) {
this.setState({forcePct: 0, forceRaw: 0})
}
handleForceWillBegin (evt) {
// evt.preventDefault()
console.log('force beginning!')
}
handleForceChanged (evt) {
if ('webkitForce' in evt) {
let forceLevel = evt.webkitForce
let clickForce = window.MouseEvent.WEBKIT_FORCE_AT_MOUSE_DOWN
let forceClickForce = window.MouseEvent.WEBKIT_FORCE_AT_FORCE_MOUSE_DOWN
if (forceLevel >= clickForce && forceLevel < forceClickForce) {
// normal click stuff here
let pct = forceLevel / forceClickForce
this.setState({forcePct: pct, forceRaw: forceLevel})
// console.log(this.state)
} else if (forceLevel >= forceClickForce) {
// Perform operations in response to a force click
this.setState({forcePct: (forceLevel / forceClickForce)})
}
}
}
handleForceDown (evt) {
console.log('cliiiiiick')
}
handleForceUp (evt) {
console.log('ahhhhhhhhh')
this.setState({forcePct: 0, forceRaw: 0})
}
handleTouchStart (evt) {
var force = evt.touches[0].force
console.log(force)
this.setState({forcePct: force, forceRaw: force})
}
handleTouchMove (evt) {
var force = evt.touches[0].force
console.log(force)
this.setState({forcePct: force, forceRaw: force})
}
}
let StatusBar = (props) => {
let parentStyle = {height: 10}
let childStyle = {height: '100%', width: `${props.pct * 100}%`, backgroundColor: 'red'}
return <div style={parentStyle}>
<div style={childStyle}></div>
</div>
}
/* put your css here */
html {
background-color: #eaeeee;
}
body {
display:flex;
justify-content:center;
align-items:center;
width:100%;
height:100%;
}
.force-component {
width: 100px;
height: 100px;
background-color: white;
-webkit-touch-callout: none;
-webkit-tap-highlight-color: rgba(0,0,0,0);
}
.force-component::selection {
color:transparent;
background-color: transparent;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment