diff --git a/panther2d.js b/panther2d.js index b1fb6a23e5459327b3b657699a1a2fbf4af8ea71..18f5aae74599192ee2bf1d07525d8941422ddef4 100644 --- a/panther2d.js +++ b/panther2d.js @@ -29,19 +29,20 @@ for (let i=0; i<pa.length; i++) {const p = pa[i].split('='); parameters[p[0]] = p[1];} const machineCaseSensitive = document.location.search.indexOf('machine=')>-1? document.location.search.split('machine=')[1].split('&')[0]: 'elettra'; const machine = machineCaseSensitive.toLowerCase(); - let rulerStart = false; + let measurementStart = 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'); + let measurementType = document.location.search.indexOf('measurement=')>-1? document.location.search.split('measurement=')[1].split('&')[0].split(','): document.location.search.indexOf('measurement')>-1; + let measurementEvent = 'contextmenu'; + if (typeof measurementType == "object") { + const index = measurementType.indexOf('left'); if (index>-1) { - rulerEvent = 'mousedown'; - ruler.splice(index, 1); + measurementEvent = 'mousedown'; + measurementType.splice(index, 1); } - if (ruler.length==0) $('#bm').hide(); + if (measurementType.length==0) $('#bm').hide(); } else $('#bm').hide(); + let measurement = typeof measurementType == "object" || measurementType; function setTick(x, y, cx, cy, dist, distPixel, n, pow10=1000) { const tx1 = cx + (x - cx) / dist * pow10 * n; @@ -89,14 +90,14 @@ const y = event.clientY - rect.top; 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); + if (measurementStart) $('#stright').val(Math.round(dist)/1000); // 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 + if (measurementStart) { + // stright measurement const pow10 = Math.pow(10, Math.round(Math.log10(dist))-1); - $('#rulerLine').attr('x2', x); - $('#rulerLine').attr('y2', y); + $('#measurementLine').attr('x2', x); + $('#measurementLine').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); } @@ -105,109 +106,162 @@ let dindex = -1; let mincDistance = Infinity; let dcindex = -1; - // beam pattern ruler - if (typeof ruler == "object" && typeof lattice[ruler[0]] == "object") { + // beam pattern measurement + if (typeof measurementType == "object" && typeof lattice[measurementType[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; + for (let i=0; i < lattice[measurementType[0]].sections.length; i++) { + j = (i+1) % lattice[measurementType[0]].sections.length; + vertex[i] = lattice[measurementType[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); + d = pDistance(x1, y1, vertex[i].x, vertex[i].z, lattice[measurementType[0]].sections[j].start.x, lattice[measurementType[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); + d = pDistance(xc1, yc1, vertex[i].x, vertex[i].z, lattice[measurementType[0]].sections[j].start.x, lattice[measurementType[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)); + j = (k+1) % lattice[measurementType[0]].sections.length; + let dd = Math.sqrt(Math.pow(pc.x-lattice[measurementType[0]].sections[j].start.x, 2) + Math.pow(pc.y-lattice[measurementType[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)+' '; + j = (k+1) % lattice[measurementType[0]].sections.length; + if (k != dcindex) dd = dd + Math.sqrt(Math.pow(lattice[measurementType[0]].sections[k].start.x-lattice[measurementType[0]].sections[j].start.x, 2) + Math.pow(lattice[measurementType[0]].sections[k].start.z-lattice[measurementType[0]].sections[j].start.z, 2)); + pathd = pathd + 'L '+(lattice[measurementType[0]].sections[j].start.x * panZoomPanther.getSizes().realZoom + panZoomPanther.getPan().x)+' '+(lattice[measurementType[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)); + dd = dd + Math.sqrt(Math.pow(p.x-lattice[measurementType[0]].sections[dindex].start.x, 2) + Math.pow(p.y-lattice[measurementType[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); + $('#measurementSide1').attr('x2', pc.x * panZoomPanther.getSizes().realZoom + panZoomPanther.getPan().x); + $('#measurementSide1').attr('y2', pc.y * panZoomPanther.getSizes().realZoom + panZoomPanther.getPan().y); + $('#measurementSide2').attr('x1', x); + $('#measurementSide2').attr('y1', y); + $('#measurementSide2').attr('x2', p.x * panZoomPanther.getSizes().realZoom + panZoomPanther.getPan().x); + $('#measurementSide2').attr('y2', p.y * panZoomPanther.getSizes().realZoom + panZoomPanther.getPan().y); } } } - function clearRuler() { - $('#rulerLine').attr('x1', cx); - $('#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); + function clearmeasurement() { + $('#measurementLine').attr('x1', cx); + $('#measurementLine').attr('y1', cy); + $('#measurementLine').attr('x2', cx); + $('#measurementLine').attr('y2', cy); + $('#measurementSide1').attr('x1', cx); + $('#measurementSide1').attr('y1', cy); + $('#measurementSide1').attr('x2', cx); + $('#measurementSide1').attr('y2', cy); + $('#measurementSide2').attr('x1', cx); + $('#measurementSide2').attr('y1', cy); + $('#measurementSide2').attr('x2', cx); + $('#measurementSide2').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) { - if (rulerStart) { rulerStart = false; return;} + if (measurementStart) { measurementStart = false; return;} const rect = main.getBoundingClientRect(); cx = event.clientX - rect.left; cy = event.clientY - rect.top; console.log(Math.round(cx) + "," + Math.round(cy) + ","); - if (!rulerStart) { - // 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}); + if (!measurementStart) { + // appendSvg("circle", {id: 'measurementStart', cx: cx, cy: cy, r:8, style:"display: block", fill:"none", stroke:"red","stroke-width":2}); + if ($('#measurementLine').length==0) { + appendSvg("line", {id: 'measurementLine', 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}); + appendSvg("line", {id: 'measurementSide1', x1: cx, y1: cy, x2: cx, y2: cy, style:"display: block", fill:"none", stroke:"pink","stroke-width":2}); + appendSvg("line", {id: 'measurementSide2', 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"}); } } else { - clearRuler(); + clearmeasurement(); } - rulerStart = true; + measurementStart = true; } else { - // $('#rulerStart').attr('cx', cx); $('#rulerStart').attr('cy', cy); - $('#rulerLine').attr('x1', cx); - $('#rulerLine').attr('y1', cy); + // $('#measurementStart').attr('cx', cx); $('#measurementStart').attr('cy', cy); + $('#measurementLine').attr('x1', cx); + $('#measurementLine').attr('y1', cy); } main.addEventListener('mousemove', function(e) { getCursorPosition(main, e); }); } - if (document.location.search.indexOf('ruler')>-1) { - $('#ruler').show(); + if (document.location.search.indexOf('measurement')>-1) { + measurementEnable(); + } + function measurementToggle(enable) { + for (let i=1; i<100; i++) { + if ($('#lil-gui-name-'+i).html()=='measurement') { + if (enable) { + $('#lil-gui-name-'+(i+1)).parent().show(); + $('#lil-gui-name-'+(i+2)).parent().show(); + } + else { + $('#lil-gui-name-'+(i+1)).parent().hide(); + $('#lil-gui-name-'+(i+2)).parent().hide(); + } + break; + } + } + } + function measurementDisable() { + clearmeasurement(); + main.removeEventListener(measurementEvent, measurementListener, false); + main.style.cursor = 'default'; + measurementToggle(false); + } + function measurementListener(e) { + e.preventDefault(); + initCursorPosition(main, e); + return false; + } + function measurementEnable() { + $('#measurement').show(); const main = document.getElementById('main'); main.style.cursor = 'crosshair'; - main.addEventListener(rulerEvent, function(e) { - e.preventDefault(); - initCursorPosition(main, e); - return false; - }, false); + main.addEventListener(measurementEvent, measurementListener, false); + measurementToggle(true); + } + function measurementFacility(msg) { + console.log('measurementFacility()', msg); + if (msg=='left') { + if (measurementEvent != 'mousedown') { + measurementDisable(); + measurementEvent = 'mousedown'; + measurementEnable(); + } + } + else if (msg=='right') { + if (measurementEvent == 'mousedown') { + measurementDisable(); + measurementEvent = 'contextmenu'; + measurementEnable(); + } + } + else if (msg=='') { + measurementDisable(); + measurementType = true; + measurementEnable(); + } + else { + measurementDisable(); + measurementType = [msg]; + measurementEnable(); + } } //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 @@ -281,6 +335,8 @@ gui.add(params, 'vlv').name('vlv & bst').onChange(function() {toggleParam('vlv');}); params.ps = document.location.search.indexOf('ps')>-1; gui.add(params, 'ps').onChange(function() {toggleParam('ps');}); + params.measurement = document.location.search.indexOf('measurement')>-1; + gui.add(params, 'measurement').onChange(function() {toggleParam('measurement');}); const sstring = $('.controller.string').children().eq(1).children().eq(0); sstring.attr('id', 'sname'); sstring.attr('name', 'sname'); @@ -333,6 +389,7 @@ // $(function() {$(".sname").autocomplete({source: names, close: function(event, ui) {findComponent($('#sname').val()); }, select: function(event, ui) {findComponent(ui.item.value); return false;}});}); $(function() {$(".sname").autocomplete({source: names, select: function(event, ui) {findComponent(ui.item.value); return false;}});}); function toggleParam(name) { + if (name=='measurement') { measurement = !measurement; measurementType = measurement; if (measurement) measurementEnable(); else measurementDisable(); return;} if (name=='backgroundColor') {$('body').css('backgroundColor', params.backgroundColor); return;} const urlparam = {}; let search = document.location.search.replace('?', '').split('&'); @@ -392,14 +449,20 @@ fetch(latticeFile).then((response) => {return response.json();}).then((flattice) => { lattice = flattice; if (Object.keys(lattice).length>0) { + gui.add(params, 'measurement button', {Left: 'left', Right: 'right'}).onChange(measurementFacility); + const measurementDevice = {'': ''}; for (let i in lattice) {if (i!='conf') facilities.push(i);} for (let i in lattice) { if (i == 'conf') continue; + params[i] = false; + if (i != 'servicearea' && i != 'bl') measurementDevice[i] = i; // logic XOR https://stackoverflow.com/questions/2335979/is-there-anyway-to-implement-xor-in-javascript if ((document.location.search.indexOf('servicearea')==-1) != (i=='servicearea')) initLattice(lattice[i].sections, i); else { if (document.location.search.indexOf('+servicearea')>-1) initLattice(lattice[i].sections, i); else initSearch(lattice[i].sections, i); } } + gui.add(params, 'measurement device', measurementDevice).onChange(measurementFacility); + if (document.location.search.indexOf('measurement')==-1) measurementToggle(false); bpmInit(facilities); if (document.location.search.indexOf('servicearea')>-1) initSearch(lattice.servicearea.sections, 'servicearea'); if (typeof blm != 'undefined') blmMenu(lattice, facilities, params); @@ -873,6 +936,14 @@ } }; function myPanZoomDelayed(event) { + const urlPan = (document.location.search.indexOf('pan=')==-1)? [0, 0]: document.location.search.split('pan=')[1].split('&')[0].split(','); + const urlZoom = (document.location.search.indexOf('zoom=')==-1)? 1: document.location.search.split('zoom=')[1].split('&')[0]; + if (Math.abs(panZoomPanther.getPan().x - urlPan[0]) + Math.abs(panZoomPanther.getPan().y - urlPan[1]) > 1) { + setUrl('pan', Math.round(panZoomPanther.getPan().x*100)/100+','+Math.round(panZoomPanther.getPan().y*100)/100); + } + if (Math.abs(panZoomPanther.getZoom() - urlZoom) > 0.1) { + setUrl('zoom', Math.round(panZoomPanther.getZoom()*100)/100); + } if (event) event.preventDefault(); visibleX = 0 - point.x/zoom; visibleWidth = document.getElementById('panther').clientWidth/zoom; @@ -880,7 +951,7 @@ myPanZoomTimer = null; oldZoom = zoom; } - let firstUrl = true; + let urlCount = -1; function setUrl(name, value) { let t = + new Date(); if (t - historytime < 100) return; @@ -890,9 +961,9 @@ for (let i in parameters) {pp.push(i+'='+parameters[i]);} const url = document.location.origin+document.location.pathname+'?'+pp.join('&').replaceAll('=undefined', '').replace('search=','s='); // console.log('setUrl()',name, value, url); - if (firstUrl) window.history.pushState({"html":'panther2d.php',"pageTitle":'PAnTHer'},"", url); - else window.history.replaceState({"html":'panther2d.php',"pageTitle":'PAnTHer'},"", url); - firstUrl = false; + if (urlCount==1) window.history.pushState({"html":'panther2d.php',"pageTitle":'PAnTHer'},"", url); + else if (urlCount>1) window.history.replaceState({"html":'panther2d.php',"pageTitle":'PAnTHer'},"", url); + urlCount++; } function myPan(oldPan, newPan) { setUrl('pan', Math.round(newPan.x*100)/100+','+Math.round(newPan.y*100)/100); @@ -902,7 +973,7 @@ // mylog('myPan', p,q); } function myZoom(oldScale, newScale) { - clearRuler(); + clearmeasurement(); setUrl('zoom', Math.round(newScale*100)/100); zoom = newScale; if (newScale>2) $('.label').show(); else $('.label').hide();