diff --git a/01_Code/physical_computing_interface/app.js b/01_Code/physical_computing_interface/app.js index d6db620243ecc29c09405f7796aeedb3ea278d69..2cb95555a4847bd58d64501628db0a82acec0165 100644 --- a/01_Code/physical_computing_interface/app.js +++ b/01_Code/physical_computing_interface/app.js @@ -7,6 +7,7 @@ var utils= new utilities(); var GLOBALS=new globals(utils); + var three=new threejs(GLOBALS,utils,'webgl','threejs'); three.init(); @@ -18,3 +19,4 @@ assembler.run(); + diff --git a/01_Code/physical_computing_interface/graph/graph.js b/01_Code/physical_computing_interface/graph/graph.js index 165b3e19eb3fd1f4b8c3aa97d849b76949fc738a..84f6bf915e5cb7d3ad324dbc99d0b34ceb1ea0c1 100644 --- a/01_Code/physical_computing_interface/graph/graph.js +++ b/01_Code/physical_computing_interface/graph/graph.js @@ -6,7 +6,9 @@ function initGraph(){ var color11= "#ffffff8c"; //white transparent var color2= "#020227"; //dark blue var color3= "#1c5c61"; //teal + var color33= "#1c5c618c"; //teal transparent var color4= "#fa6e70"; //red/orange + var color44= "#fa6e708c"; //red/orange var color5="#380152"; //purple var color6="#696767"; //grey var font= "consolas";//'font-family' @@ -63,7 +65,13 @@ function initGraph(){ style: { 'width': 2, 'line-color': color3, - 'curve-style': 'straight' + 'curve-style': 'bezier', //straight + 'target-arrow-color': color3, + 'target-arrow-shape': 'vee', + 'content': 'data(name)', + 'color': color6, + 'font-family':font, + "font-size": 6 } }, @@ -83,6 +91,7 @@ function initGraph(){ } } ], + elements: { nodes: [ // { @@ -159,10 +168,104 @@ function initGraph(){ // { data: { source: 'app', target: 'api', name: 'use' }, classes: 'app' }, // { data: { source: 'app', target: 'ext', name: 'register' }, classes: 'app' } ] - }, + }, + }); + ////////////////////////// + + cy.cxtmenu({ + selector: 'node',//'node, edge', + menuRadius: 50, + fillColor: color11, // the background colour of the menu + activeFillColor: color44, // the colour used to indicate the selected command + // activePadding: 20, // additional size in pixels for the active command + indicatorSize: 20, // the size in pixels of the pointer to the active command + // separatorWidth: 3, // the empty spacing in pixels between successive commands + spotlightPadding: 4, // extra spacing in pixels between the element and the spotlight + minSpotlightRadius: 15, // the minimum radius in pixels of the spotlight + maxSpotlightRadius: 10, // the maximum radius in pixels of the spotlight + // openMenuEvents: 'cxttapstart taphold', // space-separated cytoscape events that will open the menu; only `cxttapstart` and/or `taphold` work here + itemColor: color6, // the colour of text in the command's content + // itemTextShadowColor: 'transparent', // the text shadow colour of the command's content + zIndex: 2*9999, // the z-index of the ui div + // atMouse: false // draw menu at mouse position + + commands: [ + { + content: '<span class="fa fa-play fa-1x"></span>', + select: function(ele){ + console.log( ele.id() ); + } + }, + + { + content: '<span class="fa fa-trash fa-1x"></span>', + select: function(ele){ + console.log( ele.data('name') ); + var tgt = ele; + // console.log(tgt._private.data.id); + var pos=utils.getXYZfromName(tgt._private.data.id); + if(tgt._private.data.name=="N/A"){ + tgt.remove(); + + }else{ + GLOBALS.removeNode(pos.x,pos.y,pos.z); + } + }, + // enabled: true + }, + + { + // content: 'Select', + content: '<span class="fa fa-mouse-pointer fa-1x"></span>', + select: function(ele){ + console.log( ele.id()); + // var nodes = this; + // ele.trigger('tap');//TODO FIX SELECT + + } + } + ] + }); + + cy.cxtmenu({ + selector: 'core', + menuRadius: 50, + fillColor: color11, // the background colour of the menu + activeFillColor: color44, // the colour used to indicate the selected command + // activePadding: 20, // additional size in pixels for the active command + indicatorSize: 20, // the size in pixels of the pointer to the active command + // separatorWidth: 3, // the empty spacing in pixels between successive commands + spotlightPadding: 4, // extra spacing in pixels between the element and the spotlight + minSpotlightRadius: 15, // the minimum radius in pixels of the spotlight + maxSpotlightRadius: 10, // the maximum radius in pixels of the spotlight + // openMenuEvents: 'cxttapstart taphold', // space-separated cytoscape events that will open the menu; only `cxttapstart` and/or `taphold` work here + itemColor: color6, // the colour of text in the command's content + // itemTextShadowColor: 'transparent', // the text shadow colour of the command's content + zIndex: 2*9999, // the z-index of the ui div + // atMouse: false // draw menu at mouse position + + + commands: [ + { + content: '<span class="fa fa-expand-arrows-alt fa-1.5x"></span>', + select: function(){ + // console.log( 'bg1' ); + api.expandAll(); + } + }, + + { + content: '<span class="fa fa-compress-arrows-alt fa-1.5x"></span>', + select: function(){ + api.collapseAll(); + } + } + ] + }); + ///////////////////////// addLayerNodes(GLOBALS.gridSize/2); @@ -266,7 +369,7 @@ function initGraph(){ // data: { id: 'new' + Math.round( Math.random() * 100 ) }, data: { id: e.detail.id, - name: '[' +e.detail.x +"," +e.detail.y+']', + name: 0, parent: ''+e.detail.z, data:{ id: e.detail.id, @@ -274,6 +377,8 @@ function initGraph(){ parent: ''+e.detail.z, code: "sum(x+y/2)", neighbors:[], + inputs:[], + outputs:[], } }, position: { @@ -284,6 +389,7 @@ function initGraph(){ api.expandAll(); addEdges(e.detail.x,e.detail.y,e.detail.z); + // addEvents(e.detail.x,e.detail.y,e.detail.z); // api.expandAll(); }, false); @@ -305,15 +411,18 @@ function initGraph(){ tgt._private.data.data.neighbors.push('[' +x +"," +y+","+z+']'); cy.add([ - { group: "edges", data: { source: '[' +x +"," +y+","+z+']', target: '[' +i1 +"," +j1+","+k1+']', - id:"blaaa"+'[' +x +"," +y+","+z+']'+'[' +i1 +"," +j1+","+k1+']'}} + { group: "edges",data: { name:0, source: '[' +x +"," +y+","+z+']', target: '[' +i1 +"," +j1+","+k1+']', + id:'[' +x +"," +y+","+z+']'+'to[' +i1 +"," +j1+","+k1+']'}} + ]); + cy.add([ + { group: "edges",data: { name:0, target: '[' +x +"," +y+","+z+']', source: '[' +i1 +"," +j1+","+k1+']', + id:'[' +i1 +"," +j1+","+k1+']'+'to[' +x +"," +y+","+z+']'}} ]); } } } //remove node - //TODO: UPDATE EDGES WHEN NODE IS REMOVED, CREATE UPDATE NEIGHBORS FUNCTION cy.on('cxttap', 'node', function( evt ){ var tgt = evt.target || evt.cyTarget; // 3.x || 2.x // console.log(tgt._private.data.id); @@ -363,37 +472,37 @@ function initGraph(){ var api = cy.expandCollapse('get'); var elements = null; - document.getElementById("collapseRecursively").addEventListener("click", function () { - api.collapseRecursively(cy.$(":selected")); - }); + // document.getElementById("collapseRecursively").addEventListener("click", function () { + // api.collapseRecursively(cy.$(":selected")); + // }); - document.getElementById("expandRecursively").addEventListener("click", function () { - api.expandRecursively(cy.$(":selected")); - }); + // document.getElementById("expandRecursively").addEventListener("click", function () { + // api.expandRecursively(cy.$(":selected")); + // }); - document.getElementById("expandAllAndRemove").addEventListener("click", function () { - api.expandAll(); - elements = cy.elements().remove(); - }); + // document.getElementById("expandAllAndRemove").addEventListener("click", function () { + // api.expandAll(); + // elements = cy.elements().remove(); + // }); - document.getElementById("loadInCollapsedState").addEventListener("click", function () { - if (elements){ - cy.add(elements); - api.collapseAll(); - elements = null; - } - else{ - console.warn("Remove elements first by clicking on 'Expand all and remove' button."); - } - }); + // document.getElementById("loadInCollapsedState").addEventListener("click", function () { + // if (elements){ + // cy.add(elements); + // api.collapseAll(); + // elements = null; + // } + // else{ + // console.warn("Remove elements first by clicking on 'Expand all and remove' button."); + // } + // }); - document.getElementById("collapseAll").addEventListener("click", function () { - api.collapseAll(); - }); + // document.getElementById("collapseAll").addEventListener("click", function () { + // api.collapseAll(); + // }); - document.getElementById("expandAll").addEventListener("click", function () { - api.expandAll(); - }); + // document.getElementById("expandAll").addEventListener("click", function () { + // api.expandAll(); + // }); // }); diff --git a/01_Code/physical_computing_interface/graph/style.css b/01_Code/physical_computing_interface/graph/style.css index 3a080dc977f292125a463520111c4ed68f1f0c1a..64e86da8a27b23c5578b1df433797207b11d6da6 100644 --- a/01_Code/physical_computing_interface/graph/style.css +++ b/01_Code/physical_computing_interface/graph/style.css @@ -1,5 +1,5 @@ body { - font: 14px helvetica neue, helvetica, arial, sans-serif; + font: 8px helvetica neue, helvetica, arial, sans-serif; } #cy { @@ -8,4 +8,13 @@ body { position: absolute; left: 0; top: 0; +} + +/* you can set the disabled style how you like on the text/icon */ +.cxtmenu-disabled { + opacity: 0.1; +} +/* you can set the disabled style how you like on the text/icon */ +.cxtmenu { + opacity: 0.1; } \ No newline at end of file diff --git a/01_Code/physical_computing_interface/index.html b/01_Code/physical_computing_interface/index.html index 6d9261ba523dfa7532a5600332bb9ed3897a89a7..7ead2497cdf597ced975b3c874d313ca3e5607d5 100644 --- a/01_Code/physical_computing_interface/index.html +++ b/01_Code/physical_computing_interface/index.html @@ -4,6 +4,10 @@ <title>Physical Computing Interface</title> <link rel="stylesheet" type="text/css" href="style.css" media="screen"/> <link rel="stylesheet" type="text/css" href="./lib/jsoneditor/jsoneditor.css" > + <!-- <link href="https://unpkg.com/font-awesome@5.8.0/css/font-awesome.min.css" rel="stylesheet" type="text/css" /> --> + <!-- <link href="//netdna.bootstrapcdn.com/font-awesome/3.2.1/css/font-awesome.css" rel="stylesheet"> --> + <script src="https://kit.fontawesome.com/99c302ff33.js" crossorigin="anonymous"></script> + </head> <body> @@ -28,16 +32,14 @@ <i> Graph</i> </div> <div id=jsondiveditor> - <p> + <!-- <p> <button class="button" id="expandAll">Expand all</button> <button class="button" id="collapseAll">Collapse all</button> - <!-- <br/> --> <button class="button" id="collapseRecursively">Collapse selected </button> <button class="button" id="expandRecursively">Expand selected </button> - <!-- <br/> --> <button class="button" id="expandAllAndRemove">Expand all and remove</button> <button class="button" id="loadInCollapsedState">Load all collapsed</button> - </p> + </p> --> <div id="cy"></div> </div> @@ -92,6 +94,7 @@ <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script> <script src="./lib/cytoscape.min.js"></script> +<script src="./lib/cytoscape-cxtmenu.js"></script> <script src="https://unpkg.com/layout-base/layout-base.js"></script> <script src="https://unpkg.com/cose-base/cose-base.js"></script> <script src="https://unpkg.com/cytoscape-cose-bilkent/cytoscape-cose-bilkent.js"></script> diff --git a/01_Code/physical_computing_interface/lib/cytoscape-cxtmenu copy.js b/01_Code/physical_computing_interface/lib/cytoscape-cxtmenu copy.js new file mode 100644 index 0000000000000000000000000000000000000000..4294ea67bfd92cadb71705056492661cfbb8da86 --- /dev/null +++ b/01_Code/physical_computing_interface/lib/cytoscape-cxtmenu copy.js @@ -0,0 +1,795 @@ +(function webpackUniversalModuleDefinition(root, factory) { + if(typeof exports === 'object' && typeof module === 'object') + module.exports = factory(); + else if(typeof define === 'function' && define.amd) + define([], factory); + else if(typeof exports === 'object') + exports["cytoscapeCxtmenu"] = factory(); + else + root["cytoscapeCxtmenu"] = factory(); +})(this, function() { +return /******/ (function(modules) { // webpackBootstrap +/******/ // The module cache +/******/ var installedModules = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) { +/******/ return installedModules[moduleId].exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ i: moduleId, +/******/ l: false, +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); +/******/ +/******/ // Flag the module as loaded +/******/ module.l = true; +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; +/******/ +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; +/******/ +/******/ // identity function for calling harmony imports with the correct context +/******/ __webpack_require__.i = function(value) { return value; }; +/******/ +/******/ // define getter function for harmony exports +/******/ __webpack_require__.d = function(exports, name, getter) { +/******/ if(!__webpack_require__.o(exports, name)) { +/******/ Object.defineProperty(exports, name, { +/******/ configurable: false, +/******/ enumerable: true, +/******/ get: getter +/******/ }); +/******/ } +/******/ }; +/******/ +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = function(module) { +/******/ var getter = module && module.__esModule ? +/******/ function getDefault() { return module['default']; } : +/******/ function getModuleExports() { return module; }; +/******/ __webpack_require__.d(getter, 'a', getter); +/******/ return getter; +/******/ }; +/******/ +/******/ // Object.prototype.hasOwnProperty.call +/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; +/******/ +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = ""; +/******/ +/******/ // Load entry module and return exports +/******/ return __webpack_require__(__webpack_require__.s = 4); +/******/ }) +/************************************************************************/ +/******/ ([ +/* 0 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var defaults = __webpack_require__(2); +var assign = __webpack_require__(1); + +var _require = __webpack_require__(3), + removeEles = _require.removeEles, + setStyles = _require.setStyles, + createElement = _require.createElement, + getPixelRatio = _require.getPixelRatio, + getOffset = _require.getOffset; + +var cxtmenu = function cxtmenu(params) { + var options = assign({}, defaults, params); + var cy = this; + var container = cy.container(); + var target = void 0; + + var data = { + options: options, + handlers: [], + container: createElement({ class: 'cxtmenu' }) + }; + + var wrapper = data.container; + var parent = createElement(); + var canvas = createElement({ tag: 'canvas' }); + var commands = []; + var c2d = canvas.getContext('2d'); + var r = options.menuRadius; + var containerSize = (r + options.activePadding) * 2; + var activeCommandI = void 0; + var offset = void 0; + + container.insertBefore(wrapper, container.firstChild); + wrapper.appendChild(parent); + parent.appendChild(canvas); + + setStyles(wrapper, { + position: 'absolute', + zIndex: options.zIndex, + userSelect: 'none', + pointerEvents: 'none' // prevent events on menu in modern browsers + }); + + // prevent events on menu in legacy browsers + ['mousedown', 'mousemove', 'mouseup', 'contextmenu'].forEach(function (evt) { + wrapper.addEventListener(evt, function (e) { + e.preventDefault(); + + return false; + }); + }); + + setStyles(parent, { + display: 'none', + width: containerSize + 'px', + height: containerSize + 'px', + position: 'absolute', + zIndex: 1, + marginLeft: -options.activePadding + 'px', + marginTop: -options.activePadding + 'px', + userSelect: 'none' + }); + + canvas.width = containerSize; + canvas.height = containerSize; + + function createMenuItems() { + removeEles('.cxtmenu-item', parent); + var dtheta = 2 * Math.PI / commands.length; + var theta1 = Math.PI / 2; + var theta2 = theta1 + dtheta; + + for (var i = 0; i < commands.length; i++) { + var command = commands[i]; + + var midtheta = (theta1 + theta2) / 2; + var rx1 = 0.66 * r * Math.cos(midtheta); + var ry1 = 0.66 * r * Math.sin(midtheta); + + var item = createElement({ class: 'cxtmenu-item' }); + setStyles(item, { + color: options.itemColor, + cursor: 'default', + display: 'table', + 'text-align': 'center', + //background: 'red', + position: 'absolute', + 'text-shadow': '-1px -1px 2px ' + options.itemTextShadowColor + ', 1px -1px 2px ' + options.itemTextShadowColor + ', -1px 1px 2px ' + options.itemTextShadowColor + ', 1px 1px 1px ' + options.itemTextShadowColor, + left: '50%', + top: '50%', + 'min-height': r * 0.66 + 'px', + width: r * 0.66 + 'px', + height: r * 0.66 + 'px', + marginLeft: rx1 - r * 0.33 + 'px', + marginTop: -ry1 - r * 0.33 + 'px' + }); + + var content = createElement({ class: 'cxtmenu-content' }); + + if (command.content instanceof HTMLElement) { + content.appendChild(command.content); + } else { + content.innerHTML = command.content; + } + + setStyles(content, { + 'width': r * 0.66 + 'px', + 'height': r * 0.66 + 'px', + 'vertical-align': 'middle', + 'display': 'table-cell' + }); + + setStyles(content, command.contentStyle || {}); + + if (command.disabled === true || command.enabled === false) { + content.setAttribute('class', 'cxtmenu-content cxtmenu-disabled'); + } + + parent.appendChild(item); + item.appendChild(content); + + theta1 += dtheta; + theta2 += dtheta; + } + } + + function queueDrawBg(rspotlight) { + redrawQueue.drawBg = [rspotlight]; + } + + function drawBg(rspotlight) { + rspotlight = rspotlight !== undefined ? rspotlight : rs; + + c2d.globalCompositeOperation = 'source-over'; + + c2d.clearRect(0, 0, containerSize, containerSize); + + // draw background items + c2d.fillStyle = options.fillColor; + var dtheta = 2 * Math.PI / commands.length; + var theta1 = Math.PI / 2; + var theta2 = theta1 + dtheta; + + for (var index = 0; index < commands.length; index++) { + var command = commands[index]; + + if (command.fillColor) { + c2d.fillStyle = command.fillColor; + } + c2d.beginPath(); + c2d.moveTo(r + options.activePadding, r + options.activePadding); + c2d.arc(r + options.activePadding, r + options.activePadding, r, 2 * Math.PI - theta1, 2 * Math.PI - theta2, true); + c2d.closePath(); + c2d.fill(); + + theta1 += dtheta; + theta2 += dtheta; + + c2d.fillStyle = options.fillColor; + } + + // draw separators between items + c2d.globalCompositeOperation = 'destination-out'; + c2d.strokeStyle = 'white'; + c2d.lineWidth = options.separatorWidth; + theta1 = Math.PI / 2; + theta2 = theta1 + dtheta; + + for (var i = 0; i < commands.length; i++) { + var rx1 = r * Math.cos(theta1); + var ry1 = r * Math.sin(theta1); + c2d.beginPath(); + c2d.moveTo(r + options.activePadding, r + options.activePadding); + c2d.lineTo(r + options.activePadding + rx1, r + options.activePadding - ry1); + c2d.closePath(); + c2d.stroke(); + + theta1 += dtheta; + theta2 += dtheta; + } + + c2d.fillStyle = 'white'; + c2d.globalCompositeOperation = 'destination-out'; + c2d.beginPath(); + c2d.arc(r + options.activePadding, r + options.activePadding, rspotlight + options.spotlightPadding, 0, Math.PI * 2, true); + c2d.closePath(); + c2d.fill(); + + c2d.globalCompositeOperation = 'source-over'; + } + + function queueDrawCommands(rx, ry, theta) { + redrawQueue.drawCommands = [rx, ry, theta]; + } + + function drawCommands(rx, ry, theta) { + var dtheta = 2 * Math.PI / commands.length; + var theta1 = Math.PI / 2; + var theta2 = theta1 + dtheta; + + theta1 += dtheta * activeCommandI; + theta2 += dtheta * activeCommandI; + + c2d.fillStyle = options.activeFillColor; + c2d.strokeStyle = 'black'; + c2d.lineWidth = 1; + c2d.beginPath(); + c2d.moveTo(r + options.activePadding, r + options.activePadding); + c2d.arc(r + options.activePadding, r + options.activePadding, r + options.activePadding, 2 * Math.PI - theta1, 2 * Math.PI - theta2, true); + c2d.closePath(); + c2d.fill(); + + c2d.fillStyle = 'white'; + c2d.globalCompositeOperation = 'destination-out'; + + var tx = r + options.activePadding + rx / r * (rs + options.spotlightPadding - options.indicatorSize / 4); + var ty = r + options.activePadding + ry / r * (rs + options.spotlightPadding - options.indicatorSize / 4); + var rot = Math.PI / 4 - theta; + + c2d.translate(tx, ty); + c2d.rotate(rot); + + // clear the indicator + c2d.beginPath(); + c2d.fillRect(-options.indicatorSize / 2, -options.indicatorSize / 2, options.indicatorSize, options.indicatorSize); + c2d.closePath(); + c2d.fill(); + + c2d.rotate(-rot); + c2d.translate(-tx, -ty); + + // c2d.setTransform( 1, 0, 0, 1, 0, 0 ); + + // clear the spotlight + c2d.beginPath(); + c2d.arc(r + options.activePadding, r + options.activePadding, rs + options.spotlightPadding, 0, Math.PI * 2, true); + c2d.closePath(); + c2d.fill(); + + c2d.globalCompositeOperation = 'source-over'; + } + + function updatePixelRatio() { + var pxr = getPixelRatio(); + var w = containerSize; + var h = containerSize; + + canvas.width = w * pxr; + canvas.height = h * pxr; + + canvas.style.width = w + 'px'; + canvas.style.height = h + 'px'; + + c2d.setTransform(1, 0, 0, 1, 0, 0); + c2d.scale(pxr, pxr); + } + + var redrawing = true; + var redrawQueue = {}; + + var raf = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.msRequestAnimationFrame || function (fn) { + return setTimeout(fn, 16); + }; + + var redraw = function redraw() { + if (redrawQueue.drawBg) { + drawBg.apply(null, redrawQueue.drawBg); + } + + if (redrawQueue.drawCommands) { + drawCommands.apply(null, redrawQueue.drawCommands); + } + + redrawQueue = {}; + + if (redrawing) { + raf(redraw); + } + }; + + // kick off + updatePixelRatio(); + redraw(); + + var ctrx = void 0, + ctry = void 0, + rs = void 0; + + var bindings = { + on: function on(events, selector, fn) { + + var _fn = fn; + if (selector === 'core') { + _fn = function _fn(e) { + if (e.cyTarget === cy || e.target === cy) { + // only if event target is directly core + return fn.apply(this, [e]); + } + }; + } + + data.handlers.push({ + events: events, + selector: selector, + fn: _fn + }); + + if (selector === 'core') { + cy.on(events, _fn); + } else { + cy.on(events, selector, _fn); + } + + return this; + } + }; + + function addEventListeners() { + var grabbable = void 0; + var inGesture = false; + var dragHandler = void 0; + var zoomEnabled = void 0; + var panEnabled = void 0; + var boxEnabled = void 0; + var gestureStartEvent = void 0; + + var restoreZoom = function restoreZoom() { + if (zoomEnabled) { + cy.userZoomingEnabled(true); + } + }; + + var restoreGrab = function restoreGrab() { + if (grabbable) { + target.grabify(); + } + }; + + var restorePan = function restorePan() { + if (panEnabled) { + cy.userPanningEnabled(true); + } + }; + + var restoreBoxSeln = function restoreBoxSeln() { + if (boxEnabled) { + cy.boxSelectionEnabled(true); + } + }; + + var restoreGestures = function restoreGestures() { + restoreGrab(); + restoreZoom(); + restorePan(); + restoreBoxSeln(); + }; + + window.addEventListener('resize', updatePixelRatio); + + bindings.on('resize', function () { + updatePixelRatio(); + }).on(options.openMenuEvents, options.selector, function (e) { + target = this; // Remember which node the context menu is for + var ele = this; + var isCy = this === cy; + + if (inGesture) { + parent.style.display = 'none'; + + inGesture = false; + + restoreGestures(); + } + + if (typeof options.commands === 'function') { + var res = options.commands(target); + if (res.then) { + res.then(function (_commands) { + commands = _commands; + openMenu(); + }); + } else { + commands = res; + openMenu(); + } + } else { + commands = options.commands; + openMenu(); + } + + function openMenu() { + if (!commands || commands.length === 0) { + return; + } + + zoomEnabled = cy.userZoomingEnabled(); + cy.userZoomingEnabled(false); + + panEnabled = cy.userPanningEnabled(); + cy.userPanningEnabled(false); + + boxEnabled = cy.boxSelectionEnabled(); + cy.boxSelectionEnabled(false); + + grabbable = target.grabbable && target.grabbable(); + if (grabbable) { + target.ungrabify(); + } + + var rp = void 0, + rw = void 0, + rh = void 0; + if (!isCy && ele.isNode() && !ele.isParent() && !options.atMouse) { + rp = ele.renderedPosition(); + rw = ele.renderedWidth(); + rh = ele.renderedHeight(); + } else { + rp = e.renderedPosition || e.cyRenderedPosition; + rw = 1; + rh = 1; + } + + offset = getOffset(container); + + ctrx = rp.x; + ctry = rp.y; + + createMenuItems(); + + setStyles(parent, { + display: 'block', + left: rp.x - r + 'px', + top: rp.y - r + 'px' + }); + + rs = Math.max(rw, rh) / 2; + rs = Math.max(rs, options.minSpotlightRadius); + rs = Math.min(rs, options.maxSpotlightRadius); + + queueDrawBg(); + + activeCommandI = undefined; + + inGesture = true; + gestureStartEvent = e; + } + }).on('cxtdrag tapdrag', options.selector, dragHandler = function dragHandler(e) { + + if (!inGesture) { + return; + } + + var origE = e.originalEvent; + var isTouch = origE.touches && origE.touches.length > 0; + + var pageX = (isTouch ? origE.touches[0].pageX : origE.pageX) - window.scrollX; + var pageY = (isTouch ? origE.touches[0].pageY : origE.pageY) - window.scrollY; + + activeCommandI = undefined; + + var dx = pageX - offset.left - ctrx; + var dy = pageY - offset.top - ctry; + + if (dx === 0) { + dx = 0.01; + } + + var d = Math.sqrt(dx * dx + dy * dy); + var cosTheta = (dy * dy - d * d - dx * dx) / (-2 * d * dx); + var theta = Math.acos(cosTheta); + + if (d < rs + options.spotlightPadding) { + queueDrawBg(); + return; + } + + queueDrawBg(); + + var rx = dx * r / d; + var ry = dy * r / d; + + if (dy > 0) { + theta = Math.PI + Math.abs(theta - Math.PI); + } + + var dtheta = 2 * Math.PI / commands.length; + var theta1 = Math.PI / 2; + var theta2 = theta1 + dtheta; + + for (var i = 0; i < commands.length; i++) { + var command = commands[i]; + + var inThisCommand = theta1 <= theta && theta <= theta2 || theta1 <= theta + 2 * Math.PI && theta + 2 * Math.PI <= theta2; + + if (command.disabled === true || command.enabled === false) { + inThisCommand = false; + } + + if (inThisCommand) { + activeCommandI = i; + break; + } + + theta1 += dtheta; + theta2 += dtheta; + } + + queueDrawCommands(rx, ry, theta); + }).on('tapdrag', dragHandler).on('cxttapend tapend', function () { + parent.style.display = 'none'; + + if (activeCommandI !== undefined) { + var select = commands[activeCommandI].select; + + if (select) { + select.apply(target, [target, gestureStartEvent]); + activeCommandI = undefined; + } + } + + inGesture = false; + + restoreGestures(); + }); + } + + function removeEventListeners() { + var handlers = data.handlers; + + for (var i = 0; i < handlers.length; i++) { + var h = handlers[i]; + + if (h.selector === 'core') { + cy.off(h.events, h.fn); + } else { + cy.off(h.events, h.selector, h.fn); + } + } + + window.removeEventListener('resize', updatePixelRatio); + } + + function destroyInstance() { + redrawing = false; + + removeEventListeners(); + + wrapper.remove(); + } + + addEventListeners(); + + return { + destroy: function destroy() { + destroyInstance(); + } + }; +}; + +module.exports = cxtmenu; + +/***/ }), +/* 1 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +// Simple, internal Object.assign() polyfill for options objects etc. + +module.exports = Object.assign != null ? Object.assign.bind(Object) : function (tgt) { + for (var _len = arguments.length, srcs = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + srcs[_key - 1] = arguments[_key]; + } + + srcs.filter(function (src) { + return src != null; + }).forEach(function (src) { + Object.keys(src).forEach(function (k) { + return tgt[k] = src[k]; + }); + }); + + return tgt; +}; + +/***/ }), +/* 2 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var defaults = { + menuRadius: 100, // the radius of the circular menu in pixels + selector: 'node', // elements matching this Cytoscape.js selector will trigger cxtmenus + commands: [// an array of commands to list in the menu or a function that returns the array + /* + { // example command + fillColor: 'rgba(200, 200, 200, 0.75)', // optional: custom background color for item + content: 'a command name' // html/text content to be displayed in the menu + contentStyle: {}, // css key:value pairs to set the command's css in js if you want + select: function(ele){ // a function to execute when the command is selected + console.log( ele.id() ) // `ele` holds the reference to the active element + }, + enabled: true // whether the command is selectable + } + */ + ], // function( ele ){ return [ /*...*/ ] }, // example function for commands + fillColor: 'rgba(0, 0, 0, 0.75)', // the background colour of the menu + activeFillColor: 'rgba(1, 105, 217, 0.75)', // the colour used to indicate the selected command + activePadding: 20, // additional size in pixels for the active command + indicatorSize: 24, // the size in pixels of the pointer to the active command + separatorWidth: 3, // the empty spacing in pixels between successive commands + spotlightPadding: 4, // extra spacing in pixels between the element and the spotlight + minSpotlightRadius: 24, // the minimum radius in pixels of the spotlight + maxSpotlightRadius: 38, // the maximum radius in pixels of the spotlight + openMenuEvents: 'cxttapstart taphold', // space-separated cytoscape events that will open the menu; only `cxttapstart` and/or `taphold` work here + itemColor: 'white', // the colour of text in the command's content + itemTextShadowColor: 'transparent', // the text shadow colour of the command's content + zIndex: 9999, // the z-index of the ui div + atMouse: false // draw menu at mouse position +}; + +module.exports = defaults; + +/***/ }), +/* 3 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var removeEles = function removeEles(query) { + var ancestor = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : document; + + var els = ancestor.querySelectorAll(query); + + for (var i = 0; i < els.length; i++) { + var el = els[i]; + + el.parentNode.removeChild(el); + } +}; + +var setStyles = function setStyles(el, style) { + var props = Object.keys(style); + + for (var i = 0, l = props.length; i < l; i++) { + el.style[props[i]] = style[props[i]]; + } +}; + +var createElement = function createElement(options) { + options = options || {}; + + var el = document.createElement(options.tag || 'div'); + + el.className = options.class || ''; + + if (options.style) { + setStyles(el, options.style); + } + + return el; +}; + +var getPixelRatio = function getPixelRatio() { + return window.devicePixelRatio || 1; +}; + +var getOffset = function getOffset(el) { + var offset = el.getBoundingClientRect(); + + return { + left: offset.left + document.body.scrollLeft + parseFloat(getComputedStyle(document.body)['padding-left']) + parseFloat(getComputedStyle(document.body)['border-left-width']), + top: offset.top + document.body.scrollTop + parseFloat(getComputedStyle(document.body)['padding-top']) + parseFloat(getComputedStyle(document.body)['border-top-width']) + }; +}; + +module.exports = { removeEles: removeEles, setStyles: setStyles, createElement: createElement, getPixelRatio: getPixelRatio, getOffset: getOffset }; + +/***/ }), +/* 4 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var cxtmenu = __webpack_require__(0); + +// registers the extension on a cytoscape lib ref +var register = function register(cytoscape) { + if (!cytoscape) { + return; + } // can't register if cytoscape unspecified + + cytoscape('core', 'cxtmenu', cxtmenu); // register with cytoscape.js +}; + +if (typeof cytoscape !== 'undefined') { + // expose to global cytoscape (i.e. window.cytoscape) + register(cytoscape); +} + +module.exports = register; + +/***/ }) +/******/ ]); +}); \ No newline at end of file diff --git a/01_Code/physical_computing_interface/lib/cytoscape-cxtmenu.js b/01_Code/physical_computing_interface/lib/cytoscape-cxtmenu.js new file mode 100644 index 0000000000000000000000000000000000000000..4294ea67bfd92cadb71705056492661cfbb8da86 --- /dev/null +++ b/01_Code/physical_computing_interface/lib/cytoscape-cxtmenu.js @@ -0,0 +1,795 @@ +(function webpackUniversalModuleDefinition(root, factory) { + if(typeof exports === 'object' && typeof module === 'object') + module.exports = factory(); + else if(typeof define === 'function' && define.amd) + define([], factory); + else if(typeof exports === 'object') + exports["cytoscapeCxtmenu"] = factory(); + else + root["cytoscapeCxtmenu"] = factory(); +})(this, function() { +return /******/ (function(modules) { // webpackBootstrap +/******/ // The module cache +/******/ var installedModules = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) { +/******/ return installedModules[moduleId].exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ i: moduleId, +/******/ l: false, +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); +/******/ +/******/ // Flag the module as loaded +/******/ module.l = true; +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; +/******/ +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; +/******/ +/******/ // identity function for calling harmony imports with the correct context +/******/ __webpack_require__.i = function(value) { return value; }; +/******/ +/******/ // define getter function for harmony exports +/******/ __webpack_require__.d = function(exports, name, getter) { +/******/ if(!__webpack_require__.o(exports, name)) { +/******/ Object.defineProperty(exports, name, { +/******/ configurable: false, +/******/ enumerable: true, +/******/ get: getter +/******/ }); +/******/ } +/******/ }; +/******/ +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = function(module) { +/******/ var getter = module && module.__esModule ? +/******/ function getDefault() { return module['default']; } : +/******/ function getModuleExports() { return module; }; +/******/ __webpack_require__.d(getter, 'a', getter); +/******/ return getter; +/******/ }; +/******/ +/******/ // Object.prototype.hasOwnProperty.call +/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; +/******/ +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = ""; +/******/ +/******/ // Load entry module and return exports +/******/ return __webpack_require__(__webpack_require__.s = 4); +/******/ }) +/************************************************************************/ +/******/ ([ +/* 0 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var defaults = __webpack_require__(2); +var assign = __webpack_require__(1); + +var _require = __webpack_require__(3), + removeEles = _require.removeEles, + setStyles = _require.setStyles, + createElement = _require.createElement, + getPixelRatio = _require.getPixelRatio, + getOffset = _require.getOffset; + +var cxtmenu = function cxtmenu(params) { + var options = assign({}, defaults, params); + var cy = this; + var container = cy.container(); + var target = void 0; + + var data = { + options: options, + handlers: [], + container: createElement({ class: 'cxtmenu' }) + }; + + var wrapper = data.container; + var parent = createElement(); + var canvas = createElement({ tag: 'canvas' }); + var commands = []; + var c2d = canvas.getContext('2d'); + var r = options.menuRadius; + var containerSize = (r + options.activePadding) * 2; + var activeCommandI = void 0; + var offset = void 0; + + container.insertBefore(wrapper, container.firstChild); + wrapper.appendChild(parent); + parent.appendChild(canvas); + + setStyles(wrapper, { + position: 'absolute', + zIndex: options.zIndex, + userSelect: 'none', + pointerEvents: 'none' // prevent events on menu in modern browsers + }); + + // prevent events on menu in legacy browsers + ['mousedown', 'mousemove', 'mouseup', 'contextmenu'].forEach(function (evt) { + wrapper.addEventListener(evt, function (e) { + e.preventDefault(); + + return false; + }); + }); + + setStyles(parent, { + display: 'none', + width: containerSize + 'px', + height: containerSize + 'px', + position: 'absolute', + zIndex: 1, + marginLeft: -options.activePadding + 'px', + marginTop: -options.activePadding + 'px', + userSelect: 'none' + }); + + canvas.width = containerSize; + canvas.height = containerSize; + + function createMenuItems() { + removeEles('.cxtmenu-item', parent); + var dtheta = 2 * Math.PI / commands.length; + var theta1 = Math.PI / 2; + var theta2 = theta1 + dtheta; + + for (var i = 0; i < commands.length; i++) { + var command = commands[i]; + + var midtheta = (theta1 + theta2) / 2; + var rx1 = 0.66 * r * Math.cos(midtheta); + var ry1 = 0.66 * r * Math.sin(midtheta); + + var item = createElement({ class: 'cxtmenu-item' }); + setStyles(item, { + color: options.itemColor, + cursor: 'default', + display: 'table', + 'text-align': 'center', + //background: 'red', + position: 'absolute', + 'text-shadow': '-1px -1px 2px ' + options.itemTextShadowColor + ', 1px -1px 2px ' + options.itemTextShadowColor + ', -1px 1px 2px ' + options.itemTextShadowColor + ', 1px 1px 1px ' + options.itemTextShadowColor, + left: '50%', + top: '50%', + 'min-height': r * 0.66 + 'px', + width: r * 0.66 + 'px', + height: r * 0.66 + 'px', + marginLeft: rx1 - r * 0.33 + 'px', + marginTop: -ry1 - r * 0.33 + 'px' + }); + + var content = createElement({ class: 'cxtmenu-content' }); + + if (command.content instanceof HTMLElement) { + content.appendChild(command.content); + } else { + content.innerHTML = command.content; + } + + setStyles(content, { + 'width': r * 0.66 + 'px', + 'height': r * 0.66 + 'px', + 'vertical-align': 'middle', + 'display': 'table-cell' + }); + + setStyles(content, command.contentStyle || {}); + + if (command.disabled === true || command.enabled === false) { + content.setAttribute('class', 'cxtmenu-content cxtmenu-disabled'); + } + + parent.appendChild(item); + item.appendChild(content); + + theta1 += dtheta; + theta2 += dtheta; + } + } + + function queueDrawBg(rspotlight) { + redrawQueue.drawBg = [rspotlight]; + } + + function drawBg(rspotlight) { + rspotlight = rspotlight !== undefined ? rspotlight : rs; + + c2d.globalCompositeOperation = 'source-over'; + + c2d.clearRect(0, 0, containerSize, containerSize); + + // draw background items + c2d.fillStyle = options.fillColor; + var dtheta = 2 * Math.PI / commands.length; + var theta1 = Math.PI / 2; + var theta2 = theta1 + dtheta; + + for (var index = 0; index < commands.length; index++) { + var command = commands[index]; + + if (command.fillColor) { + c2d.fillStyle = command.fillColor; + } + c2d.beginPath(); + c2d.moveTo(r + options.activePadding, r + options.activePadding); + c2d.arc(r + options.activePadding, r + options.activePadding, r, 2 * Math.PI - theta1, 2 * Math.PI - theta2, true); + c2d.closePath(); + c2d.fill(); + + theta1 += dtheta; + theta2 += dtheta; + + c2d.fillStyle = options.fillColor; + } + + // draw separators between items + c2d.globalCompositeOperation = 'destination-out'; + c2d.strokeStyle = 'white'; + c2d.lineWidth = options.separatorWidth; + theta1 = Math.PI / 2; + theta2 = theta1 + dtheta; + + for (var i = 0; i < commands.length; i++) { + var rx1 = r * Math.cos(theta1); + var ry1 = r * Math.sin(theta1); + c2d.beginPath(); + c2d.moveTo(r + options.activePadding, r + options.activePadding); + c2d.lineTo(r + options.activePadding + rx1, r + options.activePadding - ry1); + c2d.closePath(); + c2d.stroke(); + + theta1 += dtheta; + theta2 += dtheta; + } + + c2d.fillStyle = 'white'; + c2d.globalCompositeOperation = 'destination-out'; + c2d.beginPath(); + c2d.arc(r + options.activePadding, r + options.activePadding, rspotlight + options.spotlightPadding, 0, Math.PI * 2, true); + c2d.closePath(); + c2d.fill(); + + c2d.globalCompositeOperation = 'source-over'; + } + + function queueDrawCommands(rx, ry, theta) { + redrawQueue.drawCommands = [rx, ry, theta]; + } + + function drawCommands(rx, ry, theta) { + var dtheta = 2 * Math.PI / commands.length; + var theta1 = Math.PI / 2; + var theta2 = theta1 + dtheta; + + theta1 += dtheta * activeCommandI; + theta2 += dtheta * activeCommandI; + + c2d.fillStyle = options.activeFillColor; + c2d.strokeStyle = 'black'; + c2d.lineWidth = 1; + c2d.beginPath(); + c2d.moveTo(r + options.activePadding, r + options.activePadding); + c2d.arc(r + options.activePadding, r + options.activePadding, r + options.activePadding, 2 * Math.PI - theta1, 2 * Math.PI - theta2, true); + c2d.closePath(); + c2d.fill(); + + c2d.fillStyle = 'white'; + c2d.globalCompositeOperation = 'destination-out'; + + var tx = r + options.activePadding + rx / r * (rs + options.spotlightPadding - options.indicatorSize / 4); + var ty = r + options.activePadding + ry / r * (rs + options.spotlightPadding - options.indicatorSize / 4); + var rot = Math.PI / 4 - theta; + + c2d.translate(tx, ty); + c2d.rotate(rot); + + // clear the indicator + c2d.beginPath(); + c2d.fillRect(-options.indicatorSize / 2, -options.indicatorSize / 2, options.indicatorSize, options.indicatorSize); + c2d.closePath(); + c2d.fill(); + + c2d.rotate(-rot); + c2d.translate(-tx, -ty); + + // c2d.setTransform( 1, 0, 0, 1, 0, 0 ); + + // clear the spotlight + c2d.beginPath(); + c2d.arc(r + options.activePadding, r + options.activePadding, rs + options.spotlightPadding, 0, Math.PI * 2, true); + c2d.closePath(); + c2d.fill(); + + c2d.globalCompositeOperation = 'source-over'; + } + + function updatePixelRatio() { + var pxr = getPixelRatio(); + var w = containerSize; + var h = containerSize; + + canvas.width = w * pxr; + canvas.height = h * pxr; + + canvas.style.width = w + 'px'; + canvas.style.height = h + 'px'; + + c2d.setTransform(1, 0, 0, 1, 0, 0); + c2d.scale(pxr, pxr); + } + + var redrawing = true; + var redrawQueue = {}; + + var raf = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.msRequestAnimationFrame || function (fn) { + return setTimeout(fn, 16); + }; + + var redraw = function redraw() { + if (redrawQueue.drawBg) { + drawBg.apply(null, redrawQueue.drawBg); + } + + if (redrawQueue.drawCommands) { + drawCommands.apply(null, redrawQueue.drawCommands); + } + + redrawQueue = {}; + + if (redrawing) { + raf(redraw); + } + }; + + // kick off + updatePixelRatio(); + redraw(); + + var ctrx = void 0, + ctry = void 0, + rs = void 0; + + var bindings = { + on: function on(events, selector, fn) { + + var _fn = fn; + if (selector === 'core') { + _fn = function _fn(e) { + if (e.cyTarget === cy || e.target === cy) { + // only if event target is directly core + return fn.apply(this, [e]); + } + }; + } + + data.handlers.push({ + events: events, + selector: selector, + fn: _fn + }); + + if (selector === 'core') { + cy.on(events, _fn); + } else { + cy.on(events, selector, _fn); + } + + return this; + } + }; + + function addEventListeners() { + var grabbable = void 0; + var inGesture = false; + var dragHandler = void 0; + var zoomEnabled = void 0; + var panEnabled = void 0; + var boxEnabled = void 0; + var gestureStartEvent = void 0; + + var restoreZoom = function restoreZoom() { + if (zoomEnabled) { + cy.userZoomingEnabled(true); + } + }; + + var restoreGrab = function restoreGrab() { + if (grabbable) { + target.grabify(); + } + }; + + var restorePan = function restorePan() { + if (panEnabled) { + cy.userPanningEnabled(true); + } + }; + + var restoreBoxSeln = function restoreBoxSeln() { + if (boxEnabled) { + cy.boxSelectionEnabled(true); + } + }; + + var restoreGestures = function restoreGestures() { + restoreGrab(); + restoreZoom(); + restorePan(); + restoreBoxSeln(); + }; + + window.addEventListener('resize', updatePixelRatio); + + bindings.on('resize', function () { + updatePixelRatio(); + }).on(options.openMenuEvents, options.selector, function (e) { + target = this; // Remember which node the context menu is for + var ele = this; + var isCy = this === cy; + + if (inGesture) { + parent.style.display = 'none'; + + inGesture = false; + + restoreGestures(); + } + + if (typeof options.commands === 'function') { + var res = options.commands(target); + if (res.then) { + res.then(function (_commands) { + commands = _commands; + openMenu(); + }); + } else { + commands = res; + openMenu(); + } + } else { + commands = options.commands; + openMenu(); + } + + function openMenu() { + if (!commands || commands.length === 0) { + return; + } + + zoomEnabled = cy.userZoomingEnabled(); + cy.userZoomingEnabled(false); + + panEnabled = cy.userPanningEnabled(); + cy.userPanningEnabled(false); + + boxEnabled = cy.boxSelectionEnabled(); + cy.boxSelectionEnabled(false); + + grabbable = target.grabbable && target.grabbable(); + if (grabbable) { + target.ungrabify(); + } + + var rp = void 0, + rw = void 0, + rh = void 0; + if (!isCy && ele.isNode() && !ele.isParent() && !options.atMouse) { + rp = ele.renderedPosition(); + rw = ele.renderedWidth(); + rh = ele.renderedHeight(); + } else { + rp = e.renderedPosition || e.cyRenderedPosition; + rw = 1; + rh = 1; + } + + offset = getOffset(container); + + ctrx = rp.x; + ctry = rp.y; + + createMenuItems(); + + setStyles(parent, { + display: 'block', + left: rp.x - r + 'px', + top: rp.y - r + 'px' + }); + + rs = Math.max(rw, rh) / 2; + rs = Math.max(rs, options.minSpotlightRadius); + rs = Math.min(rs, options.maxSpotlightRadius); + + queueDrawBg(); + + activeCommandI = undefined; + + inGesture = true; + gestureStartEvent = e; + } + }).on('cxtdrag tapdrag', options.selector, dragHandler = function dragHandler(e) { + + if (!inGesture) { + return; + } + + var origE = e.originalEvent; + var isTouch = origE.touches && origE.touches.length > 0; + + var pageX = (isTouch ? origE.touches[0].pageX : origE.pageX) - window.scrollX; + var pageY = (isTouch ? origE.touches[0].pageY : origE.pageY) - window.scrollY; + + activeCommandI = undefined; + + var dx = pageX - offset.left - ctrx; + var dy = pageY - offset.top - ctry; + + if (dx === 0) { + dx = 0.01; + } + + var d = Math.sqrt(dx * dx + dy * dy); + var cosTheta = (dy * dy - d * d - dx * dx) / (-2 * d * dx); + var theta = Math.acos(cosTheta); + + if (d < rs + options.spotlightPadding) { + queueDrawBg(); + return; + } + + queueDrawBg(); + + var rx = dx * r / d; + var ry = dy * r / d; + + if (dy > 0) { + theta = Math.PI + Math.abs(theta - Math.PI); + } + + var dtheta = 2 * Math.PI / commands.length; + var theta1 = Math.PI / 2; + var theta2 = theta1 + dtheta; + + for (var i = 0; i < commands.length; i++) { + var command = commands[i]; + + var inThisCommand = theta1 <= theta && theta <= theta2 || theta1 <= theta + 2 * Math.PI && theta + 2 * Math.PI <= theta2; + + if (command.disabled === true || command.enabled === false) { + inThisCommand = false; + } + + if (inThisCommand) { + activeCommandI = i; + break; + } + + theta1 += dtheta; + theta2 += dtheta; + } + + queueDrawCommands(rx, ry, theta); + }).on('tapdrag', dragHandler).on('cxttapend tapend', function () { + parent.style.display = 'none'; + + if (activeCommandI !== undefined) { + var select = commands[activeCommandI].select; + + if (select) { + select.apply(target, [target, gestureStartEvent]); + activeCommandI = undefined; + } + } + + inGesture = false; + + restoreGestures(); + }); + } + + function removeEventListeners() { + var handlers = data.handlers; + + for (var i = 0; i < handlers.length; i++) { + var h = handlers[i]; + + if (h.selector === 'core') { + cy.off(h.events, h.fn); + } else { + cy.off(h.events, h.selector, h.fn); + } + } + + window.removeEventListener('resize', updatePixelRatio); + } + + function destroyInstance() { + redrawing = false; + + removeEventListeners(); + + wrapper.remove(); + } + + addEventListeners(); + + return { + destroy: function destroy() { + destroyInstance(); + } + }; +}; + +module.exports = cxtmenu; + +/***/ }), +/* 1 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +// Simple, internal Object.assign() polyfill for options objects etc. + +module.exports = Object.assign != null ? Object.assign.bind(Object) : function (tgt) { + for (var _len = arguments.length, srcs = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + srcs[_key - 1] = arguments[_key]; + } + + srcs.filter(function (src) { + return src != null; + }).forEach(function (src) { + Object.keys(src).forEach(function (k) { + return tgt[k] = src[k]; + }); + }); + + return tgt; +}; + +/***/ }), +/* 2 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var defaults = { + menuRadius: 100, // the radius of the circular menu in pixels + selector: 'node', // elements matching this Cytoscape.js selector will trigger cxtmenus + commands: [// an array of commands to list in the menu or a function that returns the array + /* + { // example command + fillColor: 'rgba(200, 200, 200, 0.75)', // optional: custom background color for item + content: 'a command name' // html/text content to be displayed in the menu + contentStyle: {}, // css key:value pairs to set the command's css in js if you want + select: function(ele){ // a function to execute when the command is selected + console.log( ele.id() ) // `ele` holds the reference to the active element + }, + enabled: true // whether the command is selectable + } + */ + ], // function( ele ){ return [ /*...*/ ] }, // example function for commands + fillColor: 'rgba(0, 0, 0, 0.75)', // the background colour of the menu + activeFillColor: 'rgba(1, 105, 217, 0.75)', // the colour used to indicate the selected command + activePadding: 20, // additional size in pixels for the active command + indicatorSize: 24, // the size in pixels of the pointer to the active command + separatorWidth: 3, // the empty spacing in pixels between successive commands + spotlightPadding: 4, // extra spacing in pixels between the element and the spotlight + minSpotlightRadius: 24, // the minimum radius in pixels of the spotlight + maxSpotlightRadius: 38, // the maximum radius in pixels of the spotlight + openMenuEvents: 'cxttapstart taphold', // space-separated cytoscape events that will open the menu; only `cxttapstart` and/or `taphold` work here + itemColor: 'white', // the colour of text in the command's content + itemTextShadowColor: 'transparent', // the text shadow colour of the command's content + zIndex: 9999, // the z-index of the ui div + atMouse: false // draw menu at mouse position +}; + +module.exports = defaults; + +/***/ }), +/* 3 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var removeEles = function removeEles(query) { + var ancestor = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : document; + + var els = ancestor.querySelectorAll(query); + + for (var i = 0; i < els.length; i++) { + var el = els[i]; + + el.parentNode.removeChild(el); + } +}; + +var setStyles = function setStyles(el, style) { + var props = Object.keys(style); + + for (var i = 0, l = props.length; i < l; i++) { + el.style[props[i]] = style[props[i]]; + } +}; + +var createElement = function createElement(options) { + options = options || {}; + + var el = document.createElement(options.tag || 'div'); + + el.className = options.class || ''; + + if (options.style) { + setStyles(el, options.style); + } + + return el; +}; + +var getPixelRatio = function getPixelRatio() { + return window.devicePixelRatio || 1; +}; + +var getOffset = function getOffset(el) { + var offset = el.getBoundingClientRect(); + + return { + left: offset.left + document.body.scrollLeft + parseFloat(getComputedStyle(document.body)['padding-left']) + parseFloat(getComputedStyle(document.body)['border-left-width']), + top: offset.top + document.body.scrollTop + parseFloat(getComputedStyle(document.body)['padding-top']) + parseFloat(getComputedStyle(document.body)['border-top-width']) + }; +}; + +module.exports = { removeEles: removeEles, setStyles: setStyles, createElement: createElement, getPixelRatio: getPixelRatio, getOffset: getOffset }; + +/***/ }), +/* 4 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var cxtmenu = __webpack_require__(0); + +// registers the extension on a cytoscape lib ref +var register = function register(cytoscape) { + if (!cytoscape) { + return; + } // can't register if cytoscape unspecified + + cytoscape('core', 'cxtmenu', cxtmenu); // register with cytoscape.js +}; + +if (typeof cytoscape !== 'undefined') { + // expose to global cytoscape (i.e. window.cytoscape) + register(cytoscape); +} + +module.exports = register; + +/***/ }) +/******/ ]); +}); \ No newline at end of file diff --git a/01_Code/physical_computing_interface/threejs/grid.js b/01_Code/physical_computing_interface/threejs/grid.js index 2b93828e34d0e739270eaed39f82b74e16fa417b..84d94d488fa03121a6a0334f7d7c05d45b570294 100644 --- a/01_Code/physical_computing_interface/threejs/grid.js +++ b/01_Code/physical_computing_interface/threejs/grid.js @@ -29,6 +29,79 @@ function threejs(GLOBALS,utils,containerName,container1Name){ this.grid=GLOBALS.grid; this.cubicGrid=GLOBALS.gridPresets.Cubic; this.occupancy=GLOBALS.occupancy; + this.selectedNodeID; + this.menu; + + var color1= "#ffffff"; //white + var color11= "#ffffff8c"; //white transparent + var color2= "#020227"; //dark blue + var color3= "#1c5c61"; //teal + var color33= "#1c5c618c"; //teal transparent + var color4= "#fa6e70"; //red/orange + var color44= "#fa6e708c"; //red/orange + var color5="#380152"; //purple + var color6="#696767"; //grey + + this.cy = cytoscape({ + container: document.getElementById(container1Name), + + ready: function(){ + }, + style: [ + ], + + elements: { + nodes: [ + ], + edges: [ + ] + }, + + }); + + this.cxtdefaults = { + selector: 'core',//'node, edge', + menuRadius: 50, + fillColor: color11, // the background colour of the menu + activeFillColor: color44, // the colour used to indicate the selected command + // activePadding: 20, // additional size in pixels for the active command + indicatorSize: 20, // the size in pixels of the pointer to the active command + // separatorWidth: 3, // the empty spacing in pixels between successive commands + spotlightPadding: 4, // extra spacing in pixels between the element and the spotlight + minSpotlightRadius: 15, // the minimum radius in pixels of the spotlight + maxSpotlightRadius: 10, // the maximum radius in pixels of the spotlight + // openMenuEvents: 'cxttapstart taphold', // space-separated cytoscape events that will open the menu; only `cxttapstart` and/or `taphold` work here + itemColor: color6, // the colour of text in the command's content + // itemTextShadowColor: 'transparent', // the text shadow colour of the command's content + zIndex: 2*9999, // the z-index of the ui div + // atMouse: false // draw menu at mouse position + commands: [ + { + content: '<span class="fa fa-play fa-1x"></span>', + select: function(){ + console.log( "play");//todo move to globals + } + }, + + { + content: '<span class="fa fa-trash fa-1x"></span>', + select: function(){ + GLOBALS.removeNode(three.selectedNodeID.x,three.selectedNodeID.y,three.selectedNodeID.z); + + }, + // enabled: true + }, + + { + // content: 'Select', + content: '<span class="fa fa-mouse-pointer fa-1x"></span>', + select: function(){ + console.log( "Select");//todo move to globals + } + } + ] + }; + // this.init(); } @@ -67,11 +140,7 @@ threejs.prototype.init=function() { this.raycaster = new THREE.Raycaster(); this.mouse = new THREE.Vector2(); - // var geometry = new THREE.PlaneBufferGeometry( 1000, 1000 ); - // geometry.rotateX( - Math.PI / 2 ); - // plane = new THREE.Mesh( geometry, new THREE.MeshBasicMaterial( { visible: false } ) ); - // scene.add( plane ); - // objects.push( plane ); + this.helperPosition = new Float32Array( 1 * 3 ); var c = new THREE.Color( this.color1 ); @@ -110,7 +179,7 @@ threejs.prototype.init=function() { this.container.addEventListener( 'mousemove', onDocumentMouseMoveThree, false ); this.container.addEventListener( 'mousedown', onDocumentMouseDownThree, false ); // window.addEventListener( 'keydown', onDocumentKeyDown, false ); - // window.addEventListener( 'keyup', onDocumentKeyUp, false ); + window.addEventListener( 'mouseup', onDocumentKeyUpThree, false ); // window.addEventListener( 'mouseup', onWindowResizeThree, false ); @@ -216,23 +285,6 @@ threejs.prototype.buildHelperSnap=function(grid,x,y,z){ this.plane.position.y=p_y; this.plane.position.z=p_z; - // plane.scale.x=grid.xScale*0.95; - // plane.scale.z=grid.yScale*0.95; - - // plane.position.x=0.0; - // plane.position.y=0.0; - // plane.position.z=0.0; - - // plane.position.x+=grid.voxelSpacing*grid.xScale*(x ); - // plane.position.z+=grid.voxelSpacing*grid.yScale*(y ); - // plane.position.y+=grid.voxelSpacing*grid.zScale*(z ); - - // if(y%2!=0){ - // plane.position.x+=grid.voxelSpacing*grid.xScale*(grid.xLineOffset); - // plane.position.z+=grid.voxelSpacing*grid.yScale*(grid.yLineOffset); - - // } - // plane.position.y-=grid.voxelSpacing*grid.zScale/2.0; this.plane.name="p["+parseInt(x) +","+parseInt(y) +","+parseInt(z) +"]"; this.helperPosition[0]=this.plane.position.x; @@ -285,7 +337,11 @@ threejs.prototype.helperAt=function(x,y,z){ }; threejs.prototype.updateHelperMeshesAfterRemove=function(grid,x,y,z){ - this.buildHelperSnap(grid,x,y,z); + // this.buildHelperSnap(grid,x,y,z); + this.occupancy[x][y][z]=false; + if(z<1){ + this.buildHelperSnap(grid,x,y,z); + } var list=this.utils.getNeighborsList(grid,x,y,z); //TODO ENCLOSE for(var i=0;i<list.length;i++){ @@ -295,14 +351,20 @@ threejs.prototype.updateHelperMeshesAfterRemove=function(grid,x,y,z){ // buildHelperSnap(grid,x1,y1,z1); var name='[' +x1+"," +y1+","+z1+']'; var object = this.scene.getObjectByName( 'p'+name ); - this.scene.remove( object ); - this.objects.splice( this.objects.indexOf( object ), 1 ); - object = this.scene.getObjectByName( 's'+name ); - this.scene.remove( object ); - this.occupancyHelper[x1][y1][z1]=false; + if(object!==undefined){ + this.scene.remove( object ); + this.objects.splice( this.objects.indexOf( object ), 1 ); + + object = this.scene.getObjectByName( 's'+name ); + this.scene.remove( object ); + this.occupancyHelper[x1][y1][z1]=false; + + } + + } } - var list=this.utils.getNeighborsList(this.cubicGrid,x,y,z); + list=this.utils.getNeighborsList(this.cubicGrid,x,y,z); for(var i=0;i<list.length;i++){ var x1,y1,z1; [x1,y1,z1]=list[i]; @@ -391,13 +453,27 @@ function onDocumentMouseDownThree( event ) { var intersect = intersects1[ 0 ]; var obj=utils.getXYZfromName(intersect.object.name); - GLOBALS.removeNode(obj.x,obj.y,obj.z); + three.selectedNodeID=obj; + three.menu=three.cy.cxtmenu( three.cxtdefaults ); + + + } three.render(); } } +function onDocumentKeyUpThree(event){ + if(event.which==3){ + + if(three.menu!==undefined){ + three.menu.destroy(); + } + } + +} + document.addEventListener('removeNode', function (e) { var name='[' +e.detail.x +"," +e.detail.y+","+e.detail.z+']'; var object = three.scene.getObjectByName( name ); @@ -415,6 +491,7 @@ document.addEventListener('addNode', function (e) { var object = three.scene.getObjectByName( 'p'+name ); three.scene.remove( object ); three.objects.splice( three.objects.indexOf( object ), 1 ); + object = three.scene.getObjectByName( 's'+name ); three.scene.remove( object ); three.occupancyHelper[e.detail.x][e.detail.y][e.detail.z]=false;