diff --git a/panther2d.js b/panther2d.js index 76c1e18dec3d816fbd1bec86a8927e92159c6e1b..b1fb6a23e5459327b3b657699a1a2fbf4af8ea71 100644 --- a/panther2d.js +++ b/panther2d.js @@ -31,6 +31,17 @@ const machine = machineCaseSensitive.toLowerCase(); let rulerStart = false; let cx, cy; + const ruler = document.location.search.indexOf('ruler=')>-1? document.location.search.split('ruler=')[1].split('&')[0].split(','): document.location.search.indexOf('ruler')>-1; + let rulerEvent = 'contextmenu'; + if (typeof ruler == "object") { + const index = ruler.indexOf('left'); + if (index>-1) { + rulerEvent = 'mousedown'; + ruler.splice(index, 1); + } + if (ruler.length==0) $('#bm').hide(); + } + else $('#bm').hide(); function setTick(x, y, cx, cy, dist, distPixel, n, pow10=1000) { const tx1 = cx + (x - cx) / dist * pow10 * n; @@ -44,7 +55,34 @@ $('#tickLabel'+n).attr('x', 2*tx2-tx1); $('#tickLabel'+n).attr('y', 2*ty2-ty1); $('#tickLabel'+n).html(x==cx || distPixel<220? '': pow10 * n / 1000); - } + } + // https://stackoverflow.com/questions/849211/shortest-distance-between-a-point-and-a-line-segment + function pDistance(x, y, x1, y1, x2, y2) { + var A = x - x1; + var B = y - y1; + var C = x2 - x1; + var D = y2 - y1; + var dot = A * C + B * D; + var len_sq = C * C + D * D; + var param = -1; + if (len_sq != 0) param = dot / len_sq; //in case of 0 length line + var xx, yy; + if (param < 0) { + xx = x1; + yy = y1; + } + else if (param > 1) { + xx = x2; + yy = y2; + } + else { + xx = x1 + param * C; + yy = y1 + param * D; + } + var dx = x - xx; + var dy = y - yy; + return {dist: Math.sqrt(dx * dx + dy * dy), x: xx, y: yy}; + } function getCursorPosition(main, event) { const rect = main.getBoundingClientRect(); const x = event.clientX - rect.left; @@ -52,15 +90,63 @@ const distPixel = Math.sqrt(Math.pow(x - cx, 2) + Math.pow(y - cy, 2)); const dist = distPixel / panZoomPanther.getSizes().realZoom; if (rulerStart) $('#stright').val(Math.round(dist)/1000); - const alpha = (Math.atan2(y-cy, x-cx) * 180) / Math.PI; - $('#sr').val(Math.round((x - panZoomPanther.getPan().x)/panZoomPanther.getSizes().realZoom)/1000+' '+(-Math.round((y - panZoomPanther.getPan().y)/panZoomPanther.getSizes().realZoom)/1000) + ' a: ' + alpha); + // const alpha = (Math.atan2(y-cy, x-cx) * 180) / Math.PI; + $('#pos').val(Math.round((x - panZoomPanther.getPan().x)/panZoomPanther.getSizes().realZoom)/1000+' '+(-Math.round((y - panZoomPanther.getPan().y)/panZoomPanther.getSizes().realZoom)/1000)); if (rulerStart) { + // stright ruler const pow10 = Math.pow(10, Math.round(Math.log10(dist))-1); $('#rulerLine').attr('x2', x); $('#rulerLine').attr('y2', y); for (let i=1; i<32; i++) { if (i<dist/pow10 && distPixel>50) setTick(x, y, cx, cy, dist, distPixel, i, pow10); else setTick(x, y, x, y, dist, distPixel, i, pow10); } + const vertex = []; + let minDistance = Infinity; + let dindex = -1; + let mincDistance = Infinity; + let dcindex = -1; + // beam pattern ruler + if (typeof ruler == "object" && typeof lattice[ruler[0]] == "object") { + let d = 0; + const x1 = (x - panZoomPanther.getPan().x) / panZoomPanther.getSizes().realZoom; + const y1 = (y - panZoomPanther.getPan().y) / panZoomPanther.getSizes().realZoom; + const xc1 = (cx - panZoomPanther.getPan().x) / panZoomPanther.getSizes().realZoom; + const yc1 = (cy - panZoomPanther.getPan().y) / panZoomPanther.getSizes().realZoom; + for (let i=0; i < lattice[ruler[0]].sections.length; i++) { + j = (i+1) % lattice[ruler[0]].sections.length; + vertex[i] = lattice[ruler[0]].sections[i].start; + // d = Math.sqrt(Math.pow(vertex[i].x - x, 2) + Math.pow(vertex[i].z - y, 2)); + d = pDistance(x1, y1, vertex[i].x, vertex[i].z, lattice[ruler[0]].sections[j].start.x, lattice[ruler[0]].sections[j].start.z); + if (minDistance > d.dist) { minDistance = d.dist; dindex = i; p = d;} + d = pDistance(xc1, yc1, vertex[i].x, vertex[i].z, lattice[ruler[0]].sections[j].start.x, lattice[ruler[0]].sections[j].start.z); + if (mincDistance > d.dist) { mincDistance = d.dist; dcindex = i; pc = d;} + } + let pathd = 'M '+(pc.x*panZoomPanther.getSizes().realZoom + panZoomPanther.getPan().x)+' '+(pc.y * panZoomPanther.getSizes().realZoom + panZoomPanther.getPan().y)+' '; + k = dcindex; + j = (k+1) % lattice[ruler[0]].sections.length; + let dd = Math.sqrt(Math.pow(pc.x-lattice[ruler[0]].sections[j].start.x, 2) + Math.pow(pc.y-lattice[ruler[0]].sections[j].start.z, 2)); + if (dcindex == dindex) dd = Math.sqrt(Math.pow(pc.x-p.x, 2) + Math.pow(pc.y-p.y, 2)); + else { + while (k != dindex) { + j = (k+1) % lattice[ruler[0]].sections.length; + if (k != dcindex) dd = dd + Math.sqrt(Math.pow(lattice[ruler[0]].sections[k].start.x-lattice[ruler[0]].sections[j].start.x, 2) + Math.pow(lattice[ruler[0]].sections[k].start.z-lattice[ruler[0]].sections[j].start.z, 2)); + pathd = pathd + 'L '+(lattice[ruler[0]].sections[j].start.x * panZoomPanther.getSizes().realZoom + panZoomPanther.getPan().x)+' '+(lattice[ruler[0]].sections[j].start.z * panZoomPanther.getSizes().realZoom + panZoomPanther.getPan().y)+' '; + k = j; + } + dd = dd + Math.sqrt(Math.pow(p.x-lattice[ruler[0]].sections[dindex].start.x, 2) + Math.pow(p.y-lattice[ruler[0]].sections[dindex].start.z, 2)); + } + $('#bm').val(Math.round(dd)/1000); + pathd = pathd + 'L '+(p.x * panZoomPanther.getSizes().realZoom + panZoomPanther.getPan().x)+' '+(p.y * panZoomPanther.getSizes().realZoom + panZoomPanther.getPan().y); + //<path d="M 10 10 H 90 V 90 H 10 L 10 10"/> + console.log('minDistance', mincDistance, dcindex, pc, minDistance, dindex, p, dd, 'pathd', pathd); + $('#beam').attr('d', pathd); + $('#rulerSide1').attr('x2', pc.x * panZoomPanther.getSizes().realZoom + panZoomPanther.getPan().x); + $('#rulerSide1').attr('y2', pc.y * panZoomPanther.getSizes().realZoom + panZoomPanther.getPan().y); + $('#rulerSide2').attr('x1', x); + $('#rulerSide2').attr('y1', y); + $('#rulerSide2').attr('x2', p.x * panZoomPanther.getSizes().realZoom + panZoomPanther.getPan().x); + $('#rulerSide2').attr('y2', p.y * panZoomPanther.getSizes().realZoom + panZoomPanther.getPan().y); + } } } function clearRuler() { @@ -68,7 +154,17 @@ $('#rulerLine').attr('y1', cy); $('#rulerLine').attr('x2', cx); $('#rulerLine').attr('y2', cy); + $('#rulerSide1').attr('x1', cx); + $('#rulerSide1').attr('y1', cy); + $('#rulerSide1').attr('x2', cx); + $('#rulerSide1').attr('y2', cy); + $('#rulerSide2').attr('x1', cx); + $('#rulerSide2').attr('y1', cy); + $('#rulerSide2').attr('x2', cx); + $('#rulerSide2').attr('y2', cy); $('#stright').val(''); + $('#bm').val(''); + $('#beam').attr('d', ''); for (let i=1; i<32; i++) {setTick(cx, cy, cx, cy, 1, 1, i);} } function initCursorPosition(main, event) { @@ -81,6 +177,9 @@ // appendSvg("circle", {id: 'rulerStart', cx: cx, cy: cy, r:8, style:"display: block", fill:"none", stroke:"red","stroke-width":2}); if ($('#rulerLine').length==0) { appendSvg("line", {id: 'rulerLine', x1: cx, y1: cy, x2: cx, y2: cy, style:"display: block", fill:"none", stroke:"yellow","stroke-width":2}); + appendSvg("path", {d: '', fill: "none", stroke: "limegreen", "stroke-width": 3, id:"beam"}); + appendSvg("line", {id: 'rulerSide1', x1: cx, y1: cy, x2: cx, y2: cy, style:"display: block", fill:"none", stroke:"pink","stroke-width":2}); + appendSvg("line", {id: 'rulerSide2', x1: cx, y1: cy, x2: cx, y2: cy, style:"display: block", fill:"none", stroke:"pink","stroke-width":2}); for (let i=1; i<32; i++) { appendSvg("line", {id: 'tick'+i, x1: cx, y1: cy, x2: cx, y2: cy, style:"display: block", fill:"none", stroke:"yellow","stroke-width":2}); appendSvg("text", {id: 'tickLabel'+i, x: cx, y: cy, fill:"white", stroke:"#eeeeee","stroke-width":1, "font-family":"Arial", "font-size":12, "font-weight":"bold", "text-anchor": "start"}); @@ -103,9 +202,12 @@ if (document.location.search.indexOf('ruler')>-1) { $('#ruler').show(); const main = document.getElementById('main'); - main.addEventListener('mousedown', function(e) { + main.style.cursor = 'crosshair'; + main.addEventListener(rulerEvent, function(e) { + e.preventDefault(); initCursorPosition(main, e); - }); + return false; + }, false); } //https://puma-01.elettra.eu/rchan.php?json&valueOnly&src=srv-tango-srf-01.fcs.elettra.trieste.it:20000/f/access_control/safety/Undulator_access_state -> 5 FEL1, 6 FEL2 @@ -155,10 +257,11 @@ let search = document.location.search.split('machine=')[1].split('&')[0]; document.location = document.location.href.replace('machine='+search, 'machine='+machine);*/ } - function compLink(event) { - console.log('compLink()', event, document.getElementById("compdb").href); - window.open(document.getElementById("compdb").href, '_blank').focus(); - event.stopPropagation(); + function compLink(id) { + console.log('compLink()', id, document.getElementById("compdb").href); + // window.open(document.getElementById("compdb").href, '_blank').focus(); + window.open(id, 'components').focus(); + // event.stopPropagation(); return false; } function searchText(e) { @@ -239,7 +342,7 @@ const res = search.join('&'); document.location = document.location.href.split('?')[0]+(res.length? '?'+res: ''); } - let ujiveStarted = false; + // let ujiveStarted = false; async function subscribeSpeech() { mylog('subscribeSpeech()', 1, 2); let response = await fetch("./speech/talk.php?read&token="+speechToken); @@ -256,8 +359,10 @@ let message = await response.text(); mylog('subscribeSpeech()', message); if (message=='ujive') { - if (!ujiveStarted) window.open('../ujive.php?token='+speechToken, '_blank').focus(); - ujiveStarted = true; + window.open('../ujive.php?token='+speechToken, 'ujive').focus(); + /*if (!ujiveStarted) ujiveWindow = window.open('../ujive.php?token='+speechToken, '_blank').focus(); + setTimeout(ujiveReset, 15000); + ujiveStarted = true;*/ } else { const msg = findComponent(message); @@ -268,7 +373,7 @@ await subscribeSpeech(); } } - + // function ujiveReset() {ujiveStarted = false;} function mylog(...args) { if (document.location.search.indexOf('debug')>-1) $('#debug').val($('#debug').val()+JSON.stringify(args)+'\n'); console.trace.apply(null); @@ -303,12 +408,6 @@ gui.add(params, 'gotoAdmin').name('Admin'); params.goto3D = function() {document.location = './panther.php?machine='+params.machine;}; gui.add(params, 'goto3D').name('3D'); if (lattice.conf && lattice.conf.index) initIndex(lattice); - if (document.location.search.indexOf('ruler=')>-1) { - const ruler = document.location.search.split('ruler=')[1].split('&')[0]; - if (lattice[ruler]) { - - } - } } $('.scale').attr('transform', "scale(2)"); // {$('<div><iframe style="width: 100%;height:250px;" src="../misc/gauge.html?dark&r1only=1&r=100&max=360&throttlingPeriod=50&apply=rotate&val='+0+'"></iframe></div>').insertBefore('.function');} @@ -440,19 +539,27 @@ function openTooltip(event) { if (document.location.search.indexOf('debug')==-1) { const type = this.href? this.href.baseVal.replace('#',''): (this.id.indexOf('BLM')>-1 || this.id.indexOf('BERGOZ')>-1? 'blm': '???'); - mylog('openTooltip()',type, this.id, event, event.clientY); + console.log('openTooltip()',type, this, event, event.clientY); $('#tooltip').css('left', event.clientX+30); $('#tooltip').css('top', event.clientY+30); - document.getElementById('tooltipFrame').src = conf.tooltipApp+'?s='+type.replace('fast', '')+'¶m='+this.id; + document.getElementById('tooltipFrame').src = conf.tooltipApp+'?s='+type.replace('fast', '')+'¶m='+this.id+(typeof this.dataset.embedded == 'undefined'? '': ','+this.dataset.embedded); console.log('openTooltip(event)', type.toLowerCase(), type.toLowerCase().indexOf('beamline')); document.getElementById('tooltip').style.display = 'block'; if (hideTimeout!==false) clearTimeout(hideTimeout); hideTimeout = setTimeout(hideTooltip, 120000); - document.getElementById('compdb').style.display = (type.indexOf('rv')==0 || type.indexOf('rc')==0 || type.indexOf('rid')==0 || type.indexOf('rd')==0 || type.indexOf('rps')==0 || type.indexOf('plc')==0)? 'none': 'block'; const id = evalId(this.id); + let buttons = '<button onClick="compLink(\''+conf.compdb + id+'\')">'+id+'</button> '; + if (typeof this.dataset.embedded != 'undefined') { + const emb = this.dataset.embedded.split(','); + for (let e=0; e<emb.length; e++) { + buttons = buttons + '<button onClick="compLink(\''+evalId(emb[e])+'\')">'+evalId(emb[e])+'</button> '; + } + } + document.getElementById('compdb').innerHTML = buttons; + document.getElementById('compdb').style.display = (type.indexOf('rv')==0 || type.indexOf('rc')==0 || type.indexOf('rid')==0 || type.indexOf('rd')==0 || type.indexOf('rps')==0 || type.indexOf('plc')==0)? 'none': 'block'; if (document.getElementById('compname')) document.getElementById('compname').innerHTML = id; - document.getElementById('compdb').href = conf.compdb + id; - document.getElementById("compdb").addEventListener("click", compLink); + // document.getElementById('compdb').href = conf.compdb + id; + // document.getElementById("compdb").addEventListener("click", compLink); if (type.toLowerCase().indexOf('beamline')>-1) { document.getElementById('compdb').href = 'http://adam.elettra.trieste.it/projects/blcs/beamwatch/'; document.getElementById('compdb').innerHTML = 'search '+this.id+' in ADAM Beamwatch <span id="compname"/>'; @@ -484,7 +591,6 @@ function transformLabel(x, y, beta, labelReverse) { if (typeof labelReverse == 'object') return "translate("+rescale(x)+" "+rescale(y)+") rotate("+(beta+labelReverse[0])+") translate("+labelReverse[1]+" "+labelReverse[2]+")"; return labelReverse==180? "translate("+rescale(x)+" "+rescale(y)+") rotate("+(beta-90)+") translate(1800 100)": - //"translate("+rescale(x)+" "+rescale(y)+") rotate("+(beta+90)+") translate("+(labelReverse? -250: 250)+" "+(labelReverse? 200: 300)+")"; "translate("+rescale(x)+" "+rescale(y)+") rotate("+(beta+90)+") translate("+(labelReverse? -350: 350)+" "+(labelReverse? 100: 200)+")"; } function appendLabel(id, labelclass, display, x, y, beta, labelReverse) { @@ -492,7 +598,7 @@ appendSvg("text", { id: id+'label', class: labelclass, - x:0, y:0, style:"display: "+display, fill:"white", stroke:"#eeeeee","stroke-width":5, "font-family":"Arial", "font-size":100, "font-weight":"bold", + x:0, y:0, style:"display: "+display, fill:"white", stroke:"#eeeeee","stroke-width":5, "font-family":"Arial", "font-size":100, "font-weight":"bold", "text-anchor": (labelReverse? "end": "start"), transform: transformLabel(x, y, beta, labelReverse) }, false, id); @@ -517,6 +623,12 @@ function appendSvg(tagName, attrib, onClickCall=false, text=false, myclass=false) { const elem = document.createElementNS("http://www.w3.org/2000/svg", tagName); if (onClickCall) elem.addEventListener("click", onClickCall, false); + const titelem = document.createElementNS("http://www.w3.org/2000/svg", 'title'); + const embedded = typeof attrib['data-embedded']=='object'? '\n'+attrib['data-embedded'].join(', '): ''; + const aka = typeof attrib['data-aka']=='object' && attrib['data-aka'].length>0? '\naka: '+attrib['data-aka'].join(', '): ''; + const title = document.createTextNode(attrib.id + aka + embedded); + titelem.appendChild(title); + elem.appendChild(titelem); if (text) { const textNode = document.createTextNode(text); elem.appendChild(textNode); @@ -544,6 +656,13 @@ alias.push([id[0],component.embedded[j]]); } } + if (component.alias) { + for (let j=0; j<component.alias.length; j++) { + names.push(component.alias[j]); + shrinkedNames.push(shrinkName(component.alias[j])); + alias.push([id[0],component.alias[j]]); + } + } } } } @@ -553,7 +672,7 @@ const d = Math.sqrt(dx*dx + dy*dy); const beta = 180*Math.atan2(y0-y1, x0-x1)/Math.PI; if (components) for (let i=0; i<components.length; i++) { - const comp = components[i].type;//.replace('booster', ''); + const comp = components[i].type; // .replace('booster', ''); let x = x0+components[i].position/d*dx; let y = y0+components[i].position/d*dy; if (components[i].offset2d) {x += components[i].offset2d[0]; y += components[i].offset2d[1];} @@ -581,17 +700,22 @@ const section = components[i].name.indexOf('_')>-1? components[i].name.split('_')[1].split('.')[0]+' ': ''; const offset = components[i].type == 'beamlineUp'? "-2100 -3500": "0 -200"; const transform = "translate("+rescale(x)+" "+rescale(y)+") rotate("+(beta+180)+") translate("+offset+")"; - const compid = comp + (components[i].lenght > 0 && $('#'+comp+'_'+components[i].lenght)[0]? '_'+components[i].lenght: ''); - appendSvg("use", {href:"#"+compid, id: id[0], name:components[i].name, class: comp+' '+section+facility, style:"cursor: pointer", transform:transform}, openTooltip); + const compid = comp + (components[i].length > 0 && $('#'+comp+'_'+components[i].length)[0]? '_'+components[i].length: ''); + const aka = components[i].alias && components[i].alias.length? components[i].alias: []; + appendSvg("use", {href:"#"+compid, id: id[0], name:components[i].name, "data-embedded":components[i].embedded, "data-aka": aka, class: comp+' '+section+facility, style:"cursor: pointer", transform:transform}, openTooltip); if (components[i].type == 'label' || components[i].type == 'beamlineDown' || components[i].type == 'beamlineUp') appendLabel2(components[i], section+facility, 'none', x, y, beta, components[i].labelReverse); else appendLabel(components[i].name, comp+' label '+section+facility, 'none', x, y, beta, components[i].labelReverse); names.push(id[0]); shrinkedNames.push(shrinkName(id[0])); - if (components[i].embedded) { + + if (typeof components[i].embedded == 'object') { for (let j=0; j<components[i].embedded.length; j++) {names.push(components[i].embedded[j]); alias.push([id[0],components[i].embedded[j]]);} } + if (typeof components[i].alias == 'object') { + for (let j=0; j<components[i].alias.length; j++) {names.push(components[i].alias[j]); alias.push([id[0],components[i].alias[j]]);} + } if (id[1]) {names.push(id[1]); shrinkedNames.push(shrinkName(id[1])); alias.push(id);} if (state) { if (components[i].ps) { @@ -670,11 +794,12 @@ if (i<sections.length-1 && typeof sections[i+1].chamber != 'undefined' && sections[i+1].chamber.type=="wall") wall = true; } if (sections[0].chamber && sections[0].chamber.type=='chamber') d = d + ' Z'; - console.log('sections', sections); + if (facility=='sr') console.log('sections', sections, 'd', d); if (d!='') { if (wall) appendSvg("path", {d: d, fill: "none", stroke: "#990000", "stroke-dasharray": "200 200", "stroke-width": 50, id:"wall"+facility}); else appendSvg("path", {d: d, fill: "none", stroke: "#999999", "stroke-width": 20, id:"chamber"+facility}); } + // bending let j = 0; let i = sections.length - 1; let k = sections.length - 2; @@ -689,14 +814,12 @@ if (sections[i].bending && sections[i].bending.type) { const section = sections[i].bending.name.indexOf('_')>-1? sections[i].bending.name.split('_')[1].split('.')[0]+' ': ''; const comp = sections[i].bending.type.replace('dipolefermi','bending'); - const compid = comp + (sections[i].bending.lenght > 0 && $('#'+comp+'_'+sections[i].bending.lenght)[0]? '_'+sections[i].bending.lenght: ''); + const compid = comp + (sections[i].bending.length > 0 && $('#'+comp+'_'+sections[i].bending.length)[0]? '_'+sections[i].bending.length: ''); appendSvg("use", {href:"#"+compid, id:sections[i].bending.name.replace('.','_'), class: 'bending '+section+facility, style:"cursor: pointer", transform:"translate("+rescale(sections[i].start.x)+" "+rescale(sections[i].start.z)+") rotate("+gamma+") translate(-600 -200)"}, openTooltip); appendLabel(sections[i].bending.name, 'bending '+section+facility, 'block', sections[i].start.x, sections[i].start.z, gamma+180, sections[i].bending.labelReverse); - // appendSvg("text", {id:sections[i].bending.name+'label', class: 'bending '+section+facility, x:0, y:0, fill:"white", stroke:"#888888","stroke-width":10, "font-family":"Arial", "font-size":300, "font-weight":"bold", transform:"translate("+rescale(sections[i].start.x)+" "+rescale(sections[i].start.z)+") rotate("+gamma+") translate(-600 -250)"}, false, sections[i].bending.name); } alpha = beta; appendComponent(sections[i].components, sections[i].start.x, sections[i].start.z, sections[j].start.x, sections[j].start.z, facility); - // if (typeof bpmData != 'undefined') bpmInit(facility); } } $(document).ready(function() { @@ -784,7 +907,7 @@ zoom = newScale; if (newScale>2) $('.label').show(); else $('.label').hide(); if (myPanZoomTimer == null && document.location.search.indexOf('&autoPanZoom')==-1) myPanZoomTimer = setTimeout(myPanZoomDelayed, panZoomTime); - mylog('myZoom', zoom); + // mylog('myZoom', zoom); } /* https://github.com/dagrejs/dagre-d3/issues/202