6PSALZKWII5BVJZG7DOPH2SNY2Q4CJR6QSMROXCTVSJ6UPX2RIUAC .screen {box-sizing: border-box;position: absolute;background-color: #8BC34A;box-shadow: 0px 0px 10px rgba(0,0,0,0.1);border: 5px solid #689f38;transition: transform 0.2s ease-out, opacity 0.2s ease-out, box-shadow 0.2s ease-out;
.draggable {cursor: default;-webkit-touch-callout: none;-webkit-user-select: none;-khtml-user-select: none;-moz-user-select: none;-ms-user-select: none;user-select: none;}
while (target != elem && !target.classList.contains('dragabble')) {target = target.parentElement;}
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);
if (target == elem) {var rel = localizePoint(x, y);var screen = new Screen(rel.x, rel.y);screens.push(screen);target = screen.elem;
// Setup touch eventsfunction touchEvent(cb, e) {for (var i = 0; i < e.changedTouches.length; i++) {var touch = e.changedTouches[i];cb.call(this, {id: touch.identifier,target: e.target,pos: {x: touch.clientX, y: touch.clientY},ctrlKey: e.ctrlKey,});
var dx = x - focus.lastX;var dy = y - focus.lastY;focus.target.style.left = (parseInt(focus.target.style.left) || 0) + dx + 'px';focus.target.style.top = (parseInt(focus.target.style.top) || 0) + dy + 'px';focus.lastX = x;focus.lastY = y;
Canvas.prototype.getCenter = function() {var rect = this.elem.getBoundingClientRect();return {x: rect.width / 2,y: rect.height / 2,
};Canvas.prototype.localizePoint = function(pos) {var rect = this.elem.getBoundingClientRect();return {x: pos.x - rect.left - this.pos.x,y: pos.y - rect.top - this.pos.y,};};Canvas.prototype.addScreen = function(pos) {var id = this.screens.length;var screen = new Screen({id: id,name: 'gallifrey',pos: pos,size: {x: 160, y: 100},});screen.connectClosest(this.screens);this.screens.push(screen);this.view.appendChild(screen.elem);return screen;};Canvas.prototype.setPos = function(pos) {this.pos = pos;this.view.style.transform = 'translate(' + this.pos.x + 'px,' + this.pos.y + 'px)';};Canvas.prototype.move = function(d) {this.setPos({x: this.pos.x + d.x,y: this.pos.y + d.y});};
function dragEnd(id, x, y) {let focus = focuses[id];if (!focus) {return}focus.target.classList.remove('drag');delete focuses[id];
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;
window.addEventListener('mousemove', function(e) {dragMove(null, e.clientX, e.clientY);}, false);window.addEventListener('mouseup', function(e) {dragEnd(null, e.clientX, e.clientY);}, false);
// Bubble target until reached a valid target or the canvasvar target = e.target;while (target != this.elem && !target.dataset.id) {target = target.parentElement;}
// Touchelem.addEventListener('touchstart', function(e) {for (var i = 0; i < e.changedTouches.length; i++) {var touch = e.changedTouches[i];dragStart(touch.target, touch.identifier, touch.clientX, touch.clientY);}e.preventDefault();}, false);
// Obtain draggable interface for targetvar dragTarget;if (target != this.elem) {dragTarget = this.screens[target.dataset.id];this.view.appendChild(dragTarget.elem);} else {dragTarget = this;}
elem.addEventListener('touchmove', function(e) {for (var i = 0; i < e.changedTouches.length; i++) {var touch = e.changedTouches[i];dragMove(touch.identifier, touch.clientX, touch.clientY);}e.preventDefault();}, false);
dragTarget.elem.classList.add('dragging');this.focuses[e.id] = {target: dragTarget,lastPos: e.pos,};};Canvas.prototype.dragMove = function(e) {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,});
function Screen(x, y) {var width = 160;var height = 100;
Canvas.prototype.dragEnd = function(e) {let focus = this.focuses[e.id];if (!focus) {return;}var target = focus.target;if (target.connectClosest) {target.connectClosest(this.screens.filter((screen) => {return screen != target;}));}focus.target.elem.classList.remove('dragging');delete this.focuses[e.id];};function Screen(params) {
Screen.prototype.setPos = function(pos) {this.pos = pos;this.elem.style.left = this.pos.x - this.size.x / 2 + 'px';this.elem.style.top = this.pos.y - this.size.y / 2 + 'px';};Screen.prototype.setSize = function(size) {this.size = size;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);};Screen.prototype.closest = function(screens) {var pos = this.pos;return screens.reduce((min, curr) => {var dist = curr.distance(pos);if (!min || dist < min.dist) {return {dist: dist, screen: curr};}return min;}, null);};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.connectClosest = function(screens) {let closest = this.closest(screens);if (closest) this.connect(closest.screen);};