Skip to content

Commit

Permalink
Integrate /zone map into OnsenUI
Browse files Browse the repository at this point in the history
- replace hammerjs by own implementation
- removes zone/goto coordinates to eliminate dependency on html
- allows to define multiple zones
- allows to modify the zones
  • Loading branch information
matthiasharrer authored and Hypfer committed Feb 19, 2019
1 parent ef2fb0e commit 70d6aba
Show file tree
Hide file tree
Showing 10 changed files with 1,279 additions and 478 deletions.
431 changes: 144 additions & 287 deletions client/index.html

Large diffs are not rendered by default.

715 changes: 715 additions & 0 deletions client/js/geometry-polyfill.js

Large diffs are not rendered by default.

7 changes: 0 additions & 7 deletions client/zone/hammer.min.js

This file was deleted.

48 changes: 6 additions & 42 deletions client/zone/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@

body {
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-columns: 1fr 1fr 1fr 1fr;
grid-template-rows: 1fr 100px;
grid-template-areas:
"map map"
"button1 button2";
"map map map map"
"button1 button2 button3 button4";
justify-items: stretch;
align-items: stretch;
}
Expand All @@ -41,52 +41,16 @@
touch-action: none;
background-image: linear-gradient(var(--map-background-1), var(--map-background-2));
}
#console {
display: block;
position: absolute;
right: 0;
top: 0;
width: 300px;
max-width: 90%;
background: rgba(255,255,255,0.8);
border: 1px solid #000;
padding: 10px;
}
#console .pt_val {
width: 100%;
position: relative;
overflow: hidden;
display: block;
margin-bottom: 5px;
}
#console label, #console input {
display: inline;
margin: 0;
padding: 0;
}
#console label {
width: 13%;
}
#console input {
width: 35%;
}
</style>
</head>

<body>
<canvas id="experiments"></canvas>
<div id="console">
<div class="pt_val">
<label for="x1">X1: </label><input type="text" name="x1" id="x1" readonly /><label for="y1">Y1: </label><input type="text" name="y1" id="y1" readonly />
</div>
<div class="pt_val">
<label for="x2">X2: </label><input type="text" name="x2" id="x2" readonly /><label for="y2">Y2: </label><input type="text" name="y2" id="y2" readonly />
</div>
</div>
<button id="add_zone">Add zone</button>
<button id="goto">Goto</button>
<button id="zone">Zone</button>
<button id="repeat">Repeat: 1</button>
<button id="clean">Clean</button>
<script src="geometry-polyfill.js"></script>
<script src="hammer.min.js"></script>
<script src="main.js" type="module"></script>
</body>

Expand Down
4 changes: 3 additions & 1 deletion client/zone/js-modules/locations.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ export class Zone {

return {
updatedLocation: this,
stopPropagation: true
stopPropagation: false
};
} else {
this.active = false;
Expand Down Expand Up @@ -179,6 +179,8 @@ export class Zone {
updatedLocation: this,
stopPropagation: true
};
} else {
this.active = false;
}
}

Expand Down
4 changes: 2 additions & 2 deletions client/zone/js-modules/map-drawer.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ export function MapDrawer() {
function draw(mapData) {
this.boundingBox = getBoundingBox(mapData, mapCanvas.width, mapCanvas.height);

const freeColor = hexToRgb(getComputedStyle(document.documentElement).getPropertyValue('--map-free'));
const occupiedColor = hexToRgb(getComputedStyle(document.documentElement).getPropertyValue('--map-occupied'));
const freeColor = hexToRgb(getComputedStyle(document.documentElement).getPropertyValue('--map-free') || '#0076ff');
const occupiedColor = hexToRgb(getComputedStyle(document.documentElement).getPropertyValue('--map-occupied') || '#6699ff');

mapCtx.clearRect(0, 0, mapCanvas.width, mapCanvas.height);
const imgData = mapCtx.createImageData(mapCanvas.width, mapCanvas.height);
Expand Down
2 changes: 1 addition & 1 deletion client/zone/js-modules/path-drawer.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ export function PathDrawer() {
* Externally called function to (re)draw the path to the canvas
*/
function draw() {
const pathColor = getComputedStyle(document.documentElement).getPropertyValue('--path').trim();
const pathColor = (getComputedStyle(document.documentElement).getPropertyValue('--path') || '#ffffff').trim();

const ctx = canvas.getContext("2d");
ctx.clearRect(0, 0, canvas.width, canvas.height);
Expand Down
232 changes: 232 additions & 0 deletions client/zone/js-modules/touch-handling.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
function distance([x1, y1], [x2, y2]) {
return Math.sqrt(
Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)
);
}

class NoGesture {
constructor() {}
updatePointerPosition(evts) {}
removePointer(evt) {
return this;
}
}

class PossibleTap {
constructor(pointerDownEvent, dispatchEvent) {
this.tapTolerance = 5;
this.pointerId = pointerDownEvent.pointerId;
this.pointerDownPosition = [pointerDownEvent.clientX, pointerDownEvent.clientY];
this.lastPosition = [pointerDownEvent.clientX, pointerDownEvent.clientY];

this.dispatchEvent = dispatchEvent;
}

toleranceExeeded() {
return distance(this.lastPosition, this.pointerDownPosition) > this.tapTolerance;
}

updatePointerPosition(evts) {
this.lastPosition = [evts[0].clientX, evts[0].clientY];
}

removePointer(evt) {
if(evt.pointerId === this.pointerId) {
const tapEvent = new Event("tap");
tapEvent.tappedCoordinates = {x: this.pointerDownPosition[0], y: this.pointerDownPosition[1]};
this.dispatchEvent(tapEvent);

return new NoGesture();
} else {
return this;
}
}
}

class OngoingPan {
constructor(pointerId, [pointerDownX, pointerDownY], [currentX, currentY], dispatchEvent) {
this.pointerId = pointerId;
this.pointerDownPosition = [pointerDownX, pointerDownY];
this.lastPosition = [currentX, currentY];

this.dispatchEvent = dispatchEvent;

const panStartEvent = new Event("panstart");
panStartEvent.coordinates = {x: this.pointerDownPosition[0], y: this.pointerDownPosition[1]};
this.dispatchEvent(panStartEvent);
}

updatePointerPosition(evts) {
this.lastPosition = [evts[0].clientX, evts[0].clientY];

const panMoveEvent = new Event("panmove");
panMoveEvent.startCoordinates = {x: this.pointerDownPosition[0], y: this.pointerDownPosition[1]};
panMoveEvent.currentCoordinates = {x: evts[0].clientX, y: evts[0].clientY};
this.dispatchEvent(panMoveEvent);
}

removePointer(evt) {
if(evt.pointerId === this.pointerId) {
const panEndEvent = new Event("panend");
panEndEvent.startCoordinates = {x: this.pointerDownPosition[0], y: this.pointerDownPosition[1]};
panEndEvent.currentCoordinates = {x: evt.clientX, y: evt.clientY};
this.dispatchEvent(panEndEvent);

return new NoGesture();
} else {
return this;
}
}
}

class OngoingPinch {
constructor(pointerId, [pointerDownX, pointerDownY], secondPointerDownEvent, dispatchEvent) {
this.tapTolerance = 5;
this.pointerId = pointerId;
this.pointerDownPosition = [pointerDownX, pointerDownY];
this.lastPosition = [pointerDownX, pointerDownY];
this.pointer2Id = secondPointerDownEvent.pointerId;
this.pointer2DownPosition = [secondPointerDownEvent.clientX, secondPointerDownEvent.clientY];
this.lastPosition2 = [secondPointerDownEvent.clientX, secondPointerDownEvent.clientY];

this.dispatchEvent = dispatchEvent;

const pinchStartEvent = new Event("pinchstart");
pinchStartEvent.distance = distance(this.pointerDownPosition, this.pointer2DownPosition);
pinchStartEvent.scale = 1;
pinchStartEvent.center = {
x: (this.pointerDownPosition[0] + this.pointer2DownPosition[0]) / 2,
y: (this.pointerDownPosition[1] + this.pointer2DownPosition[1]) / 2
}
this.dispatchEvent(pinchStartEvent);
}

updatePointerPosition(evts) {
for(let evt of evts) {
if(evt.pointerId === this.pointerId) {
this.lastPosition = [evt.clientX, evt.clientY];
} else if (evt.pointerId === this.pointer2Id) {
this.lastPosition2 = [evt.clientX, evt.clientY];
}
}

const pinchMoveEvent = new Event("pinchmove");
pinchMoveEvent.distance = distance(this.lastPosition, this.lastPosition2);
pinchMoveEvent.scale = pinchMoveEvent.distance / distance(this.pointerDownPosition, this.pointer2DownPosition);
pinchMoveEvent.center = {
x: (this.lastPosition[0] + this.lastPosition2[0]) / 2,
y: (this.lastPosition[1] + this.lastPosition2[1]) / 2
}

this.dispatchEvent(pinchMoveEvent);
}

removePointer(evt) {
if(evt.pointerId === this.pointerId) {
this.dispatchEvent(new Event("pinchend"));
return new OngoingPan(
this.pointer2Id,
this.lastPosition2,
this.lastPosition2,
this.dispatchEvent
);
} else if (evt.pointerId === this.pointer2Id) {
this.dispatchEvent(new Event("pinchend"));
return new OngoingPan(
this.pointerId,
this.lastPosition,
this.lastPosition,
this.dispatchEvent
);
} else {
return this;
}
}
}

export class TouchHandler {
/**
* @param {HTMLElement} trackedElement
*/
constructor(trackedElement) {
this.trackedElement = trackedElement;
this.trackedElement.addEventListener("mousedown", e => this.pointerDown(e, this.touchChangesFromMouseEvent(e)));
this.trackedElement.addEventListener("mousemove", e => this.pointerMove(e, this.touchChangesFromMouseEvent(e)));
this.trackedElement.addEventListener("mouseup", e => this.pointerUp(e, this.touchChangesFromMouseEvent(e)));
this.trackedElement.addEventListener("mouseleave", e => this.pointerUp(e, this.touchChangesFromMouseEvent(e)));
this.trackedElement.addEventListener("mouseout", e => this.pointerUp(e, this.touchChangesFromMouseEvent(e)));

this.trackedElement.addEventListener("touchstart", e => this.pointerDown(e, this.touchChangesFromTouchEvent(e)));
this.trackedElement.addEventListener("touchmove", e => this.pointerMove(e, this.touchChangesFromTouchEvent(e)));
this.trackedElement.addEventListener("touchcancel", e => this.pointerUp(e, this.touchChangesFromTouchEvent(e)));
this.trackedElement.addEventListener("touchend", e => this.pointerUp(e, this.touchChangesFromTouchEvent(e)));

this.ongoingGesture = new NoGesture();
}


touchChangesFromMouseEvent(evt) {
return [{
clientX: evt.clientX,
clientY: evt.clientY,
pointerId: 0
}];
}

touchChangesFromTouchEvent(evt) {
const changedTouches = []

for(let touch of evt.changedTouches) {
changedTouches.push({
clientX: touch.clientX,
clientY: touch.clientY,
pointerId: touch.identifier
});
}

return changedTouches;
}

pointerDown(evt, changedTouches) {
evt.stopPropagation();
evt.preventDefault();

if(this.ongoingGesture instanceof NoGesture) {
this.ongoingGesture = new PossibleTap(changedTouches[0], this.trackedElement.dispatchEvent.bind(this.trackedElement));

} else if(this.ongoingGesture instanceof PossibleTap || this.ongoingGesture instanceof OngoingPan) {
this.ongoingGesture = new OngoingPinch(
this.ongoingGesture.pointerId,
// start the pinch with the first pointer at the current position
// (when the second pointer was added)
this.ongoingGesture.lastPosition,
changedTouches[0],
this.trackedElement.dispatchEvent.bind(this.trackedElement)
);
}
}

pointerMove(evt, changedTouches) {
evt.stopPropagation();
evt.preventDefault();

this.ongoingGesture.updatePointerPosition(changedTouches);

// Upgrade Tap to a Pan if the movement tolerance is exeeded
if(this.ongoingGesture instanceof PossibleTap && this.ongoingGesture.toleranceExeeded()) {
this.ongoingGesture = new OngoingPan(
this.ongoingGesture.pointerId,
this.ongoingGesture.pointerDownPosition,
this.ongoingGesture.lastPosition,
this.trackedElement.dispatchEvent.bind(this.trackedElement)
)
}
}

pointerUp(evt, changedTouches) {
evt.stopPropagation();
evt.preventDefault();

this.ongoingGesture = this.ongoingGesture.removePointer(changedTouches[0]);
}
}
Loading

0 comments on commit 70d6aba

Please sign in to comment.