{"id":17332985,"url":"https://github.com/mvanderkamp/westures-core","last_synced_at":"2025-04-14T17:30:57.718Z","repository":{"id":33127515,"uuid":"150985158","full_name":"mvanderkamp/westures-core","owner":"mvanderkamp","description":"The core engine of the Westures gesture library for JavaScript.","archived":false,"fork":false,"pushed_at":"2024-10-28T12:39:23.000Z","size":4394,"stargazers_count":5,"open_issues_count":2,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-11-01T05:32:56.141Z","etag":null,"topics":["custom-gestures","gesture","javascript","javascript-library","mouse","multitouch","pan","pinch","pointer","rotate","swipe","swivel","tap","touch","westures-gesture-library","zingtouch"],"latest_commit_sha":null,"homepage":"https://mvanderkamp.github.io/westures-core/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mvanderkamp.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-09-30T16:38:05.000Z","updated_at":"2024-09-05T13:37:53.000Z","dependencies_parsed_at":"2023-01-14T23:32:31.042Z","dependency_job_id":"1cec5edb-5efc-4db6-ad46-d6a6b82207f7","html_url":"https://github.com/mvanderkamp/westures-core","commit_stats":{"total_commits":713,"total_committers":11,"mean_commits":64.81818181818181,"dds":"0.16690042075736322","last_synced_commit":"e56e860c7d225c5c57f1674af09973c7926b001f"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mvanderkamp%2Fwestures-core","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mvanderkamp%2Fwestures-core/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mvanderkamp%2Fwestures-core/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mvanderkamp%2Fwestures-core/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mvanderkamp","download_url":"https://codeload.github.com/mvanderkamp/westures-core/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":223639403,"owners_count":17177816,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["custom-gestures","gesture","javascript","javascript-library","mouse","multitouch","pan","pinch","pointer","rotate","swipe","swivel","tap","touch","westures-gesture-library","zingtouch"],"created_at":"2024-10-15T14:59:24.183Z","updated_at":"2024-11-08T06:03:11.427Z","avatar_url":"https://github.com/mvanderkamp.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# westures-core\n\n[![Node.js CI](https://github.com/mvanderkamp/westures-core/actions/workflows/node.js.yml/badge.svg)](https://github.com/mvanderkamp/westures-core/actions/workflows/node.js.yml)\n[![Coverage Status](https://coveralls.io/repos/github/mvanderkamp/westures-core/badge.svg?branch=main)](https://coveralls.io/github/mvanderkamp/westures-core?branch=main)\n[![Maintainability](https://api.codeclimate.com/v1/badges/a5f4a4745352d6e2520c/maintainability)](https://codeclimate.com/github/mvanderkamp/westures-core/maintainability)\n\nWestures is a robust n-pointer multitouch gesture detection library for\nJavaScript. This means that each gesture is be capable of working seamlessly as\ninput points are added and removed, with no limit on the number of input points,\nand with each input point contributing to the gesture.  It is also capable of\nworking across a wide range of devices.\n\nThis module contains the core functionality of the Westures gesture library for\nJavaScript. It is intended for use as a lighter-weight module to use if you do\nnot want to use the base gestures included with the standard [westures](\nhttps://mvanderkamp.github.io/westures/) module.\n\nVisit this page for an example of the system in action: [Westures Example](\nhttps://mvanderkamp.github.io/westures-example/).\n\nWestures aims to achieve its goals without using any dependencies, yet maintain\nusability across the main modern browsers. Transpilation may be necessary for\nthis last point to be achieved, as the library is written using many of the\nnewer features of the JavaScript language. A transpiled bundle is provided, but\nthe browser target list is arbitrary and likely includes some bloat. In most\ncases you will be better off performing bundling, transpilation, and\nminification yourself.\n\nWestures is a fork of [ZingTouch](https://github.com/zingchart/zingtouch).\n\n## Quick Example\n\n```javascript\n// Import the module.\nconst wes = require('westures-core');\n\n// Declare a region. The default is the window object, but other elements like\n// the document body work too.\nconst region = new wes.Region();\n\n// Define a Gesture subclass\nclass Follow extends wes.Gesture {\n  move(state) {\n    return state.centroid; // Reports the {x, y} of the average input position\n  }\n}\n\n// Locate an element to attach the gesture to.\nconst element = document.querySelector('#follow');\n\n// Instantiate a Gesture for an element within the region.\nconst follow = new Follow(element, (data) =\u003e {\n  // data.x ...\n  // data.y ...\n});\n\n// Add the gesture to the region.\nregion.addGesture(follow);\n```\n\n## Table of Contents\n\n- [Features](#features)\n- [Overview](#overview)\n- [Basic Usage](#basic-usage)\n- [Implementing Custom Gestures](#implementing-custom-gestures)\n- [Nomenclature and Origins](#nomenclature-and-origins)\n- [Changes](#changes)\n- [Issues](#issues)\n- [Links](#links)\n\n## Features\n\n- Full simultaneous multi-touch gesture support.\n    - Continuous use of pointer input allows seamless flow from gesture to\n      gesture without interruption.\n- Robust, simple to understand, easy to maintain engine.\n- Inertial smoothing capabilities for systems using coarse pointers (e.g. touch\n  surfaces).\n- Ability to enable / disable gestures with keys (e.g. ctrlKey, shiftKey)\n    - This allows for easy implementation of single-pointer flows that provide\n      the equivalent behaviour as multi-pointer flows. For example, holding\n      'CTRL' on a desktop could switch from panning mode to rotating mode.\n- Allows for easy implementation and integration of custom gestures using the\n  four-phase hook structure.\n\n## Overview\n\nThere are seven classes made available by this module:\n\nName        | Description\n----------- | -----------\nGesture     | Base class for defining westures gestures\nInput       | Track a single pointer through its lifetime\nPoint2D     | Store and act on a 2-dimensional point\nPointerData | Record data pertaining to a single user input event for a single pointer.\nRegion      | Listen for user input events and respond appropriately\nSmoothable  | Datatype which provides inertial smoothing capabilities\nState       | Track inputs within a Region\n\nAdditionally, two support files are defined:\n\nName      | Description\n--------- | -----------\nconstants | Constant values used throughout the engine\nutils     | Helpful utility functions\n\n## Basic Usage\n\n- [Declaring a Region](#declaring-a-region)\n- [Defining a Gesture Subclass](#defining-a-gesture-subclass)\n- [Instantiating a Gesture](#instantiating-a-gesture)\n- [Adding a Gesture to a Region](#adding-a-gesture-to-a-region)\n\n### Importing the module\n\n```javascript\nconst wes = require('westures-core');\n```\n\n### Declaring a Region\n\nFirst, decide what region should listen for events. This could be the\ninteractable element itself, or a larger region (possibly containing many\ninteractable elements). Behaviour may differ slightly based on the approach you\ntake, as a Region will perform locking operations on its interactable elements\nand their bound gestures so as to limit interference between elements during\ngestures, and no such locking occurs between Regions.\n\nIf you have lots of interactable elements on your page, you may find it\nconvenient to use smaller elements as regions. Test it out in any case, and see\nwhat works better for you.\n\nBy default, the window object is used.\n\n```javascript\nconst region = new wes.Region(document.body);\n```\n\n### Defining a Gesture Subclass\n\nIn order to use the engine, you'll need to define gestures. This is done by\nextending the Gesture class provided by this module, and overriding any or all\nof the four phase hooks ('start', 'move', 'end', and 'cancel') as is appropriate\nfor your gesture.\n\nDefined here is a very simple gesture that simply reports the centroid of the\ninput points. Note that the returned value must be an Object!\n\n```javascript\n// Define a Gesture subclass\nclass Follow extends wes.Gesture {\n  move(state) {\n    return state.centroid;\n  }\n}\n```\n\n### Instantiating a Gesture\n\nWhen you instantiate a gesture, you need to provide a handler as well as an\nElement. The gesture will only be recognized when the first pointer to interact\nwith the region was inside the given Element. Therefore unless you want to try\nsomething fancy the gesture element should probably be contained inside the\nregion element. It could even be the region element.\n\nNow for an example. Suppose you have a div within which you want to detect the\nFollow gesture we defined above. The div has id 'follow'. We need to find the\nelement first.\n\n```javascript\nconst element = document.querySelector('#follow');\n```\n\nAnd we also need a handler. This function will be called whenever a gesture hook\nreturns non-null data. For Follow, this is just the move phase, but the handler\ndoesn't need to know that. The data returned by the hook will be available\ninside the handler.\n\n```javascript\nfunction followLogger(data) {\n  console.log(\n    'The centroid of the points interacting with #follow is:',\n    'x:', data.x,\n    'y:', data.y,\n  )\n}\n```\n\nNow we're ready to combine the element and its handler into a gesture.\n\n```javascript\nconst follow = new Follow(element, followLogger);\n```\n\nWe're not quite done though, as none of this will actually work until you add\nthe gesture to the region.\n\n### Adding a Gesture to a Region\n\nSimple:\n\n```javascript\nregion.addGesture(follow);\n```\n\nNow the `followLogger` function will be called whenever a `follow` gesture is\ndetected on the `#follow` element inside the region.\n\n## Implementing Custom Gestures\n\nThe core technique used by Westures is to process all user inputs and filter\nthem through four key lifecycle phases: `start`, `move`, `end`, and `cancel`.\nGestures are defined by how they respond to these phases. To respond to the\nphases, a gesture extends the `Gesture` class provided by this module and\noverrides the method (a.k.a. \"hook\") corresponding to the name of the phase.\n\nThe hook, when called, will receive the current State object of the region. To\nmaintain responsiveness, the functionality within a hook should be short and as\nefficient as possible.\n\nFor example, a simple way to implement a `Tap` gesture would be as follows:\n\n```javascript\nconst { Gesture } = require('westures-core');\n\nconst TIMEOUT = 100;\n\nclass Tap extends Gesture {\n  constructor() {\n    super('tap');\n    this.startTime = null;\n  }\n\n  start(state) {\n    this.startTime = Date.now();\n  }\n\n  end(state) {\n    if (Date.now() - this.startTime \u003c= TIMEOUT) {\n        return state.getInputsInPhase('end')[0].current.point;\n    }\n    return null;\n  }\n}\n```\n\nThere are problems with this example, and it should probably not be used as an\nactual Tap gesture, it is merely to illustrate the basic idea.\n\nThe default hooks for all Gestures simply return null. Data will only be\nforwarded to bound handlers when a non-null value is returned by a hook.\nReturned values should be packed inside an object. For example, instead of just\n`return 42;`, a custom hook should do `return { value: 42 };`\n\nIf your Gesture subclass needs to track any kind of complex state, remember that\nit may be necessary to reset the state in the `cancel` phase.\n\nFor information about what data is accessible via the State object, see the full\ndocumentation [here](https://mvanderkamp.github.io/westures-core/westures-core.State.html).\nNote that his documentation was generated with `jsdoc`.\n\n### Default Data Passed to Handlers\n\nAs you can see from above, it is the gesture which decides when data gets passed\nto handlers, and for the most part what that data will be. Note though that a\nfew properties will get added to the outgoing data object before the handler is\ncalled. Those properties are:\n\nName     | Type     | Value\n-------- | -------- | -----\ncentroid | Point2D  | The centroid of the input points.\nevent    | Event    | The input event which caused the gesture to be recognized\nphase    | String   | `'start'`, `'move'`, `'end'`, or `'cancel'`\ntype     | String   | The name of the gesture as specified by its designer.\ntarget   | Element  | The Element that is associated with the recognized gesture.\n\nIf data properties returned by a hook have a name collision with one of these\nproperties, the value from the hook gets precedent and the default is\noverwritten.\n\n## Nomenclature and Origins\n\nIn my last year of univerisity, I was working on an API for building\nmulti-device interfaces called \"WAMS\" (Workspaces Across Multiple Surfaces),\nwhich included the goal of supporting multi-device gestures.\n\nAfter an extensive search I found that none of the available multitouch\nlibraries for JavaScript provided the fidelity I needed, and concluded that I\nwould need to write my own, or at least fork an existing one. ZingTouch proved\nto the be the most approachable, so I decided it would make a good starting\npoint.\n\nThe name \"westures\" is a mash-up of \"WAMS\" and \"gestures\".\n\n## Changes\n\nSee the [changelog](\nhttps://github.com/mvanderkamp/westures-core/blob/master/CHANGELOG.md) for the\nmost recent updates.\n\n## Issues\n\nIf you find any issues, please let me know!\n\n## Links\n\n### westures\n\n- [npm](https://www.npmjs.com/package/westures)\n- [github](https://github.com/mvanderkamp/westures)\n- [documentation](https://mvanderkamp.github.io/westures/)\n\n### westures-core\n\n- [npm](https://www.npmjs.com/package/westures-core)\n- [github](https://github.com/mvanderkamp/westures-core)\n- [documentation](https://mvanderkamp.github.io/westures-core/)\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmvanderkamp%2Fwestures-core","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmvanderkamp%2Fwestures-core","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmvanderkamp%2Fwestures-core/lists"}