From 8bf7dd71720cf55e14a8d7320a159ed541adf9b8 Mon Sep 17 00:00:00 2001 From: BurningTreeC Date: Wed, 18 Apr 2018 12:33:59 +0200 Subject: [PATCH] Add swipe,tap and press widget to hammerjs (#3214) * Create swipe.js * add swipe widget * add popup handling * velocity mini-tweak * add press widget * add tap widget * remove popup from tap widget - not possible as it seems * add pan widget + utility css * correcting field name * naming and formatting * add usage * add pinch widget * add pinch widget * various small fixes * adding absolute coordinates to pan widget * prevent default dragging for pan widget * improve pan widget stability --- .../hammerjs/files/tiddlywiki.files | 37 ++- .../tiddlywiki/hammerjs/files/widgets/pan.js | 291 ++++++++++++++++++ .../hammerjs/files/widgets/pinch.js | 192 ++++++++++++ .../hammerjs/files/widgets/press.js | 173 +++++++++++ .../hammerjs/files/widgets/swipe.js | 168 ++++++++++ .../tiddlywiki/hammerjs/files/widgets/tap.js | 142 +++++++++ plugins/tiddlywiki/hammerjs/plugin.info | 2 +- plugins/tiddlywiki/hammerjs/styles.tid | 10 + plugins/tiddlywiki/hammerjs/usage.tid | 63 ++++ 9 files changed, 1076 insertions(+), 2 deletions(-) create mode 100644 plugins/tiddlywiki/hammerjs/files/widgets/pan.js create mode 100644 plugins/tiddlywiki/hammerjs/files/widgets/pinch.js create mode 100644 plugins/tiddlywiki/hammerjs/files/widgets/press.js create mode 100644 plugins/tiddlywiki/hammerjs/files/widgets/swipe.js create mode 100644 plugins/tiddlywiki/hammerjs/files/widgets/tap.js create mode 100644 plugins/tiddlywiki/hammerjs/styles.tid create mode 100644 plugins/tiddlywiki/hammerjs/usage.tid diff --git a/plugins/tiddlywiki/hammerjs/files/tiddlywiki.files b/plugins/tiddlywiki/hammerjs/files/tiddlywiki.files index 36cf028fb..24b88a360 100644 --- a/plugins/tiddlywiki/hammerjs/files/tiddlywiki.files +++ b/plugins/tiddlywiki/hammerjs/files/tiddlywiki.files @@ -15,6 +15,41 @@ "type": "text/plain", "title": "$:/plugins/tiddlywiki/hammerjs/license" } - } + },{ + "file": "widgets/swipe.js", + "fields": { + "type": "application/javascript", + "title": "$:/plugins/tiddlywiki/hammerjs/widgets/swipe.js", + "module-type": "widget" + } + },{ + "file": "widgets/press.js", + "fields": { + "type": "application/javascript", + "title": "$:/plugins/tiddlywiki/hammerjs/widgets/press.js", + "module-type": "widget" + } + },{ + "file": "widgets/tap.js", + "fields": { + "type": "application/javascript", + "title": "$:/plugins/tiddlywiki/hammerjs/widgets/tap.js", + "module-type": "widget" + } + },{ + "file": "widgets/pan.js", + "fields": { + "type": "application/javascript", + "title": "$:/plugins/tiddlywiki/hammerjs/widgets/pan.js", + "module-type": "widget" + } + },{ + "file": "widgets/pinch.js", + "fields": { + "type": "application/javascript", + "title": "$:/plugins/tiddlywiki/hammerjs/widgets/pinch.js", + "module-type": "widget" + } + } ] } diff --git a/plugins/tiddlywiki/hammerjs/files/widgets/pan.js b/plugins/tiddlywiki/hammerjs/files/widgets/pan.js new file mode 100644 index 000000000..74605e3df --- /dev/null +++ b/plugins/tiddlywiki/hammerjs/files/widgets/pan.js @@ -0,0 +1,291 @@ +/*\ +title: $:/plugins/tiddlywiki/hammerjs/widgets/pan.js +type: application/javascript +module-type: widget + +actions triggered on pan gestures + event coordinates + +\*/ +(function (global) { + +"use strict"; +/*jslint node: true, browser: true */ +/*global $tw: false */ + +var Widget = require("$:/core/modules/widgets/widget.js").widget; + +if (typeof window !== 'undefined') { + var Hammer = require("$:/plugins/tiddlywiki/hammerjs/hammer.js"); +} + +var PanWidget = function(parseTreeNode,options) { + this.initialise(parseTreeNode,options); +}; + +/* +Inherit from the base widget class +*/ +PanWidget.prototype = new Widget(); + +/* +Render this widget into the DOM +*/ +PanWidget.prototype.render = function(parent,nextSibling) { + var self = this; + var parentDomNode = parent; + + // Compute attributes and execute state + this.computeAttributes(); + this.execute(); + + if (self === this && parent !== undefined && nextSibling !== undefined && this.children !== undefined) { + self.renderChildren(parent,nextSibling); + } else if (self === this && parent !== undefined && nextSibling !== undefined && nextSibling !== null) { + self.refresh(); + parentDomNode = parent; + } else { + if(self.parentWidget !== undefined) { + self.parentWidget.refreshSelf(); + parentDomNode = parent; + } else { + return false; + } + } + + if(this.panTargets === undefined || this.panTargets === "") { + return false; + } + + var panElementClass; + var panMultipleClasses = null; + + if(this.panTargets.indexOf(' ') !== -1) { + panMultipleClasses = true; + panElementClass = self.panTargets.split(' '); + } else { + panElementClass = self.panTargets; + } + + if(panElementClass === undefined || panElementClass === "" || parentDomNode === undefined) { + return false; + } + + var domNodeList = []; + + if (panMultipleClasses === true) { + for (var i=0; i < elementClass.length; i++) { + var panElements = parentDomNode.getElementsByClassName(panElementClass[i]); + for (var k=0; k < panElements.length; k++) { + domNodeList[i + k] = panElements[k]; + } + } + } else { + domNodeList = parentDomNode.getElementsByClassName(panElementClass); + } + + var elementIndex; + var panStartValues = []; + + for(i=0; i < domNodeList.length; i++) { + + elementIndex = i; + + var currentElement = domNodeList[i]; + + var hammer = new Hammer.Manager(domNodeList[i]); + + hammer.add(new Hammer.Pan({ + event: 'pan', + pointers: self.panPointers, + threshold: self.panThreshold, + direction: Hammer.DIRECTION_ALL + })); + + hammer.get('pan'); + + var scrollLeft = null, + scrollTop = null; + + var startX = null; + var startY = null; + var elementTop = null; + var elementLeft = null; + var elementBottom = null; + var elementRight = null; + var elementWidth = null; + var elementHeight = null; + var startActions = null; + var singleElement = null; + var pointerType = null; + var domNodeRect = null; + var parentDomNodeRect = null; + var elementAbsoluteTop = null; + var elementAbsoluteLeft = null; + var fieldStartNames = [ 'starting-x', 'starting-y', 'element-top', 'element-left', 'element-bottom', 'element-right', 'element-width', 'element-height', 'pointer-type', 'parent-x', 'parent-y' ]; + + hammer.on('touchmove panstart panmove', function(e) { + // Prevent default behaviour + e.preventDefault && e.preventDefault(); + e.stopPropagation && e.stopPropagation(); + + // Set a "dragging" state tiddler - gets deleted when panning ends + $tw.wiki.setText("$:/state/dragging","text",undefined,"yes",null); + + // Get the coordinates of the parent Dom Node + if (parentDomNodeRect === null && parentDomNode !== undefined && parentDomNode.parentElement !== undefined) { + parentDomNodeRect = parentDomNode.parentElement.getBoundingClientRect(); + } + + // Get the current coordinates of the element + if (domNodeRect === null) { + domNodeRect = currentElement.getBoundingClientRect(); + } + + if (self.panStartActions && startActions !== "done") { + self.invokeActionString(self.panStartActions,self,e); + startActions = "done"; + } + + // Absolute coordinates of the pointer + scrollLeft = window.pageXOffset || document.documentElement.scrollLeft; + scrollTop = window.pageYOffset || document.documentElement.scrollTop; + elementAbsoluteLeft = (e.center.x + scrollLeft).toFixed(self.userToFixed); + elementAbsoluteTop = (e.center.y + scrollTop).toFixed(self.userToFixed); + + // Set values at pan-start only + if (panStartValues.length === 0) { + panStartValues[0] = e.center.x.toFixed(self.userToFixed); + panStartValues[1] = e.center.y.toFixed(self.userToFixed); + panStartValues[2] = domNodeRect.top.toFixed(self.userToFixed); + panStartValues[3] = domNodeRect.left.toFixed(self.userToFixed); + panStartValues[4] = domNodeRect.bottom.toFixed(self.userToFixed); + panStartValues[5] = domNodeRect.right.toFixed(self.userToFixed); + panStartValues[6] = domNodeRect.width.toFixed(self.userToFixed); + panStartValues[7] = domNodeRect.height.toFixed(self.userToFixed); + panStartValues[8] = e.pointerType; + panStartValues[9] = parentDomNodeRect.left.toFixed(self.userToFixed) || "undefined"; + panStartValues[10] = parentDomNodeRect.top.toFixed(self.userToFixed) || "undefined"; + + for(var t = 0; t=5.0.0", - "list": "readme license" + "list": "readme usage license" } diff --git a/plugins/tiddlywiki/hammerjs/styles.tid b/plugins/tiddlywiki/hammerjs/styles.tid new file mode 100644 index 000000000..b92731197 --- /dev/null +++ b/plugins/tiddlywiki/hammerjs/styles.tid @@ -0,0 +1,10 @@ +title: $:/plugins/tiddlywiki/hammerjs/styles +tags: $:/tags/Stylesheet + +<$list filter="[[$:/state/dragging]!is[missing]]"> + +iframe { + pointer-events: none; +} + + diff --git a/plugins/tiddlywiki/hammerjs/usage.tid b/plugins/tiddlywiki/hammerjs/usage.tid new file mode 100644 index 000000000..3d9cb2e64 --- /dev/null +++ b/plugins/tiddlywiki/hammerjs/usage.tid @@ -0,0 +1,63 @@ +title: $:/plugins/tiddlywiki/hammerjs/usage + +The ''swipe'', ''press'', ''pan'', ''tap'' and ''pinch'' widgets included in this plugin enable users of creating html elements that trigger user-actions when the corresponding gesture gets executed on the element - or, in case of the pan and pinch widgets, in addition to triggering user-actions, populate a state tiddler with coordinates and values of the element itself and the gesture + +The pan widget stores the coordinates of the element and the relative and absolute coordinates of the pointer in $:/state/pan or a user-defined tiddler + +The pinch widget stores the scale value and the angle of the detected rotation of the pinch gesture in $:/state/pinch or a user-defined tiddler + +With those values users can position elements following the mouse, create custom sliders or create image galleries with pinch-zoomable and rotatable images, in combination with [ext[css calculations|https://www.w3schools.com/cssref/func_calc.asp]] and/or tiddlywiki plugins that allow number-crunching + + +!!Swipe Widget + + + +!!Press Widget + + + +!!Pan Widget + +|!Attribute |!Description |!Optional? |h +|targets |the css class of the target element(s) |no | +|startactions |the actions that should be performed when panning starts |yes | +|endactions |the actions that should be performed when panning ends |yes | +|repeatactions |actions that are repeatedly performed while panning |yes | +|state |optional tiddler where values get stored - default: $:/state/pan |yes | +|pointers |the number of pointers needed for the swipe gesture - default: 1 |yes | +|threshold |a minimal distance in px required before recognizing the pan gesture - default: 0 |yes | +|decimals |the number of decimal points for the stored values in the state tiddler - default: 0 |yes | + + +As an example, an element with the class `tc-test-class` is made pannable by + +``` +<$pan targets="tc-test-class"> +
+ + +``` + +When users click this element, hold the mouse and move it, the tiddler $:/state/pan gets populated with the pan-values + +Those values can be used to position that same element using css in a `Stylesheet Tiddler` - note that the values from the state tiddler can be transcluded within the css `calc()` function: + +```css +.tc-test-class { + width: 70px; + height: 70px; + background-color: #f4f4f4; + position: absolute; + left: calc({{$:/state/pan!!absolute-x}}px - 35px); + top: calc({{$:/state/pan!!absolute-y}}px - 35px) +} + +``` + + +!!Tap Widget + + + +!!Pinch Widget