Merge branch 'master' of gitea.iwm-tuebingen.de:IWMBrowser/iwmlib
# Conflicts: # dist/iwmlib.js
This commit is contained in:
commit
4009ddd422
165
dist/iwmlib.js
vendored
165
dist/iwmlib.js
vendored
@ -987,6 +987,13 @@
|
|||||||
return Math.sqrt(dx * dx + dy * dy)
|
return Math.sqrt(dx * dx + dy * dy)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Distance == 0.0 indicates an inside relation.
|
||||||
|
static distanceToRect(p, r) {
|
||||||
|
var cx = Math.max(Math.min(p.x, r.x + r.width), r.x);
|
||||||
|
var cy = Math.max(Math.min(p.y, r.y + r.height), r.y);
|
||||||
|
return Math.sqrt((p.x - cx) * (p.x - cx) + (p.y - cy) * (p.y - cy))
|
||||||
|
}
|
||||||
|
|
||||||
static fromPageToNode(element, p) {
|
static fromPageToNode(element, p) {
|
||||||
// if (window.webkitConvertPointFromPageToNode) {
|
// if (window.webkitConvertPointFromPageToNode) {
|
||||||
// return window.webkitConvertPointFromPageToNode(element,
|
// return window.webkitConvertPointFromPageToNode(element,
|
||||||
@ -5044,7 +5051,7 @@
|
|||||||
context.stroke();
|
context.stroke();
|
||||||
}
|
}
|
||||||
requestAnimationFrame(dt => {
|
requestAnimationFrame(dt => {
|
||||||
this.showTouches(dt);
|
this.showTouches(dt, canvas);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5155,7 +5162,8 @@
|
|||||||
width = null, // required
|
width = null, // required
|
||||||
height = null, // required
|
height = null, // required
|
||||||
resizable = false,
|
resizable = false,
|
||||||
simulateClick = false,
|
clickOnTap = false,
|
||||||
|
allowClickDistance = 44,
|
||||||
verbose = true,
|
verbose = true,
|
||||||
onResize = null,
|
onResize = null,
|
||||||
touchAction = 'none',
|
touchAction = 'none',
|
||||||
@ -5206,7 +5214,7 @@
|
|||||||
this.height = height;
|
this.height = height;
|
||||||
this.throwVisibility = Math.min(width, height, throwVisibility);
|
this.throwVisibility = Math.min(width, height, throwVisibility);
|
||||||
this.container = container;
|
this.container = container;
|
||||||
this.simulateClick = simulateClick;
|
this.clickOnTap = clickOnTap;
|
||||||
this.scale = startScale;
|
this.scale = startScale;
|
||||||
this.rotationDegrees = this.startRotationDegrees;
|
this.rotationDegrees = this.startRotationDegrees;
|
||||||
this.transformOrigin = transformOrigin;
|
this.transformOrigin = transformOrigin;
|
||||||
@ -5219,7 +5227,8 @@
|
|||||||
rotation: this.startRotationDegrees,
|
rotation: this.startRotationDegrees,
|
||||||
transformOrigin: transformOrigin
|
transformOrigin: transformOrigin
|
||||||
};
|
};
|
||||||
|
this.tapNodes = new Map();
|
||||||
|
this.allowClickDistance = allowClickDistance;
|
||||||
|
|
||||||
// For tweenlite we need initial values in _gsTransform
|
// For tweenlite we need initial values in _gsTransform
|
||||||
TweenLite.set(element, this.initialValues);
|
TweenLite.set(element, this.initialValues);
|
||||||
@ -5412,15 +5421,98 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
onTap(event, interaction, point) {
|
onTap(event, interaction, point) {
|
||||||
if (this.simulateClick) {
|
|
||||||
let p = Points.fromPageToNode(this.element, point);
|
if (this.clickOnTap) {
|
||||||
let element = document.elementFromPoint(p.x, p.y);
|
let directNode = document.elementFromPoint(point.x, point.y);
|
||||||
if (element != null) {
|
let nearestNode = this.nearestClickable(event);
|
||||||
console.log('tap simulates click');
|
|
||||||
element.click();
|
console.log("onTap", directNode, nearestNode.tagName);
|
||||||
|
if (directNode != null && this.isClickable(directNode)) {
|
||||||
|
directNode.click();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (nearestNode.tagName == 'svg' && this.isClickable(nearestNode)) {
|
||||||
|
let handler = this.tapNodes.get(nearestNode);
|
||||||
|
console.log("Clicking beneath SVG: to be done", handler);
|
||||||
|
Events.stop(event);
|
||||||
|
//nearestNode.click()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a click or tap behavior to the node. Uses
|
||||||
|
* either the scatter clickOnTap version which requires click handlers
|
||||||
|
* or uses the hammer.js driven tap handler.
|
||||||
|
*
|
||||||
|
* @param {*} node
|
||||||
|
* @param {*} handler
|
||||||
|
* @memberof DOMScatter
|
||||||
|
*/
|
||||||
|
|
||||||
|
addTapListener(node, handler) {
|
||||||
|
if (this.clickOnTap) {
|
||||||
|
node.addEventListener('click', handler);
|
||||||
|
this.tapNodes.set(node, handler);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
InteractionMapper$1.on('tap', node, handler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
isClickable(node) {
|
||||||
|
if (node.tagName == 'A')
|
||||||
|
return true
|
||||||
|
if (this.tapNodes.has(node))
|
||||||
|
return true
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array of all clickable nodes.
|
||||||
|
* Unfortunately we cannot search for all nodes with an attached 'click' event listener
|
||||||
|
* See https://stackoverflow.com/questions/11455515/how-to-check-whether-dynamically-attached-event-listener-exists-or-not
|
||||||
|
* Therefore we can only detect the following standard cases:
|
||||||
|
* I. All clickable objects like clickables
|
||||||
|
* II. Objects that have been attached a click handler by the scatter itself via
|
||||||
|
*/
|
||||||
|
clickableNodes() {
|
||||||
|
let result = [];
|
||||||
|
for (let node of this.element.querySelectorAll("*")) {
|
||||||
|
if (this.isClickable(node))
|
||||||
|
result.push(node);
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
nearestClickable(event) {
|
||||||
|
let element = this.element;
|
||||||
|
let clickables = this.clickableNodes();
|
||||||
|
let globalClick = (event.center) ? event.center : { x: event.x, y: event.y };
|
||||||
|
let localClick = Points.fromPageToNode(element, globalClick);
|
||||||
|
|
||||||
|
let clickRects = clickables.map(link => {
|
||||||
|
let rect = link.getBoundingClientRect();
|
||||||
|
let topLeft = Points.fromPageToNode(element, rect);
|
||||||
|
let center = Points.fromPageToNode(element, { x: rect.x + rect.width / 2, y: rect.y + rect.height / 2 });
|
||||||
|
return { x: topLeft.x, y: topLeft.y, width: rect.width, height: rect.height, center, link }
|
||||||
|
});
|
||||||
|
|
||||||
|
let distances = [];
|
||||||
|
clickRects.forEach(rect => {
|
||||||
|
let distance = Points.distanceToRect(localClick, rect);
|
||||||
|
distances.push(parseInt(distance));
|
||||||
|
});
|
||||||
|
|
||||||
|
let closestClickIndex = distances.indexOf(Math.min(...distances));
|
||||||
|
let closestClickable = clickables[closestClickIndex];
|
||||||
|
if (distances[closestClickIndex] < this.allowClickDistance) {
|
||||||
|
console.log("found closest clickables", closestClickable);
|
||||||
|
return closestClickable
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
isDescendant(parent, child) {
|
isDescendant(parent, child) {
|
||||||
let node = child.parentNode;
|
let node = child.parentNode;
|
||||||
@ -5741,6 +5833,7 @@
|
|||||||
translatable = true,
|
translatable = true,
|
||||||
scalable = true,
|
scalable = true,
|
||||||
rotatable = true,
|
rotatable = true,
|
||||||
|
clickOnTap = false,
|
||||||
onFront = null,
|
onFront = null,
|
||||||
onBack = null,
|
onBack = null,
|
||||||
onClose = null,
|
onClose = null,
|
||||||
@ -5760,6 +5853,7 @@
|
|||||||
this.translatable = translatable;
|
this.translatable = translatable;
|
||||||
this.scalable = scalable;
|
this.scalable = scalable;
|
||||||
this.rotatable = rotatable;
|
this.rotatable = rotatable;
|
||||||
|
this.clickOnTap = clickOnTap;
|
||||||
this.onFrontFlipped = onFront;
|
this.onFrontFlipped = onFront;
|
||||||
this.onBackFlipped = onBack;
|
this.onBackFlipped = onBack;
|
||||||
this.onClose = onClose;
|
this.onClose = onClose;
|
||||||
@ -5814,7 +5908,8 @@
|
|||||||
translatable: this.translatable,
|
translatable: this.translatable,
|
||||||
scalable: this.scalable,
|
scalable: this.scalable,
|
||||||
rotatable: this.rotatable,
|
rotatable: this.rotatable,
|
||||||
overdoScaling: this.overdoScaling
|
overdoScaling: this.overdoScaling,
|
||||||
|
clickOnTap: this.clickOnTap
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -5823,7 +5918,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.closeOnMinScale) {
|
if (this.closeOnMinScale) {
|
||||||
|
|
||||||
const removeOnMinScale = function () {
|
const removeOnMinScale = function () {
|
||||||
if (scatter.scale <= scatter.minScale) {
|
if (scatter.scale <= scatter.minScale) {
|
||||||
this.flippable.close();
|
this.flippable.close();
|
||||||
@ -5838,11 +5932,7 @@
|
|||||||
scatter.onTransform.splice(callbackIdx, 1);
|
scatter.onTransform.splice(callbackIdx, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}.bind(this);
|
}.bind(this);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
scatter.addTransformEventCallback(removeOnMinScale);
|
scatter.addTransformEventCallback(removeOnMinScale);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5878,8 +5968,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
start({ targetCenter = null } = {}) {
|
start({ targetCenter = null } = {}) {
|
||||||
console.log('DOMFlip.start', targetCenter);
|
console.log("DOMFlip.start", targetCenter);
|
||||||
if (this.preloadBack) this.flippable.start({ duration: this.flipDuration, targetCenter });
|
if (this.preloadBack) {
|
||||||
|
|
||||||
|
this.flippable.start({ duration: this.flipDuration, targetCenter });
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
let back = this.cardWrapper.querySelector('.back');
|
let back = this.cardWrapper.querySelector('.back');
|
||||||
let flippable = this.flippable;
|
let flippable = this.flippable;
|
||||||
@ -5931,7 +6024,7 @@
|
|||||||
this.flipDuration = flip.flipDuration;
|
this.flipDuration = flip.flipDuration;
|
||||||
this.fadeDuration = flip.fadeDuration;
|
this.fadeDuration = flip.fadeDuration;
|
||||||
scatter.addTransformEventCallback(this.scatterTransformed.bind(this));
|
scatter.addTransformEventCallback(this.scatterTransformed.bind(this));
|
||||||
console.log('lib.DOMFlippable', 5000);
|
|
||||||
TweenLite.set(this.element, { perspective: 5000 });
|
TweenLite.set(this.element, { perspective: 5000 });
|
||||||
TweenLite.set(this.card, { transformStyle: 'preserve-3d' });
|
TweenLite.set(this.card, { transformStyle: 'preserve-3d' });
|
||||||
TweenLite.set(this.back, { rotationY: -180 });
|
TweenLite.set(this.back, { rotationY: -180 });
|
||||||
@ -5944,15 +6037,24 @@
|
|||||||
this.backBtn = element.querySelector('.backBtn');
|
this.backBtn = element.querySelector('.backBtn');
|
||||||
this.closeBtn = element.querySelector('.closeBtn');
|
this.closeBtn = element.querySelector('.closeBtn');
|
||||||
/* Buttons are not guaranteed to exist. */
|
/* Buttons are not guaranteed to exist. */
|
||||||
|
|
||||||
if (this.infoBtn) {
|
if (this.infoBtn) {
|
||||||
InteractionMapper$1.on('tap', this.infoBtn, event => this.flip.start());
|
scatter.addTapListener(this.infoBtn, event => {
|
||||||
|
console.log("within click handler", this);
|
||||||
|
this.flip.start();
|
||||||
|
});
|
||||||
this.enable(this.infoBtn);
|
this.enable(this.infoBtn);
|
||||||
}
|
}
|
||||||
if (this.backBtn) {
|
if (this.backBtn) {
|
||||||
InteractionMapper$1.on('tap', this.backBtn, event => this.start());
|
scatter.addTapListener(this.backBtn, event => {
|
||||||
|
console.log("within click handler", this);
|
||||||
|
this.start();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
if (this.closeBtn) {
|
if (this.closeBtn) {
|
||||||
InteractionMapper$1.on('tap', this.closeBtn, event => this.close());
|
scatter.addTapListener(this.closeBtn, event => {
|
||||||
|
this.close();
|
||||||
|
});
|
||||||
this.enable(this.closeBtn);
|
this.enable(this.closeBtn);
|
||||||
}
|
}
|
||||||
this.scaleButtons();
|
this.scaleButtons();
|
||||||
@ -6002,18 +6104,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
scaleButtons() {
|
scaleButtons() {
|
||||||
//This also works for svgs.
|
|
||||||
// if (this.infoBtn)
|
|
||||||
// this.infoBtn.style.transform = "scale(" + this.buttonScale + ")"
|
|
||||||
|
|
||||||
// if (this.backBtn)
|
|
||||||
// this.backBtn.style.transform = "scale(" + this.buttonScale + ")"
|
|
||||||
|
|
||||||
// if (this.closeBtn)
|
|
||||||
// this.closeBtn.style.transform = "scale(" + this.buttonScale + ")"
|
|
||||||
|
|
||||||
console.log(this.buttonScale);
|
|
||||||
//// This did not work with svgs!
|
|
||||||
TweenLite.set([this.infoBtn, this.backBtn, this.closeBtn], {
|
TweenLite.set([this.infoBtn, this.backBtn, this.closeBtn], {
|
||||||
scale: this.buttonScale
|
scale: this.buttonScale
|
||||||
});
|
});
|
||||||
@ -6026,6 +6116,7 @@
|
|||||||
|
|
||||||
clickInfo() {
|
clickInfo() {
|
||||||
this.bringToFront();
|
this.bringToFront();
|
||||||
|
console.log("clickInfo");
|
||||||
this.infoBtn.click();
|
this.infoBtn.click();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6067,8 +6158,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
enable(button) {
|
enable(button) {
|
||||||
this.show(button, this.fadeDuration);
|
this.show(button, this.fadeDuration);
|
||||||
if (button) {
|
if (button) {
|
||||||
@ -6078,9 +6167,6 @@
|
|||||||
|
|
||||||
disable(button) {
|
disable(button) {
|
||||||
this.hide(button, this.fadeDuration);
|
this.hide(button, this.fadeDuration);
|
||||||
if (button) {
|
|
||||||
TweenLite.set(button, { pointerEvents: 'none' });
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
start({ targetCenter = null } = {}) {
|
start({ targetCenter = null } = {}) {
|
||||||
@ -6124,7 +6210,6 @@
|
|||||||
let x = this.flipped ? xx : this.startX;
|
let x = this.flipped ? xx : this.startX;
|
||||||
let y = this.flipped ? yy : this.startY;
|
let y = this.flipped ? yy : this.startY;
|
||||||
|
|
||||||
console.log("DOMFlippable.start", this.flipped, targetCenter, x, y, this.saved);
|
|
||||||
let onUpdate = this.onUpdate !== null ? () => this.onUpdate(this) : null;
|
let onUpdate = this.onUpdate !== null ? () => this.onUpdate(this) : null;
|
||||||
console.log(this.flipDuration);
|
console.log(this.flipDuration);
|
||||||
TweenLite.to(this.card, this.flipDuration, {
|
TweenLite.to(this.card, this.flipDuration, {
|
||||||
|
163
dist/iwmlib.pixi.js
vendored
163
dist/iwmlib.pixi.js
vendored
@ -3263,6 +3263,13 @@
|
|||||||
return Math.sqrt(dx * dx + dy * dy)
|
return Math.sqrt(dx * dx + dy * dy)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Distance == 0.0 indicates an inside relation.
|
||||||
|
static distanceToRect(p, r) {
|
||||||
|
var cx = Math.max(Math.min(p.x, r.x + r.width), r.x);
|
||||||
|
var cy = Math.max(Math.min(p.y, r.y + r.height), r.y);
|
||||||
|
return Math.sqrt((p.x - cx) * (p.x - cx) + (p.y - cy) * (p.y - cy))
|
||||||
|
}
|
||||||
|
|
||||||
static fromPageToNode(element, p) {
|
static fromPageToNode(element, p) {
|
||||||
// if (window.webkitConvertPointFromPageToNode) {
|
// if (window.webkitConvertPointFromPageToNode) {
|
||||||
// return window.webkitConvertPointFromPageToNode(element,
|
// return window.webkitConvertPointFromPageToNode(element,
|
||||||
@ -6917,7 +6924,8 @@
|
|||||||
width = null, // required
|
width = null, // required
|
||||||
height = null, // required
|
height = null, // required
|
||||||
resizable = false,
|
resizable = false,
|
||||||
simulateClick = false,
|
clickOnTap = false,
|
||||||
|
allowClickDistance = 44,
|
||||||
verbose = true,
|
verbose = true,
|
||||||
onResize = null,
|
onResize = null,
|
||||||
touchAction = 'none',
|
touchAction = 'none',
|
||||||
@ -6968,7 +6976,7 @@
|
|||||||
this.height = height;
|
this.height = height;
|
||||||
this.throwVisibility = Math.min(width, height, throwVisibility);
|
this.throwVisibility = Math.min(width, height, throwVisibility);
|
||||||
this.container = container;
|
this.container = container;
|
||||||
this.simulateClick = simulateClick;
|
this.clickOnTap = clickOnTap;
|
||||||
this.scale = startScale;
|
this.scale = startScale;
|
||||||
this.rotationDegrees = this.startRotationDegrees;
|
this.rotationDegrees = this.startRotationDegrees;
|
||||||
this.transformOrigin = transformOrigin;
|
this.transformOrigin = transformOrigin;
|
||||||
@ -6981,7 +6989,8 @@
|
|||||||
rotation: this.startRotationDegrees,
|
rotation: this.startRotationDegrees,
|
||||||
transformOrigin: transformOrigin
|
transformOrigin: transformOrigin
|
||||||
};
|
};
|
||||||
|
this.tapNodes = new Map();
|
||||||
|
this.allowClickDistance = allowClickDistance;
|
||||||
|
|
||||||
// For tweenlite we need initial values in _gsTransform
|
// For tweenlite we need initial values in _gsTransform
|
||||||
TweenLite.set(element, this.initialValues);
|
TweenLite.set(element, this.initialValues);
|
||||||
@ -7174,15 +7183,98 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
onTap(event, interaction, point) {
|
onTap(event, interaction, point) {
|
||||||
if (this.simulateClick) {
|
|
||||||
let p = Points.fromPageToNode(this.element, point);
|
if (this.clickOnTap) {
|
||||||
let element = document.elementFromPoint(p.x, p.y);
|
let directNode = document.elementFromPoint(point.x, point.y);
|
||||||
if (element != null) {
|
let nearestNode = this.nearestClickable(event);
|
||||||
console.log('tap simulates click');
|
|
||||||
element.click();
|
console.log("onTap", directNode, nearestNode.tagName);
|
||||||
|
if (directNode != null && this.isClickable(directNode)) {
|
||||||
|
directNode.click();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (nearestNode.tagName == 'svg' && this.isClickable(nearestNode)) {
|
||||||
|
let handler = this.tapNodes.get(nearestNode);
|
||||||
|
console.log("Clicking beneath SVG: to be done", handler);
|
||||||
|
Events$1.stop(event);
|
||||||
|
//nearestNode.click()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a click or tap behavior to the node. Uses
|
||||||
|
* either the scatter clickOnTap version which requires click handlers
|
||||||
|
* or uses the hammer.js driven tap handler.
|
||||||
|
*
|
||||||
|
* @param {*} node
|
||||||
|
* @param {*} handler
|
||||||
|
* @memberof DOMScatter
|
||||||
|
*/
|
||||||
|
|
||||||
|
addTapListener(node, handler) {
|
||||||
|
if (this.clickOnTap) {
|
||||||
|
node.addEventListener('click', handler);
|
||||||
|
this.tapNodes.set(node, handler);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
InteractionMapper$1.on('tap', node, handler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
isClickable(node) {
|
||||||
|
if (node.tagName == 'A')
|
||||||
|
return true
|
||||||
|
if (this.tapNodes.has(node))
|
||||||
|
return true
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array of all clickable nodes.
|
||||||
|
* Unfortunately we cannot search for all nodes with an attached 'click' event listener
|
||||||
|
* See https://stackoverflow.com/questions/11455515/how-to-check-whether-dynamically-attached-event-listener-exists-or-not
|
||||||
|
* Therefore we can only detect the following standard cases:
|
||||||
|
* I. All clickable objects like clickables
|
||||||
|
* II. Objects that have been attached a click handler by the scatter itself via
|
||||||
|
*/
|
||||||
|
clickableNodes() {
|
||||||
|
let result = [];
|
||||||
|
for (let node of this.element.querySelectorAll("*")) {
|
||||||
|
if (this.isClickable(node))
|
||||||
|
result.push(node);
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
nearestClickable(event) {
|
||||||
|
let element = this.element;
|
||||||
|
let clickables = this.clickableNodes();
|
||||||
|
let globalClick = (event.center) ? event.center : { x: event.x, y: event.y };
|
||||||
|
let localClick = Points.fromPageToNode(element, globalClick);
|
||||||
|
|
||||||
|
let clickRects = clickables.map(link => {
|
||||||
|
let rect = link.getBoundingClientRect();
|
||||||
|
let topLeft = Points.fromPageToNode(element, rect);
|
||||||
|
let center = Points.fromPageToNode(element, { x: rect.x + rect.width / 2, y: rect.y + rect.height / 2 });
|
||||||
|
return { x: topLeft.x, y: topLeft.y, width: rect.width, height: rect.height, center, link }
|
||||||
|
});
|
||||||
|
|
||||||
|
let distances = [];
|
||||||
|
clickRects.forEach(rect => {
|
||||||
|
let distance = Points.distanceToRect(localClick, rect);
|
||||||
|
distances.push(parseInt(distance));
|
||||||
|
});
|
||||||
|
|
||||||
|
let closestClickIndex = distances.indexOf(Math.min(...distances));
|
||||||
|
let closestClickable = clickables[closestClickIndex];
|
||||||
|
if (distances[closestClickIndex] < this.allowClickDistance) {
|
||||||
|
console.log("found closest clickables", closestClickable);
|
||||||
|
return closestClickable
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
isDescendant(parent, child) {
|
isDescendant(parent, child) {
|
||||||
let node = child.parentNode;
|
let node = child.parentNode;
|
||||||
@ -7369,6 +7461,7 @@
|
|||||||
translatable = true,
|
translatable = true,
|
||||||
scalable = true,
|
scalable = true,
|
||||||
rotatable = true,
|
rotatable = true,
|
||||||
|
clickOnTap = false,
|
||||||
onFront = null,
|
onFront = null,
|
||||||
onBack = null,
|
onBack = null,
|
||||||
onClose = null,
|
onClose = null,
|
||||||
@ -7388,6 +7481,7 @@
|
|||||||
this.translatable = translatable;
|
this.translatable = translatable;
|
||||||
this.scalable = scalable;
|
this.scalable = scalable;
|
||||||
this.rotatable = rotatable;
|
this.rotatable = rotatable;
|
||||||
|
this.clickOnTap = clickOnTap;
|
||||||
this.onFrontFlipped = onFront;
|
this.onFrontFlipped = onFront;
|
||||||
this.onBackFlipped = onBack;
|
this.onBackFlipped = onBack;
|
||||||
this.onClose = onClose;
|
this.onClose = onClose;
|
||||||
@ -7442,7 +7536,8 @@
|
|||||||
translatable: this.translatable,
|
translatable: this.translatable,
|
||||||
scalable: this.scalable,
|
scalable: this.scalable,
|
||||||
rotatable: this.rotatable,
|
rotatable: this.rotatable,
|
||||||
overdoScaling: this.overdoScaling
|
overdoScaling: this.overdoScaling,
|
||||||
|
clickOnTap: this.clickOnTap
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -7451,7 +7546,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.closeOnMinScale) {
|
if (this.closeOnMinScale) {
|
||||||
|
|
||||||
const removeOnMinScale = function () {
|
const removeOnMinScale = function () {
|
||||||
if (scatter.scale <= scatter.minScale) {
|
if (scatter.scale <= scatter.minScale) {
|
||||||
this.flippable.close();
|
this.flippable.close();
|
||||||
@ -7466,11 +7560,7 @@
|
|||||||
scatter.onTransform.splice(callbackIdx, 1);
|
scatter.onTransform.splice(callbackIdx, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}.bind(this);
|
}.bind(this);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
scatter.addTransformEventCallback(removeOnMinScale);
|
scatter.addTransformEventCallback(removeOnMinScale);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7506,8 +7596,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
start({ targetCenter = null } = {}) {
|
start({ targetCenter = null } = {}) {
|
||||||
console.log('DOMFlip.start', targetCenter);
|
console.log("DOMFlip.start", targetCenter);
|
||||||
if (this.preloadBack) this.flippable.start({ duration: this.flipDuration, targetCenter });
|
if (this.preloadBack) {
|
||||||
|
|
||||||
|
this.flippable.start({ duration: this.flipDuration, targetCenter });
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
let back = this.cardWrapper.querySelector('.back');
|
let back = this.cardWrapper.querySelector('.back');
|
||||||
let flippable = this.flippable;
|
let flippable = this.flippable;
|
||||||
@ -7559,7 +7652,7 @@
|
|||||||
this.flipDuration = flip.flipDuration;
|
this.flipDuration = flip.flipDuration;
|
||||||
this.fadeDuration = flip.fadeDuration;
|
this.fadeDuration = flip.fadeDuration;
|
||||||
scatter.addTransformEventCallback(this.scatterTransformed.bind(this));
|
scatter.addTransformEventCallback(this.scatterTransformed.bind(this));
|
||||||
console.log('lib.DOMFlippable', 5000);
|
|
||||||
TweenLite.set(this.element, { perspective: 5000 });
|
TweenLite.set(this.element, { perspective: 5000 });
|
||||||
TweenLite.set(this.card, { transformStyle: 'preserve-3d' });
|
TweenLite.set(this.card, { transformStyle: 'preserve-3d' });
|
||||||
TweenLite.set(this.back, { rotationY: -180 });
|
TweenLite.set(this.back, { rotationY: -180 });
|
||||||
@ -7572,15 +7665,24 @@
|
|||||||
this.backBtn = element.querySelector('.backBtn');
|
this.backBtn = element.querySelector('.backBtn');
|
||||||
this.closeBtn = element.querySelector('.closeBtn');
|
this.closeBtn = element.querySelector('.closeBtn');
|
||||||
/* Buttons are not guaranteed to exist. */
|
/* Buttons are not guaranteed to exist. */
|
||||||
|
|
||||||
if (this.infoBtn) {
|
if (this.infoBtn) {
|
||||||
InteractionMapper$1.on('tap', this.infoBtn, event => this.flip.start());
|
scatter.addTapListener(this.infoBtn, event => {
|
||||||
|
console.log("within click handler", this);
|
||||||
|
this.flip.start();
|
||||||
|
});
|
||||||
this.enable(this.infoBtn);
|
this.enable(this.infoBtn);
|
||||||
}
|
}
|
||||||
if (this.backBtn) {
|
if (this.backBtn) {
|
||||||
InteractionMapper$1.on('tap', this.backBtn, event => this.start());
|
scatter.addTapListener(this.backBtn, event => {
|
||||||
|
console.log("within click handler", this);
|
||||||
|
this.start();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
if (this.closeBtn) {
|
if (this.closeBtn) {
|
||||||
InteractionMapper$1.on('tap', this.closeBtn, event => this.close());
|
scatter.addTapListener(this.closeBtn, event => {
|
||||||
|
this.close();
|
||||||
|
});
|
||||||
this.enable(this.closeBtn);
|
this.enable(this.closeBtn);
|
||||||
}
|
}
|
||||||
this.scaleButtons();
|
this.scaleButtons();
|
||||||
@ -7630,18 +7732,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
scaleButtons() {
|
scaleButtons() {
|
||||||
//This also works for svgs.
|
|
||||||
// if (this.infoBtn)
|
|
||||||
// this.infoBtn.style.transform = "scale(" + this.buttonScale + ")"
|
|
||||||
|
|
||||||
// if (this.backBtn)
|
|
||||||
// this.backBtn.style.transform = "scale(" + this.buttonScale + ")"
|
|
||||||
|
|
||||||
// if (this.closeBtn)
|
|
||||||
// this.closeBtn.style.transform = "scale(" + this.buttonScale + ")"
|
|
||||||
|
|
||||||
console.log(this.buttonScale);
|
|
||||||
//// This did not work with svgs!
|
|
||||||
TweenLite.set([this.infoBtn, this.backBtn, this.closeBtn], {
|
TweenLite.set([this.infoBtn, this.backBtn, this.closeBtn], {
|
||||||
scale: this.buttonScale
|
scale: this.buttonScale
|
||||||
});
|
});
|
||||||
@ -7654,6 +7744,7 @@
|
|||||||
|
|
||||||
clickInfo() {
|
clickInfo() {
|
||||||
this.bringToFront();
|
this.bringToFront();
|
||||||
|
console.log("clickInfo");
|
||||||
this.infoBtn.click();
|
this.infoBtn.click();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7695,8 +7786,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
enable(button) {
|
enable(button) {
|
||||||
this.show(button, this.fadeDuration);
|
this.show(button, this.fadeDuration);
|
||||||
if (button) {
|
if (button) {
|
||||||
@ -7706,9 +7795,6 @@
|
|||||||
|
|
||||||
disable(button) {
|
disable(button) {
|
||||||
this.hide(button, this.fadeDuration);
|
this.hide(button, this.fadeDuration);
|
||||||
if (button) {
|
|
||||||
TweenLite.set(button, { pointerEvents: 'none' });
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
start({ targetCenter = null } = {}) {
|
start({ targetCenter = null } = {}) {
|
||||||
@ -7752,7 +7838,6 @@
|
|||||||
let x = this.flipped ? xx : this.startX;
|
let x = this.flipped ? xx : this.startX;
|
||||||
let y = this.flipped ? yy : this.startY;
|
let y = this.flipped ? yy : this.startY;
|
||||||
|
|
||||||
console.log("DOMFlippable.start", this.flipped, targetCenter, x, y, this.saved);
|
|
||||||
let onUpdate = this.onUpdate !== null ? () => this.onUpdate(this) : null;
|
let onUpdate = this.onUpdate !== null ? () => this.onUpdate(this) : null;
|
||||||
console.log(this.flipDuration);
|
console.log(this.flipDuration);
|
||||||
TweenLite.to(this.card, this.flipDuration, {
|
TweenLite.to(this.card, this.flipDuration, {
|
||||||
|
@ -72,7 +72,7 @@ if (Capabilities.supportsTemplate()) {
|
|||||||
flipTemplate,
|
flipTemplate,
|
||||||
new ImageLoader('./examples/king.jpeg'),
|
new ImageLoader('./examples/king.jpeg'),
|
||||||
new ImageLoader('./examples/women.jpeg'),
|
new ImageLoader('./examples/women.jpeg'),
|
||||||
{ onUpdate: e => console.log(e)})
|
{ clickOnTap: true})
|
||||||
flip.load().then((flip) => {
|
flip.load().then((flip) => {
|
||||||
flip.centerAt({ x: 150, y: 120})
|
flip.centerAt({ x: 150, y: 120})
|
||||||
})
|
})
|
||||||
@ -80,10 +80,5 @@ if (Capabilities.supportsTemplate()) {
|
|||||||
else {
|
else {
|
||||||
alert("Templates not supported, use Edge, Chrome, Safari or Firefox.")
|
alert("Templates not supported, use Edge, Chrome, Safari or Firefox.")
|
||||||
}
|
}
|
||||||
|
|
||||||
setTimeout(function() {
|
|
||||||
const infoBtn = document.querySelector('.infoBtn')
|
|
||||||
InteractionMapper.on('tap', infoBtn, event => console.log('go'))
|
|
||||||
}, 2000)
|
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
@ -199,6 +199,7 @@ export class DOMFlip {
|
|||||||
translatable = true,
|
translatable = true,
|
||||||
scalable = true,
|
scalable = true,
|
||||||
rotatable = true,
|
rotatable = true,
|
||||||
|
clickOnTap = false,
|
||||||
onFront = null,
|
onFront = null,
|
||||||
onBack = null,
|
onBack = null,
|
||||||
onClose = null,
|
onClose = null,
|
||||||
@ -218,6 +219,7 @@ export class DOMFlip {
|
|||||||
this.translatable = translatable
|
this.translatable = translatable
|
||||||
this.scalable = scalable
|
this.scalable = scalable
|
||||||
this.rotatable = rotatable
|
this.rotatable = rotatable
|
||||||
|
this.clickOnTap = clickOnTap
|
||||||
this.onFrontFlipped = onFront
|
this.onFrontFlipped = onFront
|
||||||
this.onBackFlipped = onBack
|
this.onBackFlipped = onBack
|
||||||
this.onClose = onClose
|
this.onClose = onClose
|
||||||
@ -272,7 +274,8 @@ export class DOMFlip {
|
|||||||
translatable: this.translatable,
|
translatable: this.translatable,
|
||||||
scalable: this.scalable,
|
scalable: this.scalable,
|
||||||
rotatable: this.rotatable,
|
rotatable: this.rotatable,
|
||||||
overdoScaling: this.overdoScaling
|
overdoScaling: this.overdoScaling,
|
||||||
|
clickOnTap: this.clickOnTap
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -281,7 +284,6 @@ export class DOMFlip {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.closeOnMinScale) {
|
if (this.closeOnMinScale) {
|
||||||
|
|
||||||
const removeOnMinScale = function () {
|
const removeOnMinScale = function () {
|
||||||
if (scatter.scale <= scatter.minScale) {
|
if (scatter.scale <= scatter.minScale) {
|
||||||
this.flippable.close()
|
this.flippable.close()
|
||||||
@ -296,11 +298,7 @@ export class DOMFlip {
|
|||||||
scatter.onTransform.splice(callbackIdx, 1)
|
scatter.onTransform.splice(callbackIdx, 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}.bind(this)
|
}.bind(this)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
scatter.addTransformEventCallback(removeOnMinScale)
|
scatter.addTransformEventCallback(removeOnMinScale)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -336,8 +334,11 @@ export class DOMFlip {
|
|||||||
}
|
}
|
||||||
|
|
||||||
start({ targetCenter = null } = {}) {
|
start({ targetCenter = null } = {}) {
|
||||||
console.log('DOMFlip.start', targetCenter)
|
console.log("DOMFlip.start", targetCenter)
|
||||||
if (this.preloadBack) this.flippable.start({ duration: this.flipDuration, targetCenter })
|
if (this.preloadBack) {
|
||||||
|
|
||||||
|
this.flippable.start({ duration: this.flipDuration, targetCenter })
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
let back = this.cardWrapper.querySelector('.back')
|
let back = this.cardWrapper.querySelector('.back')
|
||||||
let flippable = this.flippable
|
let flippable = this.flippable
|
||||||
@ -389,7 +390,7 @@ export class DOMFlippable {
|
|||||||
this.flipDuration = flip.flipDuration
|
this.flipDuration = flip.flipDuration
|
||||||
this.fadeDuration = flip.fadeDuration
|
this.fadeDuration = flip.fadeDuration
|
||||||
scatter.addTransformEventCallback(this.scatterTransformed.bind(this))
|
scatter.addTransformEventCallback(this.scatterTransformed.bind(this))
|
||||||
console.log('lib.DOMFlippable', 5000)
|
|
||||||
TweenLite.set(this.element, { perspective: 5000 })
|
TweenLite.set(this.element, { perspective: 5000 })
|
||||||
TweenLite.set(this.card, { transformStyle: 'preserve-3d' })
|
TweenLite.set(this.card, { transformStyle: 'preserve-3d' })
|
||||||
TweenLite.set(this.back, { rotationY: -180 })
|
TweenLite.set(this.back, { rotationY: -180 })
|
||||||
@ -402,15 +403,24 @@ export class DOMFlippable {
|
|||||||
this.backBtn = element.querySelector('.backBtn')
|
this.backBtn = element.querySelector('.backBtn')
|
||||||
this.closeBtn = element.querySelector('.closeBtn')
|
this.closeBtn = element.querySelector('.closeBtn')
|
||||||
/* Buttons are not guaranteed to exist. */
|
/* Buttons are not guaranteed to exist. */
|
||||||
|
|
||||||
if (this.infoBtn) {
|
if (this.infoBtn) {
|
||||||
InteractionMapper.on('tap', this.infoBtn, event => this.flip.start())
|
scatter.addTapListener(this.infoBtn, event => {
|
||||||
|
console.log("within click handler", this)
|
||||||
|
this.flip.start()
|
||||||
|
})
|
||||||
this.enable(this.infoBtn)
|
this.enable(this.infoBtn)
|
||||||
}
|
}
|
||||||
if (this.backBtn) {
|
if (this.backBtn) {
|
||||||
InteractionMapper.on('tap', this.backBtn, event => this.start())
|
scatter.addTapListener(this.backBtn, event => {
|
||||||
|
console.log("within click handler", this)
|
||||||
|
this.start()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
if (this.closeBtn) {
|
if (this.closeBtn) {
|
||||||
InteractionMapper.on('tap', this.closeBtn, event => this.close())
|
scatter.addTapListener(this.closeBtn, event => {
|
||||||
|
this.close()
|
||||||
|
})
|
||||||
this.enable(this.closeBtn)
|
this.enable(this.closeBtn)
|
||||||
}
|
}
|
||||||
this.scaleButtons()
|
this.scaleButtons()
|
||||||
@ -460,18 +470,6 @@ export class DOMFlippable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
scaleButtons() {
|
scaleButtons() {
|
||||||
//This also works for svgs.
|
|
||||||
// if (this.infoBtn)
|
|
||||||
// this.infoBtn.style.transform = "scale(" + this.buttonScale + ")"
|
|
||||||
|
|
||||||
// if (this.backBtn)
|
|
||||||
// this.backBtn.style.transform = "scale(" + this.buttonScale + ")"
|
|
||||||
|
|
||||||
// if (this.closeBtn)
|
|
||||||
// this.closeBtn.style.transform = "scale(" + this.buttonScale + ")"
|
|
||||||
|
|
||||||
console.log(this.buttonScale)
|
|
||||||
//// This did not work with svgs!
|
|
||||||
TweenLite.set([this.infoBtn, this.backBtn, this.closeBtn], {
|
TweenLite.set([this.infoBtn, this.backBtn, this.closeBtn], {
|
||||||
scale: this.buttonScale
|
scale: this.buttonScale
|
||||||
})
|
})
|
||||||
@ -484,6 +482,7 @@ export class DOMFlippable {
|
|||||||
|
|
||||||
clickInfo() {
|
clickInfo() {
|
||||||
this.bringToFront()
|
this.bringToFront()
|
||||||
|
console.log("clickInfo")
|
||||||
this.infoBtn.click()
|
this.infoBtn.click()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -525,8 +524,6 @@ export class DOMFlippable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
enable(button) {
|
enable(button) {
|
||||||
this.show(button, this.fadeDuration)
|
this.show(button, this.fadeDuration)
|
||||||
if (button) {
|
if (button) {
|
||||||
@ -537,7 +534,7 @@ export class DOMFlippable {
|
|||||||
disable(button) {
|
disable(button) {
|
||||||
this.hide(button, this.fadeDuration)
|
this.hide(button, this.fadeDuration)
|
||||||
if (button) {
|
if (button) {
|
||||||
TweenLite.set(button, { pointerEvents: 'none' })
|
// TweenLite.set(button, { pointerEvents: 'none' })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -582,7 +579,6 @@ export class DOMFlippable {
|
|||||||
let x = this.flipped ? xx : this.startX
|
let x = this.flipped ? xx : this.startX
|
||||||
let y = this.flipped ? yy : this.startY
|
let y = this.flipped ? yy : this.startY
|
||||||
|
|
||||||
console.log("DOMFlippable.start", this.flipped, targetCenter, x, y, this.saved)
|
|
||||||
let onUpdate = this.onUpdate !== null ? () => this.onUpdate(this) : null
|
let onUpdate = this.onUpdate !== null ? () => this.onUpdate(this) : null
|
||||||
console.log(this.flipDuration)
|
console.log(this.flipDuration)
|
||||||
TweenLite.to(this.card, this.flipDuration, {
|
TweenLite.to(this.card, this.flipDuration, {
|
||||||
|
@ -15,10 +15,10 @@
|
|||||||
context.clearRect(0, 0, debugCanvas.width, debugCanvas.height)
|
context.clearRect(0, 0, debugCanvas.width, debugCanvas.height)
|
||||||
|
|
||||||
let stage = scatterContainer.polygon
|
let stage = scatterContainer.polygon
|
||||||
stage.draw(context, { stroke: '#FF0000'})
|
stage.draw(context, { stroke: '#0000FF'})
|
||||||
for(let scatter of scatterContainer.scatter.values()) {
|
for(let scatter of scatterContainer.scatter.values()) {
|
||||||
let polygon = scatter.polygon
|
let polygon = scatter.polygon
|
||||||
polygon.draw(context, { stroke: '#FF0000'})
|
polygon.draw(context, { stroke: '#0000FF'})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,7 +48,7 @@ we describe the more basic DOM scatter.
|
|||||||
<img id="women" draggable="false" style="position: absolute;" src="examples/women.jpeg" />
|
<img id="women" draggable="false" style="position: absolute;" src="examples/women.jpeg" />
|
||||||
<img id="king" draggable="false" style="position: absolute;" src="examples/king.jpeg" />
|
<img id="king" draggable="false" style="position: absolute;" src="examples/king.jpeg" />
|
||||||
|
|
||||||
<canvas id="debugCanvas" height="280" style="z-index: 100000; pointer-events: none; position: absolute; border: 1px solid red;">
|
<canvas id="debugCanvas" height="280" style="z-index: 100000; pointer-events: none; position: absolute; border: 1px solid blue;">
|
||||||
Canvas not supported.
|
Canvas not supported.
|
||||||
</canvas>
|
</canvas>
|
||||||
</div>
|
</div>
|
||||||
@ -81,4 +81,39 @@ app.run()
|
|||||||
animatePolygons()
|
animatePolygons()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<h1>
|
||||||
|
Interactive Content
|
||||||
|
</h1>
|
||||||
|
<p>
|
||||||
|
Scatter objects may contain interactive HTML structures. There is one major flag that allows
|
||||||
|
to simulate click events by using taps. If the scatter detects a tap it looks for clickable
|
||||||
|
elements under or nearby the event position and calls the click handler. Thus gestures
|
||||||
|
can be disambiguated as moves, zooms. or taps.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div id="main2" class="grayBorder interactive" style="position: relative; width: 100%; height: 280px;">
|
||||||
|
<!-- Note that we need to set draggable to false to avoid conflicts. The DOM elements
|
||||||
|
must also be positioned absolutely. -->
|
||||||
|
<div id="interactiveContent">
|
||||||
|
<img draggable="false" style="position: absolute;" src="examples/women.jpeg" />
|
||||||
|
<a style="position:absolute; top: 10px; right: 10px; color:white;" href="https://www.iwm-tuebingen.de" target="_blank">A Link</a>
|
||||||
|
<div onclick="alert('clicked')" style="position:absolute; top: 30px; right: 10px; color:white;">A Div with click handler</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script class="doctest">
|
||||||
|
|
||||||
|
let app2 = new App()
|
||||||
|
let scatterContainer2 = new DOMScatterContainer(main2)
|
||||||
|
let scatter2 = new DOMScatter(interactiveContent, scatterContainer2, {
|
||||||
|
x: 44,
|
||||||
|
y: 44,
|
||||||
|
width: 274,
|
||||||
|
height: 184,
|
||||||
|
throwVisibility: 88,
|
||||||
|
minScale: 0.5,
|
||||||
|
maxScale: 1.5})
|
||||||
|
app2.run()
|
||||||
|
</script>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
105
lib/scatter.js
105
lib/scatter.js
@ -931,7 +931,7 @@ export class DOMScatterContainer {
|
|||||||
context.stroke()
|
context.stroke()
|
||||||
}
|
}
|
||||||
requestAnimationFrame(dt => {
|
requestAnimationFrame(dt => {
|
||||||
this.showTouches(dt)
|
this.showTouches(dt, canvas)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1042,7 +1042,8 @@ export class DOMScatter extends AbstractScatter {
|
|||||||
width = null, // required
|
width = null, // required
|
||||||
height = null, // required
|
height = null, // required
|
||||||
resizable = false,
|
resizable = false,
|
||||||
simulateClick = false,
|
clickOnTap = false,
|
||||||
|
allowClickDistance = 44,
|
||||||
verbose = true,
|
verbose = true,
|
||||||
onResize = null,
|
onResize = null,
|
||||||
touchAction = 'none',
|
touchAction = 'none',
|
||||||
@ -1093,7 +1094,7 @@ export class DOMScatter extends AbstractScatter {
|
|||||||
this.height = height
|
this.height = height
|
||||||
this.throwVisibility = Math.min(width, height, throwVisibility)
|
this.throwVisibility = Math.min(width, height, throwVisibility)
|
||||||
this.container = container
|
this.container = container
|
||||||
this.simulateClick = simulateClick
|
this.clickOnTap = clickOnTap
|
||||||
this.scale = startScale
|
this.scale = startScale
|
||||||
this.rotationDegrees = this.startRotationDegrees
|
this.rotationDegrees = this.startRotationDegrees
|
||||||
this.transformOrigin = transformOrigin
|
this.transformOrigin = transformOrigin
|
||||||
@ -1106,7 +1107,8 @@ export class DOMScatter extends AbstractScatter {
|
|||||||
rotation: this.startRotationDegrees,
|
rotation: this.startRotationDegrees,
|
||||||
transformOrigin: transformOrigin
|
transformOrigin: transformOrigin
|
||||||
}
|
}
|
||||||
|
this.tapNodes = new Map()
|
||||||
|
this.allowClickDistance = allowClickDistance
|
||||||
|
|
||||||
// For tweenlite we need initial values in _gsTransform
|
// For tweenlite we need initial values in _gsTransform
|
||||||
TweenLite.set(element, this.initialValues)
|
TweenLite.set(element, this.initialValues)
|
||||||
@ -1299,15 +1301,98 @@ export class DOMScatter extends AbstractScatter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onTap(event, interaction, point) {
|
onTap(event, interaction, point) {
|
||||||
if (this.simulateClick) {
|
|
||||||
let p = Points.fromPageToNode(this.element, point)
|
if (this.clickOnTap) {
|
||||||
let element = document.elementFromPoint(p.x, p.y)
|
let directNode = document.elementFromPoint(point.x, point.y)
|
||||||
if (element != null) {
|
let nearestNode = this.nearestClickable(event)
|
||||||
console.log('tap simulates click')
|
|
||||||
element.click()
|
console.log("onTap", directNode, nearestNode.tagName)
|
||||||
|
if (directNode != null && this.isClickable(directNode)) {
|
||||||
|
directNode.click()
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (nearestNode.tagName == 'svg' && this.isClickable(nearestNode)) {
|
||||||
|
let handler = this.tapNodes.get(nearestNode)
|
||||||
|
console.log("Clicking beneath SVG: to be done", handler)
|
||||||
|
Events.stop(event)
|
||||||
|
//nearestNode.click()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a click or tap behavior to the node. Uses
|
||||||
|
* either the scatter clickOnTap version which requires click handlers
|
||||||
|
* or uses the hammer.js driven tap handler.
|
||||||
|
*
|
||||||
|
* @param {*} node
|
||||||
|
* @param {*} handler
|
||||||
|
* @memberof DOMScatter
|
||||||
|
*/
|
||||||
|
|
||||||
|
addTapListener(node, handler) {
|
||||||
|
if (this.clickOnTap) {
|
||||||
|
node.addEventListener('click', handler)
|
||||||
|
this.tapNodes.set(node, handler)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
InteractionMapper.on('tap', node, handler)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
isClickable(node) {
|
||||||
|
if (node.tagName == 'A')
|
||||||
|
return true
|
||||||
|
if (this.tapNodes.has(node))
|
||||||
|
return true
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array of all clickable nodes.
|
||||||
|
* Unfortunately we cannot search for all nodes with an attached 'click' event listener
|
||||||
|
* See https://stackoverflow.com/questions/11455515/how-to-check-whether-dynamically-attached-event-listener-exists-or-not
|
||||||
|
* Therefore we can only detect the following standard cases:
|
||||||
|
* I. All clickable objects like clickables
|
||||||
|
* II. Objects that have been attached a click handler by the scatter itself via
|
||||||
|
*/
|
||||||
|
clickableNodes() {
|
||||||
|
let result = []
|
||||||
|
for (let node of this.element.querySelectorAll("*")) {
|
||||||
|
if (this.isClickable(node))
|
||||||
|
result.push(node)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
nearestClickable(event) {
|
||||||
|
let element = this.element
|
||||||
|
let clickables = this.clickableNodes()
|
||||||
|
let globalClick = (event.center) ? event.center : { x: event.x, y: event.y }
|
||||||
|
let localClick = Points.fromPageToNode(element, globalClick)
|
||||||
|
|
||||||
|
let clickRects = clickables.map(link => {
|
||||||
|
let rect = link.getBoundingClientRect()
|
||||||
|
let topLeft = Points.fromPageToNode(element, rect)
|
||||||
|
let center = Points.fromPageToNode(element, { x: rect.x + rect.width / 2, y: rect.y + rect.height / 2 })
|
||||||
|
return { x: topLeft.x, y: topLeft.y, width: rect.width, height: rect.height, center, link }
|
||||||
|
})
|
||||||
|
|
||||||
|
let distances = []
|
||||||
|
clickRects.forEach(rect => {
|
||||||
|
let distance = Points.distanceToRect(localClick, rect)
|
||||||
|
distances.push(parseInt(distance))
|
||||||
|
})
|
||||||
|
|
||||||
|
let closestClickIndex = distances.indexOf(Math.min(...distances))
|
||||||
|
let closestClickable = clickables[closestClickIndex]
|
||||||
|
if (distances[closestClickIndex] < this.allowClickDistance) {
|
||||||
|
console.log("found closest clickables", closestClickable)
|
||||||
|
return closestClickable
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
isDescendant(parent, child) {
|
isDescendant(parent, child) {
|
||||||
let node = child.parentNode
|
let node = child.parentNode
|
||||||
|
@ -402,6 +402,13 @@ export class Points {
|
|||||||
return Math.sqrt(dx * dx + dy * dy)
|
return Math.sqrt(dx * dx + dy * dy)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Distance == 0.0 indicates an inside relation.
|
||||||
|
static distanceToRect(p, r) {
|
||||||
|
var cx = Math.max(Math.min(p.x, r.x + r.width), r.x)
|
||||||
|
var cy = Math.max(Math.min(p.y, r.y + r.height), r.y)
|
||||||
|
return Math.sqrt((p.x - cx) * (p.x - cx) + (p.y - cy) * (p.y - cy))
|
||||||
|
}
|
||||||
|
|
||||||
static fromPageToNode(element, p) {
|
static fromPageToNode(element, p) {
|
||||||
// if (window.webkitConvertPointFromPageToNode) {
|
// if (window.webkitConvertPointFromPageToNode) {
|
||||||
// return window.webkitConvertPointFromPageToNode(element,
|
// return window.webkitConvertPointFromPageToNode(element,
|
||||||
|
Loading…
Reference in New Issue
Block a user