Touch-enabled Virtual Joystick with Haptics In Vanilla JavaScript

Category: Javascript | March 14, 2025
AuthorJoker-pyc
Last UpdateMarch 14, 2025
LicenseMIT
Views1,699 views
Touch-enabled Virtual Joystick with Haptics In Vanilla JavaScript

Virtual Joystick is a vanilla JavaScript library that creates customizable on-screen joystick controls for touch-enabled devices. Weighs under 5KB gzipped and requires no external dependencies.

The library provides both static and dynamic positioning modes, built-in haptic feedback through the Vibration API, and keyboard emulation for WASD or arrow key mapping.

It’s ideal for building HTML5 canvas games, interactive web applications, or any touch-based UI that requires directional input.

Features:

  • Multi-Touch Support: Handles multiple simultaneous touch inputs for mobile interactions.
  • Haptic Feedback Integration: Built-in Vibration API support provides tactile response during joystick movement.
  • Dual Positioning Modes: Static mode fixes the joystick at a defined position, while dynamic mode spawns the control wherever the user touches.
  • Keyboard Emulation: Maps joystick directions to arrow keys or WASD for consistent input handling across devices.
  • Movement Constraints: Supports circular, square, and axis-locked movement patterns for different control schemes.
  • Customizable Appearance: Full control over colors, sizes, sensitivity, and visual feedback zones.
  • Real-Time Configuration: Update joystick settings dynamically without reinitializing the instance.

Use Cases:

  • Mobile HTML5 Games: Implement touch controls for canvas-based games where users need directional movement without covering the screen with their thumbs.
  • Progressive Web Applications: Add joystick navigation to PWAs that require spatial input, such as virtual tours, 3D model viewers, or interactive maps.
  • Accessibility Interfaces: Create alternative input methods for users who need larger, customizable touch targets instead of traditional button controls.
  • Prototype Testing: Rapidly test touch-based control schemes in web prototypes before committing to native mobile development.

How to use it:

1. Download the package and import the virtual-joystick.js into your project.

import VirtualJoystick from "./src/virtual-joystick.js";

2. Create an empty DIV container to hold the virtual joystick.

<div class="joystick"></div>

3. Create a new instance of the VirtualJoystick class and pass in a DOM element as the first argument to create the joystick interface.

const joystickContainer = document.querySelector('.joystick');
const joystick = new VirtualJoystick(joystickContainer, {
      // options
});

4. Available options to customize the virtual joystick.

OptionDefaultDescription
width100Width of the joystick base in pixels.
height100Height of the joystick base in pixels.
color“gray”Background color of the joystick base (legacy).
handleColor“white”Color of the joystick handle (legacy).
handleRadius20Radius of the joystick handle in pixels.
onChangenullCallback function triggered when the joystick position changes.
onStartnullCallback function triggered when user interaction starts.
onEndnullCallback function triggered when user interaction ends.
sensitivity1Multiplier for joystick movement sensitivity.
boundariesfalseIf true, constrains the handle movement strictly within the base.
autoCentertrueIf true, the handle returns to the center when released.
deadzone0.1Threshold (0-1) below which movement is ignored.
shape“circle”Shape of the joystick base (‘circle’ or ‘square’).
mode“static”Interaction mode: ‘static’ (fixed position) or ‘dynamic’ (appears on touch).
lockAxisnullLocks movement to a specific axis (‘x’ or ‘y’).
zones[]Array of zone objects for defining detection regions.
vibrationtrueEnables haptic feedback when entering zones (if supported).
themeObjectCustom styling object for ‘base’ and ‘handle’ appearances.
keyboardEmulationObjectConfiguration for mapping joystick directions to keyboard keys.
maxMoveRadiusnullOptional visual constraint radius; defaults to physical bounds if null.
const joystick = new VirtualJoystick(joystickContainer, {
  width: 100,
  height: 100,
  color: "gray",
  handleColor: "white",
  handleRadius: 20,
  onChange: null,
  onStart: null,
  onEnd: null,
  sensitivity: 1,
  boundaries: false,
  autoCenter: true,
  deadzone: 0.1,
  shape: "circle",
  mode: "static", // 'static' or 'dynamic'
  lockAxis: null, // null, 'x', or 'y'
  zones: [],
  vibration: true,
  theme: {
    base: {
      background: "rgba(128, 128, 128, 0.5)",
      border: "3px solid rgba(0, 0, 0, 0.8)",
      shadow: "0 0 10px rgba(0, 0, 0, 0.3)",
    },
    handle: {
      background: "rgba(255, 255, 255, 0.9)",
      border: "2px solid rgba(0, 0, 0, 0.8)",
      shadow: "0 0 5px rgba(0, 0, 0, 0.5)",
    },
  },
  keyboardEmulation: {
    enabled: false,
    map: {
      up: "ArrowUp",
      down: "ArrowDown",
      left: "ArrowLeft",
      right: "ArrowRight",
    },
  },
  maxMoveRadius: null,
});

5. API Methods

  • joystick.destroy(): Removes the joystick DOM elements and unbinds all event listeners.
  • joystick.setOption(key, value): Updates a specific setting in real-time without re-initializing.

Changelog:

v2.0 (12/10/2025)

  • update and complete remake

FAQs:

Q: How do I prevent the joystick from interfering with page scrolling on mobile devices?
A: Add touch-action: none to the container element’s CSS. This prevents the browser from interpreting touch events as scroll gestures.

Q: Can I use multiple joystick instances on the same page?
A: Yes. Create separate container elements and initialize independent VirtualJoystick instances for each. Each instance maintains its own event listeners and state. This works well for dual-stick control schemes in games.

Q: Why isn’t haptic feedback working on my device?
A: The Vibration API has limited browser support and requires user interaction to activate. Check navigator.vibrate availability before enabling haptics. iOS devices don’t support the Vibration API in web browsers.

You Might Be Interested In:


Leave a Reply