Merge branch 'master' of gitea.iwm-tuebingen.de:IWMBrowser/iwmlib

# Conflicts:
#	dist/iwmlib.js
This commit is contained in:
2019-07-05 13:58:20 +02:00
7 changed files with 420 additions and 132 deletions
+127 -42
View File
@@ -987,6 +987,13 @@
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) {
// if (window.webkitConvertPointFromPageToNode) {
// return window.webkitConvertPointFromPageToNode(element,
@@ -5044,7 +5051,7 @@
context.stroke();
}
requestAnimationFrame(dt => {
this.showTouches(dt);
this.showTouches(dt, canvas);
});
}
@@ -5155,7 +5162,8 @@
width = null, // required
height = null, // required
resizable = false,
simulateClick = false,
clickOnTap = false,
allowClickDistance = 44,
verbose = true,
onResize = null,
touchAction = 'none',
@@ -5206,7 +5214,7 @@
this.height = height;
this.throwVisibility = Math.min(width, height, throwVisibility);
this.container = container;
this.simulateClick = simulateClick;
this.clickOnTap = clickOnTap;
this.scale = startScale;
this.rotationDegrees = this.startRotationDegrees;
this.transformOrigin = transformOrigin;
@@ -5219,7 +5227,8 @@
rotation: this.startRotationDegrees,
transformOrigin: transformOrigin
};
this.tapNodes = new Map();
this.allowClickDistance = allowClickDistance;
// For tweenlite we need initial values in _gsTransform
TweenLite.set(element, this.initialValues);
@@ -5412,16 +5421,99 @@
}
onTap(event, interaction, point) {
if (this.simulateClick) {
let p = Points.fromPageToNode(this.element, point);
let element = document.elementFromPoint(p.x, p.y);
if (element != null) {
console.log('tap simulates click');
element.click();
if (this.clickOnTap) {
let directNode = document.elementFromPoint(point.x, point.y);
let nearestNode = this.nearestClickable(event);
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) {
let node = child.parentNode;
while (node != null) {
@@ -5573,12 +5665,12 @@
this.maxHeight = maxHeight != null ? maxHeight : window.innerHeight;
this.addedNode = null;
console.log({
width,
height,
maxWidth,
maxHeight,
});
}
@@ -5741,6 +5833,7 @@
translatable = true,
scalable = true,
rotatable = true,
clickOnTap = false,
onFront = null,
onBack = null,
onClose = null,
@@ -5760,6 +5853,7 @@
this.translatable = translatable;
this.scalable = scalable;
this.rotatable = rotatable;
this.clickOnTap = clickOnTap;
this.onFrontFlipped = onFront;
this.onBackFlipped = onBack;
this.onClose = onClose;
@@ -5814,7 +5908,8 @@
translatable: this.translatable,
scalable: this.scalable,
rotatable: this.rotatable,
overdoScaling: this.overdoScaling
overdoScaling: this.overdoScaling,
clickOnTap: this.clickOnTap
}
);
@@ -5823,7 +5918,6 @@
}
if (this.closeOnMinScale) {
const removeOnMinScale = function () {
if (scatter.scale <= scatter.minScale) {
this.flippable.close();
@@ -5838,11 +5932,7 @@
scatter.onTransform.splice(callbackIdx, 1);
}
}
}.bind(this);
scatter.addTransformEventCallback(removeOnMinScale);
}
@@ -5878,8 +5968,11 @@
}
start({ targetCenter = null } = {}) {
console.log('DOMFlip.start', targetCenter);
if (this.preloadBack) this.flippable.start({ duration: this.flipDuration, targetCenter });
console.log("DOMFlip.start", targetCenter);
if (this.preloadBack) {
this.flippable.start({ duration: this.flipDuration, targetCenter });
}
else {
let back = this.cardWrapper.querySelector('.back');
let flippable = this.flippable;
@@ -5931,7 +6024,7 @@
this.flipDuration = flip.flipDuration;
this.fadeDuration = flip.fadeDuration;
scatter.addTransformEventCallback(this.scatterTransformed.bind(this));
console.log('lib.DOMFlippable', 5000);
TweenLite.set(this.element, { perspective: 5000 });
TweenLite.set(this.card, { transformStyle: 'preserve-3d' });
TweenLite.set(this.back, { rotationY: -180 });
@@ -5944,15 +6037,24 @@
this.backBtn = element.querySelector('.backBtn');
this.closeBtn = element.querySelector('.closeBtn');
/* Buttons are not guaranteed to exist. */
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);
}
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) {
InteractionMapper$1.on('tap', this.closeBtn, event => this.close());
scatter.addTapListener(this.closeBtn, event => {
this.close();
});
this.enable(this.closeBtn);
}
this.scaleButtons();
@@ -6002,18 +6104,6 @@
}
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], {
scale: this.buttonScale
});
@@ -6026,6 +6116,7 @@
clickInfo() {
this.bringToFront();
console.log("clickInfo");
this.infoBtn.click();
}
@@ -6067,8 +6158,6 @@
}
}
enable(button) {
this.show(button, this.fadeDuration);
if (button) {
@@ -6078,9 +6167,6 @@
disable(button) {
this.hide(button, this.fadeDuration);
if (button) {
TweenLite.set(button, { pointerEvents: 'none' });
}
}
start({ targetCenter = null } = {}) {
@@ -6124,7 +6210,6 @@
let x = this.flipped ? xx : this.startX;
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;
console.log(this.flipDuration);
TweenLite.to(this.card, this.flipDuration, {
+126 -41
View File
@@ -3263,6 +3263,13 @@
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) {
// if (window.webkitConvertPointFromPageToNode) {
// return window.webkitConvertPointFromPageToNode(element,
@@ -6917,7 +6924,8 @@
width = null, // required
height = null, // required
resizable = false,
simulateClick = false,
clickOnTap = false,
allowClickDistance = 44,
verbose = true,
onResize = null,
touchAction = 'none',
@@ -6968,7 +6976,7 @@
this.height = height;
this.throwVisibility = Math.min(width, height, throwVisibility);
this.container = container;
this.simulateClick = simulateClick;
this.clickOnTap = clickOnTap;
this.scale = startScale;
this.rotationDegrees = this.startRotationDegrees;
this.transformOrigin = transformOrigin;
@@ -6981,7 +6989,8 @@
rotation: this.startRotationDegrees,
transformOrigin: transformOrigin
};
this.tapNodes = new Map();
this.allowClickDistance = allowClickDistance;
// For tweenlite we need initial values in _gsTransform
TweenLite.set(element, this.initialValues);
@@ -7174,16 +7183,99 @@
}
onTap(event, interaction, point) {
if (this.simulateClick) {
let p = Points.fromPageToNode(this.element, point);
let element = document.elementFromPoint(p.x, p.y);
if (element != null) {
console.log('tap simulates click');
element.click();
if (this.clickOnTap) {
let directNode = document.elementFromPoint(point.x, point.y);
let nearestNode = this.nearestClickable(event);
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) {
let node = child.parentNode;
while (node != null) {
@@ -7335,12 +7427,12 @@
this.maxHeight = maxHeight != null ? maxHeight : window.innerHeight;
this.addedNode = null;
console.log({
width,
height,
maxWidth,
maxHeight,
});
}
@@ -7369,6 +7461,7 @@
translatable = true,
scalable = true,
rotatable = true,
clickOnTap = false,
onFront = null,
onBack = null,
onClose = null,
@@ -7388,6 +7481,7 @@
this.translatable = translatable;
this.scalable = scalable;
this.rotatable = rotatable;
this.clickOnTap = clickOnTap;
this.onFrontFlipped = onFront;
this.onBackFlipped = onBack;
this.onClose = onClose;
@@ -7442,7 +7536,8 @@
translatable: this.translatable,
scalable: this.scalable,
rotatable: this.rotatable,
overdoScaling: this.overdoScaling
overdoScaling: this.overdoScaling,
clickOnTap: this.clickOnTap
}
);
@@ -7451,7 +7546,6 @@
}
if (this.closeOnMinScale) {
const removeOnMinScale = function () {
if (scatter.scale <= scatter.minScale) {
this.flippable.close();
@@ -7466,11 +7560,7 @@
scatter.onTransform.splice(callbackIdx, 1);
}
}
}.bind(this);
scatter.addTransformEventCallback(removeOnMinScale);
}
@@ -7506,8 +7596,11 @@
}
start({ targetCenter = null } = {}) {
console.log('DOMFlip.start', targetCenter);
if (this.preloadBack) this.flippable.start({ duration: this.flipDuration, targetCenter });
console.log("DOMFlip.start", targetCenter);
if (this.preloadBack) {
this.flippable.start({ duration: this.flipDuration, targetCenter });
}
else {
let back = this.cardWrapper.querySelector('.back');
let flippable = this.flippable;
@@ -7559,7 +7652,7 @@
this.flipDuration = flip.flipDuration;
this.fadeDuration = flip.fadeDuration;
scatter.addTransformEventCallback(this.scatterTransformed.bind(this));
console.log('lib.DOMFlippable', 5000);
TweenLite.set(this.element, { perspective: 5000 });
TweenLite.set(this.card, { transformStyle: 'preserve-3d' });
TweenLite.set(this.back, { rotationY: -180 });
@@ -7572,15 +7665,24 @@
this.backBtn = element.querySelector('.backBtn');
this.closeBtn = element.querySelector('.closeBtn');
/* Buttons are not guaranteed to exist. */
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);
}
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) {
InteractionMapper$1.on('tap', this.closeBtn, event => this.close());
scatter.addTapListener(this.closeBtn, event => {
this.close();
});
this.enable(this.closeBtn);
}
this.scaleButtons();
@@ -7630,18 +7732,6 @@
}
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], {
scale: this.buttonScale
});
@@ -7654,6 +7744,7 @@
clickInfo() {
this.bringToFront();
console.log("clickInfo");
this.infoBtn.click();
}
@@ -7695,8 +7786,6 @@
}
}
enable(button) {
this.show(button, this.fadeDuration);
if (button) {
@@ -7706,9 +7795,6 @@
disable(button) {
this.hide(button, this.fadeDuration);
if (button) {
TweenLite.set(button, { pointerEvents: 'none' });
}
}
start({ targetCenter = null } = {}) {
@@ -7752,7 +7838,6 @@
let x = this.flipped ? xx : this.startX;
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;
console.log(this.flipDuration);
TweenLite.to(this.card, this.flipDuration, {