;
onMounted(() => {
- if (!square.value) return;
+ if (!container.value || !square.value) return;
+ const squareRect = square.value.getBoundingClientRect();
+ const bodyRect = container.value.getBoundingClientRect();
+ data.x = (bodyRect.width - squareRect.width) / 2;
+ data.y = (bodyRect.height - squareRect.height) / 2;
pointeract = new Pointeract(
{
- element: square.value,
+ element: container.value,
lubricator: {
drag: dragPreset,
pan: panPreset,
@@ -50,32 +63,37 @@ onMounted(() => {
},
},
[PreventDefault, WheelPanZoom, MultitouchPanZoom, Click, Drag, Lubricator],
- ).start();
- pointeract.on('pan', (e) => {
- data.x += e.detail.deltaX;
- data.y += e.detail.deltaY;
- });
- pointeract.on('drag', (e) => {
- data.x += e.detail.deltaX;
- data.y += e.detail.deltaY;
- });
- pointeract.on('zoom', (e) => {
- const detail = e.detail;
- data.scale *= detail.factor;
- data.x += detail.x * (1 - detail.factor);
- data.y += detail.y * (1 - detail.factor);
- });
- pointeract.on('trueClick', (e) => {
- data.streak = e.detail.streak;
- if (streakTimeout) clearTimeout(streakTimeout);
- streakTimeout = setTimeout(() => {
- data.streak = 0;
- }, 400);
- });
+ )
+ .start()
+ .on('pan', (e) => {
+ data.x += e.deltaX;
+ data.y += e.deltaY;
+ })
+ .on('drag', (e) => {
+ data.x += e.deltaX;
+ data.y += e.deltaY;
+ })
+ .on('zoom', (e) => {
+ data.scale *= e.factor;
+ const canvas = C2C(e);
+ data.x = e.x - canvas.x * e.factor;
+ data.y = e.y - canvas.y * e.factor;
+ })
+ .on('trueClick', (e) => {
+ data.streak = e.streak;
+ if (streakTimeout) clearTimeout(streakTimeout);
+ streakTimeout = setTimeout(() => {
+ data.streak = 0;
+ }, 400);
+ });
});
onBeforeUnmount(() => {
pointeract.dispose();
+ if (streakTimeout) {
+ clearTimeout(streakTimeout);
+ streakTimeout = null;
+ }
});
@@ -96,14 +114,12 @@ onBeforeUnmount(() => {
display: flex;
align-items: center;
justify-content: center;
- top: calc(50% - 150px);
- left: calc(50% - 150px);
width: 300px;
height: 300px;
color: white;
background-color: rgb(72, 130, 255);
border-radius: 16px;
- transform-origin: 0 0;
+ transform-origin: top left;
box-shadow: 0px 0px 16px rgba(0, 0, 0, 0.3);
font-size: 100px;
font-weight: bold;
diff --git a/docs/en/basic/index.md b/docs/en/basic/index.md
deleted file mode 100644
index ef7f595..0000000
--- a/docs/en/basic/index.md
+++ /dev/null
@@ -1,51 +0,0 @@
-# Base Class
-
-Everything Pointeract does is based on this class.
-
-## TL;DR CheatSheet
-
-| Description | Method |
-| ------------------------------------------------------- | ------------------------------------------------- |
-| [Instantiate the Class](/basic/lifecycle#instantiation) | `new Pointeract(element, modules, options?)` |
-| [Start Base Class](/basic/lifecycle#start) | `start()` |
-| [Stop Base Class](/basic/lifecycle#stop) | `stop()` |
-| [Start Modules](/basic/module-lifecycle#start-and-stop) | `start(moduleConstructor \| ModuleConstructor[])` |
-| [Stop Modules](/basic/module-lifecycle#start-and-stop) | `stop(moduleConstructor \| ModuleConstructor[])` |
-| [Subscribe](/basic/subscribe-unsubscribe#subscribe) | `on(eventName, callback)` |
-| [Unsubscribe](/basic/subscribe-unsubscribe#unsubscribe) | `off(eventName, callback)` |
-| [Get Event Types](/events/#obtain-event-types) | `typeof events.
` |
-| [Dispose](/basic/lifecycle#disposal) | `dispose()` |
-
-## Full Example
-
-```TypeScript
-import { Pointeract, Drag, PreventDefault } from 'pointeract';
-
-const app = document.getElementById('app') as HTMLDivElement;
-const options = {
- coordinateOutput: 'absolute',
-}
-const pointeract = new Pointeract(app, [Drag, PreventDefault], options).start();
-
-const hook = (e: typeof pointeract.events.drag) => {
- console.log(e.detail);
-};
-
-// Subscribe to drag events
-const unsubscribe = pointeract.on('drag', hook);
-// Unsubscribe
-unsubscribe();
-// Or: pointeract.off('drag', hook);
-
-// Hot update options
-options.coordinateOutput = 'relative';
-
-// Pause
-pointeract.stop();
-// Resume
-pointeract.start();
-pointeract.stop(PreventDefault); // Disable PreventDefault only
-
-// Dispose
-pointeract.dispose();
-```
diff --git a/docs/en/basic/lifecycle.md b/docs/en/basic/lifecycle.md
deleted file mode 100644
index 9d412c5..0000000
--- a/docs/en/basic/lifecycle.md
+++ /dev/null
@@ -1,96 +0,0 @@
-# Lifecycle
-
-## Instantiation
-
-First, import the class:
-
-```TypeScript
-import { Pointeract } from 'pointeract';
-```
-
-You may also want to grab some modules, find them in [Modules](/modules/):
-
-```TypeScript
-import { Drag, PreventDefault } from 'pointeract';
-```
-
-Then, you need a DOM element to attach to, below shows how to do that in Vanilla DOM:
-
-::: code-group
-
-```TypeScript [TypeScript]
-const app = document.getElementById('app') as HTMLDivElement;
-```
-
-```HTML [HTML]
-
-```
-
-:::
-
-Finally, you may want to define options, read elaboration in [Options](./options):
-
-```TypeScript
-const options = {
- coordinateOutput: 'absolute',
-}
-```
-
-Now, you can create a Pointeract instance by passing the element, modules, and options in a row, note that the `options` is optional:
-
-```TypeScript
-const pointeract = new Pointeract(app, [Drag, PreventDefault], options);
-```
-
-::: info
-Pointeract uses TypeScript generics to smartly infer the types of options and events available by scanning every module passed into the constructor.
-:::
-
-## Start
-
-Pointeract does not do anything after initialization by design, make it running by calling `start()`:
-
-```TypeScript
-pointeract.start();
-```
-
-::: tip
-`start()` returns the instance itself, so you can chain it:
-
-```TypeScript
-const pointeract = new Pointeract(app, [Drag, PreventDefault]); // [!code --]
-const pointeract = new Pointeract(app, [Drag, PreventDefault]).start(); // [!code ++]
-```
-
-:::
-
-## Stop
-
-To stop Pointeract, call `stop()`:
-
-```TypeScript
-pointeract.stop();
-```
-
-::: tip
-`stop()` also returns the class instance and does not destroy it. You can start it again later:
-
-```TypeScript
-pointeract.stop();
-// ... some logic here
-pointeract.start();
-```
-
-:::
-
-## Disposal
-
-To completely dispose Pointeract, call `dispose()`:
-
-```TypeScript
-pointeract.dispose();
-```
-
-::: tip
-You don't need to call `stop()` before disposal, `dispose()` handles everything for you.
-:::
diff --git a/docs/en/basic/module-lifecycle.md b/docs/en/basic/module-lifecycle.md
deleted file mode 100644
index 37a1535..0000000
--- a/docs/en/basic/module-lifecycle.md
+++ /dev/null
@@ -1,37 +0,0 @@
-# Module Lifecycle
-
-## Instantiation
-
-All modules are instantiated when a Pointeract instance is constructed.
-
-## Start and Stop
-
-To turn on/off modules at runtime, also use `start()` and `stop()`. For these two methods, if you do not pass any arguments, they will start/stop the Pointeract instance; otherwise the specified modules. All modules passed in are enabled by default at Pointeract construction.
-
-You start/stop modules by passing in the **constructors** of modules, the methods accept a single module or an array of modules:
-
-```TypeScript
-pointeract.start(PreventDefault); // single module
-pointeract.stop([PreventDefault, Drag]); // multiple modules
-```
-
-::: tip
-Note that the start/stop of modules are independent to the start/stop of the base class: when the base class is stopped, all modules will be paused; but when the base class is started, only modules not explicitly stopped will be resumed. E.g.:
-
-```TypeScript
-// remember we have modules PreventDefault and Drag
-pointeract.stop(); // everything is paused
-pointeract.stop(PreventDefault); // no apparent change, but PreventDefault is disabled at module level
-pointeract.start(); // only the base class and Drag are started
-pointeract.start(PreventDefault); // PreventDefault will not be restarted unless explicitly reenabled here
-```
-
-:::
-
-::: warning
-You cannot start/stop a module that is not passed into the Pointeract constructor.
-:::
-
-## Disposal
-
-All modules of a instance are collectively disposed when the `dispose()` it is called.
diff --git a/docs/en/basic/options.md b/docs/en/basic/options.md
deleted file mode 100644
index b1c1cc5..0000000
--- a/docs/en/basic/options.md
+++ /dev/null
@@ -1,50 +0,0 @@
-# Options
-
-## Define Options
-
-Options are defined as an object and passed as the third argument of a Pointeract constructor:
-
-```TypeScript
-const options = {
- coordinateOutput: 'absolute',
-}
-const pointeract = new Pointeract(app, [Drag, PreventDefault], options);
-```
-
-## Base Options
-
-Most options are provided by [modules](/modules/), the only exception is `coordinateOutput` which is shipped with the base class:
-
-```TypeScript
-type options = {
- coordinateOutput: 'absolute' | 'relative' | 'relativeFraction';
-}
-```
-
-It defines how the coordinates are output across Pointeract, options are:
-
-- `absolute`: screen coordinates in pixels
-- `relative`(default): relative to the top-left corner of the element in pixels
-- `relativeFraction`: relative to the top-left corner of the element divided by the element's size
-
-## Update Options
-
-Pointeract uses the same `options` reference passed in the constructor, so you can reactively update options during runtime, or batch update options for many Pointeract instances at once:
-
-```TypeScript
-import { Pointeract, WheelPanZoom, Options } from 'pointeract';
-
-const options: Options = {
- coordinateOutput: 'absolute', // output absolute coordinates
-}
-
-const pointeract = new Pointeract(document.body, WheelPanZoom, options);
-
-options.coordinateOutput = 'relative'; // output format instantly changes to relative
-```
-
-::: tip
-To ensure type safety of options, you can import `Options` from `pointeract` and assign it to your options object, it accepts a single module constructor or a list of modules constructors as type parameter.
-
-You need to use `typeof ` to get the constructor type of the module.
-:::
diff --git a/docs/en/basic/subscribe-unsubscribe.md b/docs/en/basic/subscribe-unsubscribe.md
deleted file mode 100644
index 7b068b2..0000000
--- a/docs/en/basic/subscribe-unsubscribe.md
+++ /dev/null
@@ -1,28 +0,0 @@
-# Subscribe/Unsubscribe
-
-## Subscribe
-
-Use `on()` to subscribe, the usage is similar to `addEventListener()`, but is fully typed and returns the corresponding unsubscribe function.
-
-Pointeract utilizes native [EventTarget](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget) internally, the events are `CustomEvent`s and event data is stored in `e.detail`.
-
-```TypeScript
-const hook = (e: typeof pointeract.events.drag) => {
- console.log(e.detail);
-};
-const unsubscribe = pointeract.on('drag', hook);
-```
-
-## Unsubscribe
-
-Use `off()` or returned unsubscribe functions to unsubscribe, also similar to `removeEventListener()`:
-
-```TypeScript
-unsubscribe();
-// or:
-pointeract.off('drag', hook);
-```
-
-::: tip
-Its good practice to unsubscribe all the events **before** the disposal of a Pointeract instance.
-:::
diff --git a/docs/en/basic/types.md b/docs/en/basic/types.md
new file mode 100644
index 0000000..5401bc5
--- /dev/null
+++ b/docs/en/basic/types.md
@@ -0,0 +1,92 @@
+# Access Types
+
+Pointeract implements advanced type orchestration engine, which serves as a key component of its modularity and flexibility.
+
+## Key Concepts
+
+The `Pointeract` class is purely a module loader. It does nothing else than managing module lifecycles. The class comes with some pre-defined **standard events (`StdEvents`)**, some base options (`BaseOptions`), and some class methods and properties.
+
+All the functionalities are achieved by modules, they add custom events and options by extending `StdEvents` and `BaseOptions`, as well as augmenting the `Pointeract` instance by injecting custom methods and properties.
+
+Everything modules extend is done declaratively, and the type orchestration of all options, events and instance properties is done automatically when you load modules.
+
+This architecture can create highly modular apps and nice DX. Here we provide you comprehensive types to ensure you always can access what you need.
+
+:::tip
+All the types shown below are designed to be flexible, they accept:
+
+- a single constructor / instance
+- an array of either module constructors / instances
+- nothing
+
+as their type parameters
+
+for example:
+
+```TypeScript
+import { Drag, PreventDefault, type Options } from "pointeract";
+
+type MyOptions1 = Options<[Drag, PreventDefault]>;
+type MyOptions2 = Options<[typeof Drag, typeof PreventDefault]>;
+type MyOptions3 = Options;
+type MyOptions3 = Options;
+type MyOptions4 = Options;
+```
+
+In the example above, `MyOptions1` and `MyOptions2`, `MyOptions3` and `MyOptions4` are equivalent, `MyOptions4` is the base options.
+:::
+
+## Options
+
+Pointeract automatically orchestrates the type of the options when you instantiate the class:
+
+```TypeScript
+import { Pointeract, Click } from 'pointeract';
+
+new Pointeract({});
+// available options: element, coordinateOutput
+
+new Pointeract({}, Click);
+// available options: element, coordinateOutput, clickPreserveTime, moveThreshold
+```
+
+If you need to access the type elsewhere, simply use the `Options` export, pass the same modules as the ones in your constructor:
+
+```TypeScript
+import { Options, Click } from 'pointeract';
+
+type AvailableOptions = Options;
+// available options: coordinateOutput, element, clickPreserveTime, moveThreshold
+```
+
+## Events
+
+Like `Options`, simply use the `Events` export:
+
+```TypeScript
+import { Events, Click } from 'pointeract';
+
+type AvailableEvents = Events;
+// available events: pan, zoom, drag, trueClick
+```
+
+To use the type of a single event, simply extract one:
+
+```TypeScript
+type PanEvents = Events['pan'];
+
+const onPan = (e: PanEvent) => console.log(e);
+```
+
+## Interface
+
+As simple as usual, you can use the `PointeractInterface` exported class:
+
+```TypeScript
+import { PointeractInterface, Pointeract, Click } from 'pointeract';
+
+const instance = new Pointeract({}, Click);
+type InstanceType = PointeractInterface;
+```
+
+Above, `InstanceType` is exactly the type of `instance`.
diff --git a/docs/en/basic/use-pointeract.md b/docs/en/basic/use-pointeract.md
new file mode 100644
index 0000000..dea5f35
--- /dev/null
+++ b/docs/en/basic/use-pointeract.md
@@ -0,0 +1,245 @@
+# Use the `Pointeract` Class
+
+Everything Pointeract does is based on this class. It serves as an orchestrator of all the modules, interfaces and events.
+
+## CheatSheet
+
+| Description | Method |
+| --------------------------------------- | ------------------------------------------------------------ |
+| [Instantiate the Class](#instantiation) | `new Pointeract(element, modules, options?)` |
+| [Start Base Class](#start-and-stop) | `pointeract.start()` |
+| [Stop Base Class](#start-and-stop) | `pointeract.stop()` |
+| [Start Modules](#modules) | `pointeract.start(ModuleConstructor \| ModuleConstructor[])` |
+| [Stop Modules](#modules) | `pointeract.stop(ModuleConstructor \| ModuleConstructor[])` |
+| [Subscribe](#subscribe) | `pointeract.on(eventName, callback)` |
+| [Unsubscribe](#unsubscribe) | `pointeract.off(eventName, callback)` |
+| [Dispose](#disposal) | `pointeract.dispose()` |
+
+## Lifecycle
+
+`Pointeract` implements a four-stage runtime pattern and runtime module resume / reloading pattern to meet various flexibility requirements.
+
+### Instantiation
+
+First, import the class:
+
+```TypeScript
+import { Pointeract } from 'pointeract';
+```
+
+You may also want to grab some modules, find them in [Modules](/modules/):
+
+```TypeScript
+import { Drag, PreventDefault } from 'pointeract';
+```
+
+Then, you need a DOM element to attach to, below shows how to do that in Vanilla DOM:
+
+::: code-group
+
+```TypeScript [TypeScript]
+const app = document.getElementById('app') as HTMLDivElement;
+```
+
+```HTML [HTML]
+
+```
+
+:::
+
+Finally, you may want to define options, read elaboration in [Options](#options):
+
+```TypeScript
+const options = {
+ element: app,
+ coordinateOutput: 'absolute',
+}
+```
+
+Now, you can create a Pointeract instance by passing the options and modules in a row, note that the `modules` is optional:
+
+```TypeScript
+const pointeract = new Pointeract(options, [Drag, PreventDefault]);
+```
+
+::: info
+Pointeract uses TypeScript generics to smartly infer the types of options, events, and class methods available by scanning every module passed into the constructor.
+:::
+
+### Start and Stop
+
+Pointeract does not do anything after initialization by design, make it running by calling `start()`:
+
+```TypeScript
+pointeract.start();
+```
+
+To stop Pointeract, call `stop()`:
+
+```TypeScript
+pointeract.stop();
+```
+
+::: tip
+`stop()` also returns the class instance and does not destroy it. You can resume it later:
+
+```TypeScript
+pointeract.stop();
+// ... some logic here
+pointeract.start();
+```
+
+:::
+
+### Disposal
+
+To completely dispose Pointeract, call `dispose()`:
+
+```TypeScript
+pointeract.dispose();
+```
+
+::: tip
+You don't need to call `stop()` or unsubscribe all event listeners before disposal, `dispose()` handles everything for you.
+:::
+
+### Modules
+
+All modules are instantiated during the construction of `Pointeract` and disposed together when it is disposed.
+
+To turn on/off modules at runtime, also use `start()` and `stop()`. For these two methods, if you do not pass any arguments, they will start/stop the Pointeract instance; otherwise the specified modules. All modules passed in are enabled by default at Pointeract construction.
+
+You start/stop modules by passing in the **constructors** of modules, the methods accept a single module or an array of modules:
+
+```TypeScript
+pointeract.start(PreventDefault); // single module
+pointeract.stop([PreventDefault, Drag]); // multiple modules
+```
+
+::: tip
+Note that the start/stop of modules are independent to the start/stop of the base class: when the base class is stopped, all modules will be paused; but when the base class is started, only modules not explicitly stopped will be resumed. E.g.:
+
+```TypeScript
+// we have modules PreventDefault and Drag
+pointeract.stop(); // everything is paused
+pointeract.stop(PreventDefault); // no apparent change, but PreventDefault is disabled at module level
+pointeract.start(); // only the base class and Drag are started
+pointeract.start(PreventDefault); // PreventDefault will not be restarted unless explicitly reenabled here
+```
+
+:::
+
+::: warning
+You cannot load a module that is not passed into the Pointeract constructor after the construction.
+:::
+
+## Subscribe to Events
+
+### Subscribe
+
+Use `on()` to subscribe, the usage is similar to `addEventListener()`, but is fully typed and returns the corresponding unsubscribe function.
+
+Pointeract utilizes native [EventTarget](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget) internally, the events are `CustomEvent`s and event data is stored in `e.detail`.
+
+```TypeScript
+const hook = (e: typeof pointeract.events.drag) => {
+ console.log(e.detail);
+};
+const unsubscribe = pointeract.on('drag', hook);
+```
+
+### Unsubscribe
+
+Use `off()` or returned unsubscribe functions to unsubscribe, also similar to `removeEventListener()`:
+
+```TypeScript
+unsubscribe();
+// or:
+pointeract.off('drag', hook);
+```
+
+## Options
+
+### Define Options
+
+Options are defined as an object and passed as the third argument of a Pointeract constructor:
+
+```TypeScript
+const options = {
+ coordinateOutput: 'absolute',
+}
+const pointeract = new Pointeract(app, [Drag, PreventDefault], options);
+```
+
+### Base Options
+
+Most options are provided by [modules](/modules/), the only two exceptions are `coordinateOutput` and `element` shipped with the `Pointeract` class:
+
+```TypeScript
+interface BaseOptions {
+ element: HTMLElement;
+ coordinateOutput?: 'absolute' | 'relative' | 'relativeFraction';
+}
+```
+
+**`element`** (required): the element to monitor.
+
+**`coordinateOutput`**: defines the output coordinates format across Pointeract:
+
+- `absolute`: screen coordinates in pixels
+- `relative`(default): relative to the top-left corner of the element in pixels
+- `relativeFraction`: relative to the top-left corner of the element divided by the element's size
+
+### Update Options
+
+Pointeract uses the same `options` reference passed in the constructor, you can reactively update options during runtime, or batch update options for many Pointeract instances at once:
+
+```TypeScript
+import { Pointeract, WheelPanZoom, Options } from 'pointeract';
+
+const options: Options = {
+ coordinateOutput: 'absolute', // output absolute coordinates
+}
+
+const pointeract = new Pointeract(document.body, WheelPanZoom, options);
+
+options.coordinateOutput = 'relative'; // output format instantly changes to relative
+```
+
+## Full Example
+
+```TypeScript
+import { Pointeract, Drag, PreventDefault, Events } from 'pointeract';
+
+function hook(e: Events['drag']) {
+ console.log(e);
+};
+
+const app = document.getElementById('app') as HTMLDivElement;
+const options = {
+ element: app,
+ coordinateOutput: 'absolute',
+}
+
+// instantiate the class and subscribe
+const pointeract = new Pointeract(options, [Drag, PreventDefault])
+ .start()
+ .on('drag', hook);
+
+// Hot update options
+options.coordinateOutput = 'relative';
+
+// Unsubscribe
+pointeract.off('drag', hook);
+
+// Pause
+pointeract.stop();
+// Resume
+pointeract.start();
+
+// Disable PreventDefault only
+pointeract.stop(PreventDefault);
+
+// Dispose
+pointeract.dispose();
+```
diff --git a/docs/en/development/custom-events.md b/docs/en/development/custom-events.md
deleted file mode 100644
index 820c503..0000000
--- a/docs/en/development/custom-events.md
+++ /dev/null
@@ -1,46 +0,0 @@
-# Custom Events
-
-The events that can be emitted by your modules are not limited to the ones listed in [Standard Events](/events/#standard-events). You can literally emit any event you want.
-
-## Extending `StdEvents`
-
-You may have seen a type error when trying to emit a custom event within a module:
-
-```TypeScript
-import { BaseModule } from 'pointeract';
-
-class YourModule extends BaseModule {
- onPointerMove = () => {
- this.utils.dispatch('moveMove'); // TypeError: Argument of type '"moveMove"' is not assignable to parameter of type '"pan" | "drag" | "trueClick" | "zoom"'.
- };
-}
-```
-
-That's because Pointeract aims to provide the best-in-class type safety, if you want to use custom events, you first need to declare your custom events by extending `StdEvents`:
-
-```TypeScript
-import { BaseModule } from 'pointeract'; // [!code --]
-import { BaseModule, StdEvents } from 'pointeract'; // [!code ++]
-interface CustomEvents extends StdEvents { // [!code ++]
- moveMove: CustomEvent; // add an event with no detail // [!code ++]
- moveDetail: CustomEvent<{ x: number; y: number }>; // add an event with detail of coordinates // [!code ++]
-} // [!code ++]
-```
-
-Then you can pass your custom events to `BaseClass` as a type parameter:
-
-```TypeScript
-class YourModule extends BaseModule { // [!code --]
-class YourModule extends BaseModule { // [!code ++]
- onPointerMove = () => {
- this.utils.dispatch('moveMove'); // no error
- this.utils.dispatch('moveDetail', { x: 0, y: 0 }); // no error
- };
-}
-```
-
-Then you can dispatch your custom events. Yourself and your module users will gain full type safety.
-
-> **Reference to**:
->
-> - [MDN CustomEvent](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent)
diff --git a/docs/en/development/custom-modules.md b/docs/en/development/custom-modules.md
index ea18822..2c14efe 100644
--- a/docs/en/development/custom-modules.md
+++ b/docs/en/development/custom-modules.md
@@ -14,67 +14,85 @@ class MyModule extends BaseModule {
}
```
-::: tip
-In most cases, a Pointeract module does not need construction by yourself, which is done in `BaseModule`.
-:::
+If you want to customize the construction process, grab `BaseArgs` and spread the constructor parameters into `super()`:
+
+```TypeScript
+import { BaseModule, type BaseArgs } from 'pointeract';
+
+class MyModule extends BaseModule {
+ constructor(...args: BaseArgs) {
+ super(...args);
+ // ... your logic
+ }
+}
+```
+
+## Type Orchestration
+
+`BaseModule` accepts the type parameters as: `BaseModule`.
+
+It uses default declarations if no parameters are provided:
+
+- Events: `StdEvents`
+- Options: `BaseOptions`
+- Augmentation: `{}`
+
+Modules claim their custom [events](#custom-events), [options](#custom-options) and [Augmentation](#augment-the-pointeract-instance) declaratively, which are then used in the type orchestration engine to provide first-of-class type safety, modularity and DX.
+
+You can always declare you custom ones by extending either one above and pass to `BaseModule`.
## Properties
-This class provides the basic stuff for a module:
+This class provides the basic data and helpers for a module:
```TypeScript
class BaseModule {
+ options: ;
element: HTMLElement;
window: Window;
pointers: Map;
- utils: {
- getNthPointer: (n: number) => Pointer;
- screenToTarget: (raw: Coordinates) => Coordinates;
- dispatch: (name: string, detail?: unknown) => void;
- getLast: (arr: T[], num?: number) => T;
- }
+ getNthPointer: (n: number) => Pointer;
+ toTargetCoords: (raw: Coordinates) => Coordinates;
+ augment: () => void;
+ dispatch: (name: , detail?: ) => void;
}
type Pointer = {
- records: Array<{ x: number; y: number; timestamp: number }>; // pointer records, coordinates are absolute screen coords
- target: EventTarget | null;
- [key: Indexable]: any; // your can add your own properties into a pointer, the key can be a string, number or symbol
+ records: Array<{ x: number; y: number; timestamp: number }>; // pointer records, coordinates are absolute screen coords
+ target: EventTarget | null;
+ [key: Indexable]: any; // your can add your own properties into a pointer, the key can be a string, number or symbol
};
```
-- `element`: The element to be monitored, the same as the first argument passed into the constructor.
+- `element`: The element to be monitored, the same as the `event` field in `BaseOptions`.
- `window`: The window context of the monitoring element. It's always better practice to use `this.window` instead of direct `window` in a module.
+- `options`: The full options that the suer passes in.
- `pointers`: A hot-updated map of pointers, the key is the pointer ID, the value is a pointer object.
-- `utils`: A set of utilities for a module:
- - `getNthPointer`: Get the nth pointer value in the pointers map.
- - `screenToTarget`: Convert screen coordinates to target coordinates that is configured by `coordinateOutput`, always use it if you are emitting events that involve coordinates.
- - `dispatch`: Dispatch an event with a given name and detail.
- - `getLast`: A pure functional utility: get the last element in an array.import { BaseModule } from 'pointeract';
+- `getNthPointer`: Get the nth pointer value in the pointers map.
+- `toTargetCoords`: Convert screen coordinates to target coordinates that is configured by `coordinateOutput`, always use it if you are emitting events that involve coordinates.
+- `dispatch`: Dispatch an event with a given name and detail.
+- `augment`: inject properties into the parent `Pointeract` instance, you must provide what you have passed in as `Augmentations` in the type parameters.
## Hooks
```TypeScript
class BaseModule {
- onPointerDown?: (...args: [PointerEvent, Pointer, Pointers]) => void;
- onPointerMove?: (...args: [PointerEvent, Pointer, Pointers]) => void;
- onPointerUp?: (...args: [PointerEvent, Pointer, Pointers]) => void;
- onWheel?: (...args: [WheelEvent]) => void;
- onStart?: () => void;
- onStop?: () => void;
- modifier?: () => ModifierReturn;
+ onPointerDown?: (...args: [PointerEvent, Pointer, Pointers]) => void;
+ onPointerMove?: (...args: [PointerEvent, Pointer, Pointers]) => void;
+ onPointerUp?: (...args: [PointerEvent, Pointer, Pointers]) => void;
+ onWheel?: (...args: [WheelEvent]) => void;
+ onStart?: () => void;
+ onStop?: () => void;
dispose?: () => void;
}
-
-type ModifierReturn = true | false | { name: string; detail: unknown };
```
- `onPointerDown`: Triggered when a pointer is pressed (same to `pointerdown` event but with extra context and avoids repeatedly adding listeners).
- `onPointerMove`: Triggered when a pointer is moved (same to `pointermove` event).
- `onPointerUp`: Triggered when a pointer is released (same to `pointerup` event).
- `onWheel`: Triggered when a wheel event is triggered (same to `wheel` event).
-- `onStart`: Triggered when the module is started (`pointeract.start(MyModule)`).
-- `onStop`: Triggered when the module is stopped (`pointeract.stop(MyModule)`).
-- `modifier`: Triggered when an event is about to be dispatched. (find more details in [Modifier](/development/modifier))
+- `onStart`: Triggered when the module is started or after construction (`pointeract.start(MyModule)`).
+- `onStop`: Triggered when the module is stopped or before disposal (`pointeract.stop(MyModule)`).
- `dispose`: Triggered when the module and the Pointeract instance is disposed (`pointeract.dispose()`).
::: tip
@@ -88,6 +106,121 @@ Always remember to use arrow functions when defining these hooks, otherwise the
## Dispatching Events
-Use `this.utils.dispatch()` to dispatch an event, the second argument will be assigned to the `detail` property of the event.
+Use `this.dispatch(name, detail)` to dispatch an event, the first argument is the event name, the second one is the event body, which can be undefined.
+
+There are [existing event types](/events/) that you can follow, or you can [write your own events](#custom-events).
+
+## Modifiers
-There are [existing event types](/events/) that you can follow, or you can [write your own events](/development/custom-events).
+Since all tasks Pointeract does is to dispatch all kinds of events, you can alter anything by intercepting events.
+
+Modifier is such a powerful tool that allows you to read, intercept, and modify all events before they are dispatched.
+
+### Define a Modifier
+
+Use the `modifier` hook in a module to define modifiers, it consists any number of fields: the key is the name of the event you want to modify, and the value is the handler function. For the function: argument is the body of the raw event.
+
+```TypeScript
+class BaseModule {
+ modifiers?: {
+ [Key in ]?: (event: ) => boolean | ;
+ };
+}
+```
+
+### Modifier Return
+
+- `true`: The event will be kept as-is and dispatched.
+- `false`: The event will be ignored.
+- ``: The event will be dispatched with your custom data, you still need to follow the corresponding event type.
+
+The example above monitors the zoom event and logs the number of times it has been dispatched. It keeps all events unchanged.
+
+::: info
+When multiple modifiers are used, the first modifier that does not return `true` will be the only one that is executed.
+:::
+
+## Custom Events
+
+The events that can be emitted by your modules are not limited to the ones listed in [Standard Events](/events/). You can literally emit any event you want.
+
+### Extending `StdEvents`
+
+If you want to use custom events, you first need to declare your custom events by extending `StdEvents`:
+
+```TypeScript
+import { BaseModule, StdEvents, BaseOptions } from 'pointeract';
+
+interface CustomEvents extends StdEvents {
+ moveMove: undefined; // add an event with no detail
+ moveDetail: { x: number; y: number }; // add an event with detail of coordinates
+}
+```
+
+Then you can pass your custom events to `BaseClass` as a type parameter:
+
+```TypeScript
+class YourModule extends BaseModule {
+ onPointerMove = () => {
+ this.utils.dispatch('moveMove'); // no error
+ this.utils.dispatch('moveDetail', { x: 0, y: 0 }); // no error
+ };
+}
+```
+
+Then you can dispatch your custom events. Yourself and your module users will gain full type safety.
+
+## Custom Options
+
+Pointeract inherits the same `options` reference from the constructor across the base class and all modules.
+
+You also need to make an interface extend `BaseOptions` to declare the types.
+
+```TypeScript
+import { BaseModule, BaseOptions } from 'pointeract';
+
+interface Options extends BaseOptions {
+ moduleEnabled?: boolean,
+}
+
+class YourModule extends BaseModule {
+ onPointerMove = () => {
+ if (!this.options.moduleEnabled) return; // no error
+ }
+}
+```
+
+## Augment the `Pointeract` Instance
+
+Almost same as options and events, but this time you don't need to extend anything since the default augmentation is empty. You also need to manually call `this.augment()` in your constructor.
+
+```TypeScript
+import { BaseModule, BaseOptions, StdEvents, BaseArgs } from 'pointeract';
+
+interface Augmentation {
+ log: YourModule['log'];
+}
+
+export default class YourModule extends BaseModule {
+ private log = () => console.log('log injected!');
+
+ constructor(...args: BaseArgs) {
+ super(...args);
+ this.augment({ log: this.log });
+ }
+}
+```
+
+Then when you instantiate the `Pointeract` class with your module loaded, you can see `log` appearing directly in the `Pointeract` instance:
+
+```TypeScript
+import { Pointeract } from 'pointeract';
+import YourModule from './your-module';
+
+const instance = new Pointeract({ element: app }, YourModule);
+instance.log();
+
+// Result:
+// no type error
+// 'log injected!' appears in the console
+```
diff --git a/docs/en/development/custom-options.md b/docs/en/development/custom-options.md
deleted file mode 100644
index 3a3431f..0000000
--- a/docs/en/development/custom-options.md
+++ /dev/null
@@ -1,33 +0,0 @@
-# Custom Options
-
-Pointeract inherits the same `options` reference from the constructor across the base class and all modules.
-
-## Define Options
-
-Simply use the `options` property to define options with their default values:
-
-```TypeScript
-import { BaseModule } from 'pointeract';
-
-class YourModule extends BaseModule {
- options = {
- customModule: true,
- };
-}
-```
-
-Pointeract will process options in your modules, when the user of your module passes the it into Pointeract, they will get full type completions.
-
-## Use Options
-
-Simply use the options you just defined in your module:
-
-```TypeScript
-class YourModule extends BaseModule {
- onPointerMove = () => {
- if (this.options.customModule) console.log('custom module is enabled');
- }
-}
-```
-
-Your options will be merged into the user options passed into Pointeract. So when you access your options, it's already polyfilled with the user's options.
diff --git a/docs/en/development/modifier.md b/docs/en/development/modifier.md
deleted file mode 100644
index bea5140..0000000
--- a/docs/en/development/modifier.md
+++ /dev/null
@@ -1,41 +0,0 @@
-# Modifier
-
-Since all tasks Pointeract does is to dispatch all kinds of events, once you've controlled the channel of events, you would own the absolute power of Pointeract.
-
-Modifier is such a powerful tool that allows you to read, intercept, and modify all events before they are dispatched.
-
-## Define a Modifier
-
-Use the `modifier` hook in a module to define a modifier, the first argument is the event name, the second argument is the event detail:
-
-```TypeScript
-class BaseModule {
- modifier?: (...args: [string, unknown]) => ModifierReturn;
-}
-
-type ModifierReturn = true | false | { name: string; detail: unknown };
-```
-
-## Modifier Return
-
-- `true`: The event will be kept as-is and dispatched.
-- `false`: The event will be ignored.
-- `{ name: string; detail: unknown }`: The event will be renamed and dispatched.
-
-```TypeScript
-class YourModule extends BaseModule {
- private zoomCount = 0;
- modifier = (name) => {
- if (name !== 'zoom') return true;
- this.zoomCount++;
- console.log(`Zoom has been dispatched for ${this.zoomCount} times.`);
- return true;
- }
-}
-```
-
-The example above monitors the zoom event and logs the number of times it has been dispatched. It keeps all events unchanged.
-
-::: info
-When multiple modifiers are used, the first modifier that does not return `true` will be the only one that is executed.
-:::
diff --git a/docs/en/events/drag.md b/docs/en/events/drag.md
index d3a7a95..b7b24bb 100644
--- a/docs/en/events/drag.md
+++ b/docs/en/events/drag.md
@@ -1,20 +1,30 @@
# Drag Event
- **Event Name**: `drag`
-- **Access Type**: `StdEvents['drag']`
+- **Access Type**: `Events['drag']`
- **Details**:
```TypeScript
-type event = {
- // ...
- detail: {
- x: number;
- y: number;
- clientX: number;
- clientY: number;
- }
+type DragEvent = {
+ x: number;
+ y: number;
+ deltaX: number;
+ deltaY: number;
}
```
-- `x/y`: the amount of drag - the difference between the current position and the position of the last dispatch.
-- `clientX/clientY`: The position of the pointer when the drag event is triggered.
+- `deltaX`, `deltaY`: the amount of drag - the difference between the current position and the position of the last dispatch.
+- `x`, `y`: The position of the pointer when the drag event is triggered.
+
+## Smooth Dragging
+
+Pointeract supports using [`Lubricator`](/modules/lubricator) to smoothify `drag` events. For quick config, you can use presets:
+
+```TypeScript
+import { Drag, Lubricator, Pointeract, dragPreset as drag } from 'pointeract';
+
+new Pointeract({
+ element: app,
+ lubricator: { drag },
+}, [Drag, Lubricator])
+```
diff --git a/docs/en/events/index.md b/docs/en/events/index.md
index cbfdd19..0fb7631 100644
--- a/docs/en/events/index.md
+++ b/docs/en/events/index.md
@@ -1,8 +1,6 @@
# Events
-**See also**: [Create Custom Events](/development/custom-events)
-
-## Standard Events
+**See also**: [Create Custom Events](/development/custom-modules#custom-events)
The following events are parts of Pointeract standard schema:
@@ -12,26 +10,3 @@ The following events are parts of Pointeract standard schema:
| [`pan`](/events/drag) | move the viewport in a canvas APP |
| [`zoom`](/events/drag) | change the scale of elements / an element |
| [`trueClick`](/events/true-click) | perform a simple click on an element |
-
-## Obtain Event Types
-
-Pointeract has an interface export `StdEvents`, which contains all standard event types, access them as follows:
-
-```TypeScript
-import { StdEvents } from 'pointeract';
-function hook(event: StdEvents['drag']) {
- console.log(event.detail);
-}
-```
-
-You may also have noticed that Pointeract class has an `events` property, which contains all event types available in a specific instance. This can be helpful if you are using a module that emits custom events. Use them as type hints with `typeof`:
-
-```TypeScript
-function hook(event: typeof pointeract.events.drag) {
- console.log(event.detail);
-}
-```
-
-::: warning
-Do not use `pointeract.events.` directly as real events, they contain only event types.
-:::
diff --git a/docs/en/events/pan.md b/docs/en/events/pan.md
index cd75983..ac9d9e9 100644
--- a/docs/en/events/pan.md
+++ b/docs/en/events/pan.md
@@ -1,17 +1,27 @@
# Pan Event
- **Event Name**: `pan`
-- **Access Type**: `StdEvents['pan']`
+- **Access Type**: `Events['pan']`
- **Details**:
```TypeScript
-type event = {
- // ...
- detail: {
- x: number;
- y: number;
- }
+type PanEvent = {
+ deltaX: number;
+ deltaY: number;
}
```
-- `x/y`: Amount of pan - the difference between the current position and the position of the last dispatch.
+- `deltaX`, `deltaY`: Amount of pan - the difference between the current position and the position of the last dispatch.
+
+## Smooth Panning
+
+Pointeract supports using [`Lubricator`](/modules/lubricator) to smoothify `pan` events. You can use the `panPreset` or customize yourself:
+
+```TypeScript
+import { WheelPanZoom, Lubricator, Pointeract, panPreset as pan } from 'pointeract';
+
+new Pointeract({
+ element: app,
+ lubricator: { pan },
+}, [WheelPanZoom, Lubricator])
+```
diff --git a/docs/en/events/true-click.md b/docs/en/events/true-click.md
index 4d2fb8d..dc665d2 100644
--- a/docs/en/events/true-click.md
+++ b/docs/en/events/true-click.md
@@ -5,21 +5,18 @@
> The built-in `click` event is dispatched when the mouse or touch is released on the same element it is pressed. In cases where the element is huge or moves with the pointer, the click event is always dispatched, although the user may not have intended to click.
- **Event Name**: `trueClick`
-- **Access Type**: `StdEvents['trueClick']`
+- **Access Type**: `Events['trueClick']`
- **Details**:
```TypeScript
-type event = {
- // ...
- detail: {
- x: number;
- y: number;
- target: EventTarget | null;
- streak: number;
- }
+type TrueClickEvent = {
+ x: number;
+ y: number;
+ target: EventTarget | null;
+ streak: number;
}
```
-- `x/y`: The coordinates of the pointer when the click event is triggered.
+- `x`, `y`: The coordinates of the pointer when the click event is triggered.
- `target`: The target element of the click event.
- `streak`: The number of clicks in a streak, you can use this ti detect double/triple/quadruple/any click or tap.
diff --git a/docs/en/events/zoom.md b/docs/en/events/zoom.md
index 7f362d4..d38a91d 100644
--- a/docs/en/events/zoom.md
+++ b/docs/en/events/zoom.md
@@ -1,19 +1,29 @@
# Zoom Event
- **Event Name**: `zoom`
-- **Access Type**: `StdEvents['zoom']`
+- **Access Type**: `Events['zoom']`
- **Details**:
```TypeScript
-type event = {
- // ...
- detail: {
- x: number;
- y: number;
- factor: number;
- }
+type ZoomEvent = {
+ x: number;
+ y: number;
+ factor: number;
}
```
-- `x/y`: The coordinates of the zoom origin.
+- `x`, `y`: The coordinates of the zoom origin.
- `factor`: The zoom factor, smaller than 1 zooms out, larger than 1 zooms in.
+
+## Smooth Zooming
+
+Pointeract supports using [`Lubricator`](/modules/lubricator) to smoothify `zoom` events. You can use the `zoomPreset` or customize yourself:
+
+```TypeScript
+import { WheelPanZoom, Lubricator, Pointeract, zoomPreset as zoom } from 'pointeract';
+
+new Pointeract({
+ element: app,
+ lubricator: { zoom },
+}, [WheelPanZoom, Lubricator])
+```
diff --git a/docs/en/get-started.md b/docs/en/get-started.md
index 31d2ea5..5a1ba00 100644
--- a/docs/en/get-started.md
+++ b/docs/en/get-started.md
@@ -37,10 +37,10 @@ Or include the following lines directly in your HTML file:
This link ships the latest ESM version by default, to access CJS version or earlier versions, try using a different URL like:
```html
-
+
```
-The link above ships version 1.0.0 in CJS.
+The link above ships version 1.0.1 in CJS.
## Kickstart
@@ -49,8 +49,11 @@ Simply grab the core class and a module:
```TypeScript
import { Pointeract, Drag } from 'pointeract';
-const poi = new Pointeract({ element: yourElement }, Drag).start();
-poi.on('drag', e => console.log(e.detail));
+new Pointeract({ element: yourElement }, Drag)
+ .start()
+ .on('drag', e => console.log(e));
```
Congratulations! You can now press your mouse or finger to the element and move, the console will log events like a waterfall.
+
+**Read next**: dive into the usage of Pointeract in [Use Pointeract](/basic/use-pointeract).
diff --git a/docs/en/index.md b/docs/en/index.md
index 8e7ef1d..eac9cff 100644
--- a/docs/en/index.md
+++ b/docs/en/index.md
@@ -3,15 +3,15 @@ layout: home
hero:
name: Pointeract
- text: For multitouch and all other gestures
- tagline: Just a much more elegant solution to Hammer.js.
+ text: extensible user gesture recognizer
+ tagline: Just a much more elegant solution than Hammer.js.
actions:
- theme: brand
- text: What's Pointeract?
- link: /whats-pointeract
- - theme: alt
text: Get Started
link: /get-started
+ - theme: alt
+ text: What's Pointeract?
+ link: /whats-pointeract
- theme: alt
text: Playground
link: /playground
diff --git a/docs/en/modules/click.md b/docs/en/modules/click.md
index d61f0bd..fc1f8d5 100644
--- a/docs/en/modules/click.md
+++ b/docs/en/modules/click.md
@@ -8,15 +8,15 @@ The click module in checks whether the mouse/touch has actually moved during dow
```TypeScript
import { Click, Pointeract } from 'pointeract';
-const pointeract = new Pointeract(app, Click);
+const pointeract = new Pointeract({ element: app }, Click);
```
## Options
```TypeScript
-type options = {
- clickPreserveTime: number;
- moveThreshold: number;
+interface Options extends BaseOptions {
+ clickPreserveTime?: number;
+ moveThreshold?: number;
}
```
diff --git a/docs/en/modules/drag.md b/docs/en/modules/drag.md
index 58d216e..dafb758 100644
--- a/docs/en/modules/drag.md
+++ b/docs/en/modules/drag.md
@@ -8,5 +8,5 @@ This module handles drag interactions, events are dispatched when a single touch
```TypeScript
import { Drag, Pointeract } from 'pointeract';
-const pointeract = new Pointeract(app, Drag);
+const pointeract = new Pointeract({ element: app }, Drag);
```
diff --git a/docs/en/modules/index.md b/docs/en/modules/index.md
index 807cd42..db7309f 100644
--- a/docs/en/modules/index.md
+++ b/docs/en/modules/index.md
@@ -1,53 +1,12 @@
-# Modules
-
-Modules are the heart of Pointeract.
-
-## Shipped Modules
+# Module List
Here you can find all modules shipped with Pointeract:
-| Module | Target | Description |
-| :-----------------------------------------------: | :------------: | ------------------------------------------------------- |
-| [PreventDefault](/modules/prevent-default) | The Element | Prevents default browser behavior. |
-| [Click](/modules/click) | Single Pointer | Checks if a click was performed without any movement. |
-| [Drag](/modules/drag) | Single Pointer | Tracks pointer movement and emits drag events. |
-| [WheelPanZoom](/modules/wheel-pan-zoom) | Mouse Wheel | Tracks pointer wheel movement and key press. |
-| [MultiTouchPanZoom](/modules/multitouch-pan-zoom) | Multitouch | Resolves pan/zoom by analyzing movement of two touches. |
-
-## Module Types Conversion
-
-TypeScript class behavior is weird:
-
-- In actual runtime logic, a constructor is constructor.
-- But When you are passing a class constructor as a type, it actually infers the class instance type.
-- You need to use `typeof` to get the constructor type.
-
-This may seem confusing at first glance:
-
-```TypeScript
-import { Drag } from 'pointeract'
-const dragCtor: Drag = Drag; // Type Error: Type 'typeof Drag' is missing the following properties from type 'Drag': onPointerMove, utils, window, pointers, and 2 more.
-const dragCtor: typeof Drag = Drag; // OK
-```
-
-All module arguments Pointeract accepts are module constructors, so in your runtime code, you pass constructors:
-
-```TypeScript
-import { Pointeract, Drag, PreventDefault } from 'pointeract';
-const pointeract = new Pointeract(app, [Drag, PreventDefault]).start();
-```
-
-However, when you are accessing types, you need to use `typeof`:
-
-```TypeScript
-import { Pointeract, Drag, PreventDefault } from 'pointeract';
-type pointeract = Pointeract;
-```
-
-For this reason, Pointeract has a type helper export `Ctors | BaseModule>` when accessing types:
-
-```TypeScript
-import { Pointeract, Drag, PreventDefault, Ctors, Options } from 'pointeract';
-type pointeract = Pointeract>;
-type options = Options>;
-```
+| Module | Target | Description |
+| :-------------------------------------------------: | :------------: | ------------------------------------------------------------------------------- |
+| [`PreventDefault`](/modules/prevent-default) | The Element | Prevents default browser behavior. |
+| [`Click`](/modules/click) | Single Pointer | Checks if a click was performed without any movement. |
+| [`Drag`](/modules/drag) | Single Pointer | Tracks pointer movement and emits drag events. |
+| [`WheelPanZoom`](/modules/wheel-pan-zoom) | Mouse Wheel | Tracks pointer wheel movement and key press. |
+| [`MultiTouchPanZoom`](/modules/multitouch-pan-zoom) | Multitouch | Resolves pan/zoom by analyzing movement of two touches. |
+| [`Lubricator`](/modules/lubricator) | Events | Smoothify configured events by intercepting them and re-emit interpolated ones. |
diff --git a/docs/en/modules/lubricator.md b/docs/en/modules/lubricator.md
new file mode 100644
index 0000000..2234baf
--- /dev/null
+++ b/docs/en/modules/lubricator.md
@@ -0,0 +1,98 @@
+# Lubricator Module
+
+Lubricator digests raw events and produces smoothified interactions.
+
+This module is a functional module, itself doesn't recognize any gesture. Instead, it intercepts all configured events that is to be dispatched via the [modifier API](/development/custom-modules#modifiers). It then interpolates them and emit smoothified events.
+
+It is not dependent on any modules or events. Instead, it exposes a comprehensive configuration API that enables the interpolation on any events.
+
+## Loading
+
+```TypeScript
+import { Lubricator, Pointeract, Drag, dragPreset as drag } from 'pointeract';
+const pointeract = new Pointeract({
+ element: app,
+ lubricator: { drag },
+}, [Lubricator, Drag]);
+```
+
+## Options
+
+Lubricator requires a granular configuration of what and how to interpolate an event:
+
+```TypeScript
+interface Options extends BaseOptions {
+ lubricator?: {
+ [Key: string]?: {
+ decayFactor: number;
+ fields: {
+ [Key: string]?: {
+ countType: 'sum' | 'product';
+ diminishBoundary: number;
+ };
+ };
+ };
+ };
+}
+```
+
+The direct children of `lubricator` consists any amount of fields, where the keys are the name of events to intercept (i.e. to smooth), and the values are configurations per-event.
+
+In **per-event** configuration:
+
+`decayFactor`: controls how fast it interpolates, i.e., how the smoothified event lags behind the real-time interaction. The lower this value is, the more smooth interactions are.
+
+`fields`: the name of fields in the event to interpolate, the fields must be the type `number`, you can find the fields of events in the [event types](/basic/types#events). The values of the items in `fields` are configurations per-field.
+
+In **per-field** configuration:
+
+`countType`: defines the interpolation goal:
+
+- `sum`: the aggregate sum of this field in the interpolated events must be equal to the sum of raw interaction. Typical for `deltaX`, `deltaY` in `pan` event.
+- `product` the aggregate product if this field in the interpolated events must be equal to the product the raw interaction. Typical for `factor` in `zoom` event.
+
+`diminishBoundary`: defines the threshold for the final dispatch.
+
+- interpolation is infinite if you don't manually define a boundary. If the difference between the real dispatch and raw is smaller than this boundary, the interpolation will stop and lubricator will dispatch a final event to make the aggregate interpolation equals the raw.
+
+In the following example, we will smoothify `zoom` event:
+
+```TypeScript
+import { WheelPanZoom, Lubricator, Pointeract } from 'pointeract';
+
+new Pointeract({
+ element: app,
+ lubricator: {
+ zoom: {
+ decayFactor: 0.25,
+ fields: {
+ factor: {
+ countType: 'product',
+ diminishBoundary: 0.01,
+ },
+ },
+ },
+ },
+}, [WheelPanZoom, Lubricator])
+```
+
+In this example, we've configured Lubricator to intercept event `zoom`, interpolate the `factor` field in it with product goal and stops when the aggregate interpolation is less than 1% from total product.
+
+## Presets
+
+Lubricator provides configuration presets the events, currently available ones are:
+
+- `panPreset`: targets `pan` event
+- `zoomPreset`: targets `zoom` event
+- `dragPreset`: targets `drag` event
+
+To use them, simply import them from `pointeract` and plug them into your options:
+
+```TypeScript
+import { WheelPanZoom, Lubricator, Pointeract, panPreset as pan, zoomPreset as zoom } from 'pointeract';
+
+new Pointeract({
+ element: app,
+ lubricator: { pan, zoom },
+}, [WheelPanZoom, Lubricator])
+```
diff --git a/docs/en/modules/multitouch-pan-zoom.md b/docs/en/modules/multitouch-pan-zoom.md
index e1a7a36..c6575e8 100644
--- a/docs/en/modules/multitouch-pan-zoom.md
+++ b/docs/en/modules/multitouch-pan-zoom.md
@@ -11,5 +11,5 @@ This module monitors touches on the screen.
```TypeScript
import { MultitouchPanZoom, Pointeract } from 'pointeract';
-const pointeract = new Pointeract(app, MultitouchPanZoom);
+const pointeract = new Pointeract({ element: app }, MultitouchPanZoom);
```
diff --git a/docs/en/modules/prevent-default.md b/docs/en/modules/prevent-default.md
index 5030ca8..21d8315 100644
--- a/docs/en/modules/prevent-default.md
+++ b/docs/en/modules/prevent-default.md
@@ -1,10 +1,10 @@
# Prevent Default Module
-This module disables all default browser behaviors related to touch/mouse/wheel events about the target element.
+This module disables all default browser behaviors related to touch / mouse / wheel events about the target element. After starting pointeract, the prevention is started, when the class is disposed or stopped, the prevention will be stopped as well.
## Loading
```TypeScript
import { PreventDefault, Pointeract } from 'pointeract';
-const pointeract = new Pointeract(app, PreventDefault);
+const pointeract = new Pointeract({ element: app }, PreventDefault);
```
diff --git a/docs/en/modules/wheel-pan-zoom.md b/docs/en/modules/wheel-pan-zoom.md
index 2bc8be2..08d17e8 100644
--- a/docs/en/modules/wheel-pan-zoom.md
+++ b/docs/en/modules/wheel-pan-zoom.md
@@ -22,16 +22,16 @@ Most devices with touchpad interpret touchpad gestures as mouse wheel + key pres
```TypeScript
import { WheelPanZoom, Pointeract } from 'pointeract';
-const pointeract = new Pointeract(app, WheelPanZoom);
+const pointeract = new Pointeract({ element: app }, WheelPanZoom);
```
## Options
```TypeScript
-type options = {
- proControlSchema: boolean;
- lockControlSchema: boolean;
- zoomFactor: number;
+interface Options extends BaseOptions {
+ proControlSchema?: boolean;
+ lockControlSchema?: boolean;
+ zoomFactor?: number;
}
```
diff --git a/docs/en/playground.md b/docs/en/playground.md
index e0ac6a8..5ca45ec 100644
--- a/docs/en/playground.md
+++ b/docs/en/playground.md
@@ -1,6 +1,6 @@
# Playground
-Loaded modules: [`PreventDefault`](/modules/prevent-default) [`Drag`](/modules/drag) [`Click`](/modules/click) [`WheelPanZoom`](/modules/wheel-pan-zoom) [`MultitouchPanZoom`](/modules/multitouch-pan-zoom)
+Loaded modules: [`PreventDefault`](/modules/prevent-default) [`Drag`](/modules/drag) [`Click`](/modules/click) [`WheelPanZoom`](/modules/wheel-pan-zoom) [`MultitouchPanZoom`](/modules/multitouch-pan-zoom) [`Lubricator`](/modules/lubricator)