diff --git a/README.md b/README.md index 07dcdda1640cebe9bf5f49c3948efdf16fb211bd..df2ba7a1e8a6fa71a64ae9533fee6ece1ee0ce50 100644 --- a/README.md +++ b/README.md @@ -15,9 +15,15 @@ This project serves the developement environment / api we use to write and repre ## For MW - - top menu bar instructions - rick click on menu bar to delete module + - walk program units and change + - what program units do we want? + - try demo machine setup ... want flow control, + - jogging, etc ... keydown units ? + + - documentation + - upd8ts to modules: - rename inout to jsunit - buttons get onClick evt @@ -25,6 +31,11 @@ This project serves the developement environment / api we use to write and repre - as you test, to track, - weird state types solution: arrays, numbers, buttons, etc ? + - UI desires + - off-screen divs get pointers-to so that we don't get lost + - 'h' or something to zoom-to-extents + - highlight wires + - GIFS - load a program - drag around @@ -35,39 +46,10 @@ This project serves the developement environment / api we use to write and repre - rm modules - change settings - - *don't forget* - - onload, load state... - - when hooking back to server, server.emitChange(key) ... from writeStateObject - - - this spiral - - entire programs read into UI - - hook sever-and-back - - for event hookup - - for module add - - for state push-down - - re-hook state push-down - - can req and add to program new modules - - can req to load new program - - can req to save this program - - next spiral - programs come in chunk-wise and get placed - programs are modules are heirarchical - - fundament - - the basic unit is a .js file having inputs, outputs, and state objects - - we can compose programs of these modules, being collections of them with connections - - we can represent these programs heirarchically, or in a flat manner ... heirarchy just requires an extra wrap, we do it later - - - load / save programs (req. prgmem representation) - - rewrite ui & transfers to use this rep. - - UI - - title bar descr. how to operate - - 'L' for load, 'M' for new module, type for module search ? - - right-click delete / copy etc - - evt line highlight on hover - - hover display type - ## WRT Representations OK diff --git a/client/client.js b/client/client.js index 84d0f845f5ef15076597fc85900393ece6328b83..fa9323d9c22bbc6850c36cf58a77fab1bfbffd83 100644 --- a/client/client.js +++ b/client/client.js @@ -21,10 +21,11 @@ CLIENT GLOBALS --------------------------------------------------- */ var sckt = {} -var lastPos = { x: 10, y: 10 } +var lastPos = { x: 10, y: 30 } // drawing / div-ing var wrapper = {} +var nav = {} /* @@ -50,6 +51,8 @@ window.onload = function() { wrapper.id = 'wrapper' document.body.append(wrapper) + nav = document.getElementById('nav') + const socket = new WebSocket('ws://localhost:8081') socket.onopen = function(evt) { @@ -121,7 +124,7 @@ function socketRecv(evt) { case 'put module change': console.log('RECV MODULE CHANGE') heapSendsModuleChange(data) - break + break case 'put state change': console.log('RECV STATE CHANGE') heapSendsStateChange(data) @@ -183,22 +186,22 @@ function heapSendsNewModule(mdl) { // containing references to those DOM objects -function heapSendsModuleChange(data){ +function heapSendsModuleChange(data) { console.log(data) // data should be rep of changed module var rep = program.modules[data.description.id] // we want a general case, but for now we know we're looking for // new event hookups or new state items - for(key in rep.outputs){ + for (key in rep.outputs) { var output = rep.outputs[key] - if(output.calls.length !== data.outputs[key].calls.length){ + if (output.calls.length !== data.outputs[key].calls.length) { rep.outputs = data.outputs } } // ok - for(key in rep.state){ + for (key in rep.state) { var stateItem = rep.state[key] - if(stateItem != data.state[key]){ + if (stateItem != data.state[key]) { stateItem = data.state[key] rep.ui.state[key].value = data.state[key] } @@ -211,9 +214,9 @@ function heapSendsModuleChange(data){ // update state from server to UI function heapSendsStateChange(data) { console.log('HEAP SENDS CHANGE STATE IN MODULE', data) - var rep = program.modules[data.id] - rep.state[data.key] = data.val - rep.ui.state[data.key].value = data.val + var rep = program.modules[data.id] + rep.state[data.key] = data.val + rep.ui.state[data.key].value = data.val } /* @@ -226,7 +229,7 @@ UI -> HEAP --------------------------------------------------- function putState(rep, key) { var data = { id: rep.description.id, - key: key, + key: key, val: rep.state[key] } socketSend('put state change', data) @@ -326,12 +329,107 @@ UI EVENTS --------------------------------------------------------------------- */ +// drag / pan etc + +document.body.style.overflow = 'hidden' +document.body.style.transform = 'scale(1) translate(0px, 0px)' +document.body.style.transformOrigin = '0px 0px' +// s/o @ Neil +function getCurrentTransform() { + // a string + var transform = document.body.style.transform + + var index = transform.indexOf('scale') + var left = transform.indexOf('(', index) + var right = transform.indexOf(')', index) + var s = parseFloat(transform.slice(left + 1, right)) + var index = transform.indexOf('translate') + var left = transform.indexOf('(', index) + var right = transform.indexOf('px', left) + var tx = parseFloat(transform.slice(left + 1, right)) + var left = transform.indexOf(',', right) + var right = transform.indexOf('px', left) + var ty = parseFloat(transform.slice(left + 1, right)) + var origin = document.body.style.transformOrigin + var pxx = origin.indexOf('px') + var ox = parseFloat(origin.slice(0, pxx)) + var pxy = origin.indexOf('px', pxx + 2) + var oy = parseFloat(origin.slice(pxx + 2, pxy)) + + return ({ + s: s, + tx: tx, + ty: ty, + ox: ox, + oy: oy + }) +} + +function elementIsNotModule(element) { + if ((element.tagName == 'HTML') || (element.tagName == 'BODY') || (element.tagName == 'svg')) { + return true + } else { + return false + } +} + +onwheel = function(evt) { + var el = document.elementFromPoint(evt.pageX, evt.pageY) + if (elementIsNotModule(el)) { + var cT = getCurrentTransform() + evt.preventDefault() + evt.stopPropagation() + if (evt.deltaY > 0) { + var scale = 1.05 * cT.s + } else { + var scale = 0.95 * cT.s + } + var tx = cT.tx + (evt.pageX - cT.ox) * (1 - 1 / cT.s) + var ty = cT.ty + (evt.pageY - cT.oy) * (1 - 1 / cT.s) + + // body + document.body.style.transform = `scale(${scale}) translate(${tx}px,${ty}px)` + document.body.style.transformOrigin = `${evt.pageX}px ${evt.pageY}px` + + // opposite for nav + nav.style.transformOrigin = `${evt.pageX}px ${evt.pageY}px` + nav.style.transform = `scale(${1/scale}) translate(${-tx*scale}px,${-ty*scale}px)` + } +} + +onmousedown = function(evt) { + var el = document.elementFromPoint(evt.pageX, evt.pageY) + if (elementIsNotModule(el)) { + window.addEventListener('mousemove', mouseMoveDragListener) + window.addEventListener('mouseup', mouseUpDragListener) + } +} + +function mouseMoveDragListener(evt) { + evt.preventDefault() + evt.stopPropagation() + var cT = getCurrentTransform() + var dx = evt.movementX + var dy = evt.movementY + var tx = cT.tx + dx / cT.s + var ty = cT.ty + dy / cT.s + + // for body + document.body.style.transform = `scale(${cT.s}) translate(${tx}px,${ty}px)` + + // opposite for nav + nav.style.transform = `scale(${1/cT.s}) translate(${-tx*cT.s}px,${-ty*cT.s}px)` +} + +function mouseUpDragListener(evt) { + window.removeEventListener('mousemove', mouseMoveDragListener) + window.removeEventListener('mouseup', mouseUpDragListener) +} + // get json menu item and render // and ask for module at /obj/key oncontextmenu = function(evt) { if (sckt) { - lastPos.x = evt.pageX - lastPos.y = evt.pageY socketSend('get module menu', '') } else { // socket brkn, reload page @@ -341,17 +439,17 @@ oncontextmenu = function(evt) { return false } -document.onmousemove = function(evt){ - lastPos.x = evt.pageX - lastPos.y = evt.pageY +onmousemove = function(evt){ + var cT = getCurrentTransform() + lastPos.x = cT.ox - cT.tx + (evt.pageX - cT.ox)/cT.s + lastPos.y = cT.oy - cT.ty + (evt.pageY - cT.oy)/cT.s } -document.onkeydown = function(evt){ - console.log(evt) - switch(evt.key){ +document.onkeydown = function(evt) { + switch (evt.key) { case 'Escape': location.reload() - break + break case 's': // get path ? var path = prompt("path? starting at atkapi/programs/") @@ -359,12 +457,12 @@ document.onkeydown = function(evt){ break case 'l': socketSend('get program menu', '') - break + break case 'm': socketSend('get module menu', '') - break + break default: - break + break } } @@ -373,6 +471,7 @@ document.onkeydown = function(evt){ function heapSendsModuleMenu(tree) { var menuDom = document.createElement('div') menuDom.id = 'moduleMenu' + console.log(lastPos) menuDom.style.left = lastPos.x + 'px' menuDom.style.top = lastPos.y + 'px' for (key in tree) { @@ -410,23 +509,23 @@ function heapSendsProgramMenu(tree) { menuDom.id = 'programMenu' menuDom.style.left = lastPos.x + 'px' menuDom.style.top = lastPos.y + 'px' - for(key in tree){ + for (key in tree) { var li = document.createElement('li') var path = tree[key].path li.innerHTML = key.toString() - li.id = path - li.addEventListener('click', function(evt){ + li.id = path + li.addEventListener('click', function(evt) { var data = this.id socketSend('load program', data) wrapper.removeChild(document.getElementById('programMenu')) }) menuDom.appendChild(li) } - wrapper.append(menuDom) + wrapper.append(menuDom) - function rmListener(evt){ - var findMenu = document.getElementById('programMenu') - if(findMenu !== null && findMenu.id == 'programMenu'){ + function rmListener(evt) { + var findMenu = document.getElementById('programMenu') + if (findMenu !== null && findMenu.id == 'programMenu') { wrapper.removeChild(findMenu) } // rm this listner... @@ -434,4 +533,4 @@ function heapSendsProgramMenu(tree) { } document.addEventListener('click', rmListener) -} +} \ No newline at end of file diff --git a/client/divtools.js b/client/divtools.js index 337a85cf5a4257bf169b8816b462f055be446479..ee000c89689232614b3ffd97b2a155fc348bec5f 100644 --- a/client/divtools.js +++ b/client/divtools.js @@ -1,6 +1,5 @@ // writing representations - function addRepToView(rep) { // a div to locate it var domElem = document.createElement('div') @@ -85,21 +84,25 @@ function addRepToView(rep) { offsetX = evt.clientX - domElem.getBoundingClientRect().left offsetY = evt.clientY - domElem.getBoundingClientRect().top - function domElemMouseMove(mv) { - domElem.style.left = mv.pageX - offsetX + 'px' - domElem.style.top = mv.pageY - offsetY + 'px' + function domElemMouseMove(evt) { + evt.preventDefault() + evt.stopPropagation() + var cT = getCurrentTransform() + domElem.style.left = parseFloat(domElem.style.left) + evt.movementX/cT.s + 'px' + domElem.style.top = parseFloat(domElem.style.top) + evt.movementY/cT.s + 'px' redrawLinks() } - document.addEventListener('mousemove', domElemMouseMove) - - title.onmouseup = function() { + function rmOnMouseUp(evt){ rep.description.position.left = parseInt(domElem.style.left, 10) rep.description.position.top = parseInt(domElem.style.top, 10) putUi(rep) document.removeEventListener('mousemove', domElemMouseMove) - title.onmouseup = null + document.removeEventListener('mouseup', rmOnMouseUp) } + + document.addEventListener('mousemove', domElemMouseMove) + document.addEventListener('mouseup', rmOnMouseUp) } wrapper.appendChild(rep.ui.domElem) diff --git a/client/index.html b/client/index.html index 3e1055e3aa21fb877a2f9386dfc3faa06a5bb46f..5008fd782a7e5fbf20d24a38693b0c0207023404 100644 --- a/client/index.html +++ b/client/index.html @@ -11,6 +11,9 @@ <script type="text/javascript" src="dummies.js"></script> --> <script type="text/javascript" src="divtools.js"></script> <script type="text/javascript" src="client.js"></script> + <div id = "nav"> + <p>'l' for load program, 's' for save program, right-click or 'm' for add module menu</p> + </div> </body> </html> \ No newline at end of file diff --git a/programs/default.json b/programs/default.json index 251b0a4023275c536b03576f62f39469500a647d..1be7d018319dd6940d486a6232f86169bd3ebc37 100644 --- a/programs/default.json +++ b/programs/default.json @@ -12,7 +12,7 @@ "path": "./src/util/gate.js", "position": { "left": 10, - "top": 10 + "top": 30 } }, "inputs": {