joicomponents
Version:
Design patterns to build native web components
120 lines (96 loc) • 4.98 kB
Markdown
# Mixin: `DraggingFling`
`DraggingFling` adds support for one-finger gesture for dragging on the screen,
commonly used to move and/or scroll elements on the screen.
A `fling` callback/event is triggered if the finger is removed from the screen while in motion,
the dragging ends abruptly.
See also `spin` in [PinchSpin](Mixin3_PinchSpinGesture.md).
`DraggingFling` records a sequence of one-finger events
(cf. [EventRecording](../../chapter2_HowToMakeMixins/Pattern4_EventRecording.md)):
* `touchstart`/`mousedown`,
* `touchmove`/`mousemove`,
* `touchend`/`mouseup`, and
* `touchcancel`.
And turns them into a series of *optional* callbacks
(cf. [OptionalCallbacksEvents](../../chapter2_HowToMakeMixins/Pattern6_OptionalCallbacksEvents.md)):
* `draggingstartCallback()`,
* `draggingCallback()`,
* `draggingendCallback()`,
* `draggingcancelCallback()`,
* and `flingCallback()`.
The `draggingstart`, `dragging`, `draggingend` timeline correspond to
`touchstart`, `touchmove`, and `touchend/touchcancel`.
## Implementation details
The `DraggingFling` is built using the [EventRecording](../../chapter2_HowToMakeMixins/Pattern4_EventRecording.md) and
[FunctionalMixin](../../chapter2_HowToMakeMixins/Pattern2_FunctionalMixin.md) patterns.
The `DraggingFling` mixin only reacts when *one* finger/mousebutton is used.
If only an additional finger or mousebutton is pressed,
the event recording is cancelled.
`fling` is triggered when the finger or mouse have moved more
than a minimum `flingDistance`(px) for more than minimum `flingDuration`(ms).
Both `flingDistance` and `flingDuration` are implemented as [StaticSettings](../../chapter2_HowToMakeMixins/Pattern3_StaticSettings.md).
The default value of `flingDistance` is `50`(px), and
the default value of `flingDuration` is `200`(ms).
`flingDistance` is calculated as the distance from the start and end position of
the finger/mouse, where the start position was the position of the finger/mouse at pinchend - `spinDuration`.
`DraggingFling` has the following *OptionalCallbacks* methods:
- `draggingstartCallback({event, x, y})`
- `draggingCallback({event, x, y, distX, distY, distDiag, durationMs})`
- `draggingendCallback({event, x, y})`
- `draggingcancelCallback({event})`
- `flingCallback({event, x, y, distX, distY, distDiag, durationMs})`
`DraggingFling` has the following StaticSetting for an *OptionalEvent*:
- draggingEvent: true => mixin will also dispatch the following events
- draggingstart: {event, x, y}
- dragging: {event, x, y, distX, distY, distDiag, durationMs}
- draggingend: {event, x, y}
- fling: {event, x, y, distX, distY, distDiag, durationMs}
The *OptionalCallback* methods' names and argument
correspond exactly to the *OptionalEvent* name and detail.
`DraggingFling` implement an extensive [InvadeAndRetreat!](../gestures/Pattern4_InvadeAndRetreat.md) strategy
to block default actions in the browsers such as "drag-to-scroll".
`DraggingFling` does not use pointerevents. It could have.
But it doesn't in order to avoid to polyfill pointerevents in Safari.
## Example: DraggingBlock
```html
<style>
dragging-block {
display: block;
position: fixed;
top: 100px;
left: 100px;
width: 50px;
height: 50px;
background: orange;
}
</style>
<dragging-block></dragging-block>
<script type="module">
import {DraggingFling} from "https://rawgit.com/orstavik/JoiComponents/master/src/gestures/DraggingFling.js";
class DraggingBlock extends DraggingFling(HTMLElement) { //[1]
static get draggingEvent(){
return true;
}
draggingCallback(detail){
this.innerText = "x: " + detail.distX + ", y: " + detail.distY; //[3]
}
}
customElements.define("dragging-block", DraggingBlock);
const block = document.querySelector("dragging-block");
block.addEventListener("dragging", (e) => {
block.style.left = (parseFloat(block.style.left) + e.detail.distX) + "px"; //[3]
block.style.top = (parseFloat(block.style.top) + e.detail.distY) + "px"; //[3]
});
</script>
```
todo add and writeup the numbers in the example.
1. Adding the functional mixin `DraggingFling(HTMLElement)`.
DraggingBlock elements will now dispatch dragging events when dragged.
2. Adds the listener for `dragging` event when the element connects to the DOM.
Removes the listener for `dragging` event when the element disconnects.
3. Moves the element using `e.detail.distX` and `e.detail.distY` from the `dragging` event.
Test it out on [codepen](https://codepen.io/orstavik/pen/XEwPaE).
## References
* [Lauke: getting touchy presentation](https://www.youtube.com/watch?v=jSL-RluQhMs)
* [Lauke: getting touchy on github](https://github.com/patrickhlauke/getting-touchy-presentation)
* https://developer.mozilla.org/en-US/docs/Web/API/Pointer_events
* https://github.com/jquery/PEP