joystick-component-lib v0.1.2
joystick-component-lib
Library containing a custom joystick component and its TouchEventDemuxer, that allows for several joysticks to be moved simultaneously.
Contains:
Joystick: A standalone retro style joystick componentTouchEventDemuxer: a high order component that intercepts touch events and dispatches them to its children, allowing for several components being moved simultaneouslyJoystickDemuxed: A wrapper forJoystick, making it compatible withTouchEventDemuxer
To use it, simply
npm install joystick-component-libThen import it in your project
import { Joystick } from 'joystick-component-lib';
// ...TouchEventDemuxer
React Native's touch event management is such that only one responder can be active at a time. While this is usually beneficial, effectively shutting down 'unwanted' touches when an action in ongoing, it can be a nuisance when trying to have several objects manipulable at the same time (such as being able to move a second joystick without releasing the first one). TouchEventDemuxer is a solution to this problem, that intercepts all touch events happening in its children, analyzes them before dispatching them to the right owner.
Basic Usage
import React from 'React';
import { TouchEventDemuxer, JoystickDemuxed } from 'joystick-component-lib';
const componentArray = [JoystickDemuxed, JoystickDemuxed];
DoubleJoystick = TouchEventDemuxer(componentArray);
// props are then passed in an array as follows:
class MyFancyComponent extends React.Component {
render() {
return (
<DoubleJoystick
childrenProps={[
{
// props for the first component of the componentArray
},
{
// props for the second component of the componentArray
},
]}
/>
);
}
}Details
To be compatible with TouchEventDemuxer, children components must implement the method includes(x,y) and can implement onTouchStart(touch) onTouchMove(touch) and onTouchEnd(touch), where:
includes(x, y)is used by theTouchEventDemuxerto ask its children if the touch hapening at the position(x, y)"belongs" to them or not. It is advised to be careful when defining theincludes()function, as two components should not return true for a same given position (no overlap). Note that if for some reason, several children return true for a given(x1, y1), then priority will be given to the first of these children in the children array.onTouch*(touch)are callbacks triggered when theTouchEventDemuxergives ownership of a touch to the children component, and when subsequent moves happen until release.touchhas the following shape:responderID: ID of the children controlling the touch,X0: screen coordinates of the touch grant,Y0: screen coordinates of the touch grant,pageX: latest screen coordinates of the recently moved touch,pageY: latest screen coordinates of the recently moved touch,dx: accumulated distance of the gesture since the touch starteddy: accumulated distance of the gesture since the touch started
Joystick Component
Simple, retro-style joystick than can be take either a vertical, circular or horizontal shape.

Main or Required Props
- shape: Can be
circular,horizontalorvertical. The value ofshapewill determine the effect of thelengthproperty - length: Determine the characteristic length of the joystick, i.e. half its length for a
verticalorhorizontaljoystick or its radius for acircularone - neutralPointX: X Position of the center of the joystick
- neutralPointY: Y Position of the center of the joystick
Callbacks triggered on handle displacement
- onDraggableMove: will be called every time the handle is moved, with a
touchobject containing at leastdxanddy, displacement relative to the neutral point - onDraggableRelease: will be called on handle release, with a similar
touchobject - onDraggableStart: will be called before the handle starts moving
note: the above props are different in case of a JoystickDemuxed (see below).
Other Props
- isSticky: If set to true, then the handle will automatically come back to the neutral point when released. Default to false
- hasResponderOverride: Used as a standalone, the
Joystickcomponent comes with its ownPanResponderand can therefore be used out of the box. When multiplesJoystickare to be used simultaneously, thenhasResponderOverridemust be set totruein order to inhibate thePanRepsonderand allow the parent component to take control. If you want to use this functionality however, it is recommended to directly use theTouchEventDemuxerin conjunction with severalJoystickDemuxed(see below for more details)
Appearance
The default appearance is fully customizable through the props draggableStyle (will be applied to the handle) and draggableBackground. Note that the background's style will try to adapt to the one of the handle (by automatically extending it's width, for instance)
JoystickDemuxed
High order component that adds a functional layer to the Joystick component in order to make it compatible with TouchEventDemuxer. Properties are roughly identical to the regular Joystick component, with a few differences:
onDraggableMove,onDraggableStartandonDraggableReleaseare replaced with the uniqueonJoystickMovethat is triggered on start, move and release with(xRatio, yRatio); wherexRatio = relative displacement / length value(and similarly foryRatio) and thus takes values between -1 and 1
Modifications & Development
If you wish to edit and modify this library, please feel free! Simply clone this repository, and run npm install.
Playground Expo application
A "playground" (expo application to test out changes) is available, with a special launch script to make the expo launcher work with simlinks as long as the packages simlinked are include in the package.json project dependencies.
To use it, go to the playground/ folder, then npm install it. You can go back to the root folder and npm link, then go to playground/ and npm link joystick-component-lib. After having checked that joystick-component-lib is indeed listed as a dependency in package.json, launch the app using node react-native-start-with-link.js.