B2X5NJ7QAQTOZXHDAGANNGNYHTPN6LWKTJTL5IM6VBP4NETHHS5AC function dragStart(e) {// Add new screens when ctrl is pressedif (e.ctrlKey) {this.addScreen(this.localizePos(e.pos));return;}if (this.focuses[e.id]) {return;}// Bubble target until reached a valid target or the canvasvar elem = e.target;while (elem != this.elem && !elem.dataset.id) {elem = elem.parentElement;}// Obtain draggable interface for targetvar target;if (elem != this.elem) {target = this.screens[elem.dataset.id];this.view.appendChild(target.elem);} else {target = this;}// Call target callbacktarget.elem.classList.add('dragging');if (target.dragStart) {e.source = this;e.delta = [0, 0];target.dragStart(e);}this.focuses[e.id] = {target: target,lastPos: e.pos,};};function dragMove(e) {var focus = this.focuses[e.id];if (!focus) {return;}// Call target callbackvar target = focus.target;if (target.dragMove) {e.source = this;e.delta = vectorSub(e.pos, focus.lastPos);target.dragMove(e);}focus.lastPos = e.pos;};function dragEnd(e) {var focus = this.focuses[e.id];if (!focus) {return;}// Call target callbackvar target = focus.target;target.elem.classList.remove('dragging');if (target.dragEnd) {e.source = this;e.delta = vectorSub(e.pos, focus.lastPos);target.dragEnd(e);}delete this.focuses[e.id];};
elem.addEventListener('mousedown', mouseEvent.bind(this, this.dragStart), false);window.addEventListener('mousemove', mouseEvent.bind(this, this.dragMove), false);window.addEventListener('mouseup', mouseEvent.bind(this, this.dragEnd), false);
elem.addEventListener('mousedown', mouseEvent.bind(this, dragStart), false);window.addEventListener('mousemove', mouseEvent.bind(this, dragMove), false);window.addEventListener('mouseup', mouseEvent.bind(this, dragEnd), false);
// Setup resize event// window.addEventListener('resize', this.recenter.bind(this), false);
elem.addEventListener('touchstart', touchEvent.bind(this, dragStart), false);elem.addEventListener('touchmove', touchEvent.bind(this, dragMove), false);elem.addEventListener('touchend', touchEvent.bind(this, dragEnd), false);
Canvas.prototype.getCenter = function() {var rect = this.elem.getBoundingClientRect();return {x: rect.width / 2,y: rect.height / 2,}
Canvas.prototype.setPos = function(pos) {this.pos = pos;this.view.style.transform = 'translate(' + this.pos[0] + 'px,' + this.pos[1] + 'px)';
return {x: pos.x - rect.left - this.pos.x,y: pos.y - rect.top - this.pos.y,};};
return [pos[0] - rect.left - this.pos[0],pos[1] - rect.top - this.pos[1],];};Canvas.prototype.getScreens = function() {return this.screens.filter((screen) => {// Ignore screens that have focuses on themfor (key in this.focuses) {if (screen == this.focuses[key].target) {return false;}}return true;});};
Canvas.prototype.recenter = function() {this.setPos({x: 0, y: 0});};Canvas.prototype.dragStart = function(e) {// Add new screens when ctrl is pressedif (e.ctrlKey) {this.addScreen(this.localizePoint(e.pos));return;}if (this.focuses[e.id]) {return;}// Bubble target until reached a valid target or the canvasvar target = e.target;while (target != this.elem && !target.dataset.id) {target = target.parentElement;}
// Obtain draggable interface for targetvar dragTarget;if (target != this.elem) {dragTarget = this.screens[target.dataset.id];this.view.appendChild(dragTarget.elem);} else {dragTarget = this;}dragTarget.elem.classList.add('dragging');this.focuses[e.id] = {target: dragTarget,lastPos: e.pos,};};
let focus = this.focuses[e.id];if (!focus) {return;}focus.target.move({x: e.pos.x - focus.lastPos.x,y: e.pos.y - focus.lastPos.y,});focus.lastPos = e.pos;};Canvas.prototype.dragEnd = function(e) {let focus = this.focuses[e.id];if (!focus) {return;}var target = focus.target;if (target.connectClosest) {let blarg = this.screens.filter((screen) => {for (key in this.focuses) {if (screen == this.focuses[key].target) {return false;}}return true;});target.connectClosest(blarg);}focus.target.elem.classList.remove('dragging');delete this.focuses[e.id];};
this.setPos(vectorAdd(this.pos, e.delta));}
this.elem.style.width = this.size.x + 'px';this.elem.style.height = this.size.y + 'px';};Screen.prototype.move = function(d) {this.setPos({x: this.pos.x + d.x,y: this.pos.y + d.y,});};Screen.prototype.distance = function(pos) {var dx = this.pos.x - pos.x;var dy = this.pos.y - pos.y;return Math.sqrt(dx * dx + dy * dy);
this.elem.style.width = this.size[0] + 'px';this.elem.style.height = this.size[1] + 'px';
Screen.prototype.connect = function(screen) {var pad = 5;// Compute edge-edge deltasvar dx = this.pos.x - screen.pos.x;var dy = this.pos.y - screen.pos.y;if (Math.abs(dx) > Math.abs(dy)) {if (dx > 0) {screen.edges.right = this;this.edges.left = screen;this.setPos({x: screen.pos.x + screen.size.x + pad, y: screen.pos.y});} else {screen.edges.left = this;this.edges.right = screen;this.setPos({x: screen.pos.x - this.size.x - pad, y: screen.pos.y});}} else {if (dy > 0) {screen.edges.bottom = this;this.edges.top = screen;this.setPos({x: screen.pos.x, y: screen.pos.y + screen.size.y + pad});} else {screen.edges.top = this;this.edges.bottom = screen;this.setPos({x: screen.pos.x, y: screen.pos.y - this.size.y - pad});
Screen.prototype.connect = function(other) {// Find the dimension with the largest delta// TODO: Take into account aspect ratiovar delta = vectorSub(this.pos, other.pos);var dim = delta.reduce((max, curr, dim) => {if (max == null || Math.abs(curr) > Math.abs(delta[max])) {return dim;
}
return max;}, null);// Determine which sides to connect togethervar side = delta[dim] < 0 ? 0 : 1;other.edges[dim][side] = this;this.edges[dim][1 - side] = other;// Walk around the graph to find direct neighbours (only works in 2D)other.edges[1 - dim].forEach((screen, pathSide) => {if (!screen) return;screen = screen.edges[dim][side];if (!screen) return;// Found a neighbourthis.edges[1 - dim][pathSide] = screen;screen.edges[1 - dim][1 - pathSide] = this;screen = screen.edges[dim][side];if (!screen) return;screen = screen.edges[1 - dim][1 - pathSide];if (!screen) return;// Found a neighbour (if found by one path, should be found by all paths)this.edges[dim][side] = screen;screen.edges[dim][1 - side] = this;});// Move this screen adjacent to the other screenvar pos = other.pos.slice();var offset = ((this.size[dim] + other.size[dim]) / 2 + gridPad);pos[dim] += (2 * side - 1) * offset;this.setPos(pos);};Screen.prototype.swap = function(dim, side) {// console.log('swap:', dim, side);// var other = this.edges[dim][side];// // Swap edges// var temp = this.edges;// this.edges = other.edges;// this.edges[1 - side] = other;// other.edges = temp;// other.edges[side] = this;// // Reposition other screen// var pos = other.pos;// var offset = ((this.size[dim] + other.size[dim]) / 2 + gridPad);// pos[dim] -= (2 * side - 1) * offset;// other.setPos(pos);
Screen.prototype.dragMove = function(e) {this.setPos(vectorAdd(this.pos, e.delta));// Swap when this center meets the edge of another screenthis.pos.forEach((val, dim) => {this.edges[dim].forEach((other, side) => {if (other && val >= other.pos[dim] - (2 * side - 1) * other.size[dim] / 2) {this.swap(dim, side);}});});};Screen.prototype.dragEnd = function(e) {this.connectClosest(e.source.getScreens());};