Newer
Older
// jshint esversion: 6
let gui = new lil.GUI();
let hideTimeout = false;
let svg;
let zoom = 1;
let oldZoom = 1;
let panZoomPanther;
let foundAnimate = 1;
let foundScale = 1.05;
let myPanZoomTimer = null;
let historytime = + new Date();
let fel1 = false;
let fel2 = false;
const panZoomTime = 500;
const facilities = [''];
const names = [];
const serviceareanames = [];
const alias = [];
let maxZoom = 230;
const status = [];
const point = {x: 0, y: 0};
const pa = document.location.search.replace('?','').split('&');
const parameters = {};
const state = document.location.search.indexOf('ps')>-1;
const vlv = document.location.search.indexOf('vlv')>-1;
const vlvs = [];
const speechToken = Math.floor(Math.random() * 1000000000000);
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();
const backgroundColor = document.location.search.indexOf('backgroundColor=')>-1? document.location.search.split('backgroundColor=')[1].split('&')[0]: '#000'; //'#333333';
let trajectoryWidth = document.location.search.indexOf('trajectoryWidth=')>-1? document.location.search.split('trajectoryWidth=')[1].split('&')[0]-0: 2;
const main = document.getElementById('main');
const facilityStatus = {};
let ruler = document.location.search.indexOf('ruler')>-1;
let measurementType = document.location.search.indexOf('measurement=')>-1? document.location.search.split('measurement=')[1].split('&')[0].split(','): document.location.search.indexOf('measurement')>-1;
let hidecomponents = document.location.search.indexOf('hidecomponents=')>-1? document.location.search.split('hidecomponents=')[1].split('&')[0].split(','): false;
if (typeof measurementType == "object") {
const index = measurementType.indexOf('left');
measurementEvent = 'mousedown';
measurementType.splice(index, 1);
let measurement = typeof measurementType == "object" || measurementType;
function pad(n, width, z) {
z = z || '0';
n = n + '';
return n.length >= width ? n : new Array(width - n.length + 1).join(z) + n;
}
// console.log('getRulerPosition', main, event, facility);
if (clickStat) return;
const rect = main.getBoundingClientRect();
const x = event.clientX - rect.left;
const y = event.clientY - rect.top;
const vertex = [];
let p;
let minDistance = Infinity;
let d = 0;
let dindex = -1;
const x1 = (x - panZoomPanther.getPan().x) / panZoomPanther.getSizes().realZoom;
const y1 = (y - panZoomPanther.getPan().y) / panZoomPanther.getSizes().realZoom;
for (let i=0; i < lattice[facility].sections.length; i++) {
const j = (i+1) % lattice[facility].sections.length;
vertex[i] = lattice[facility].sections[i].start;
d = pDistance(x1, y1, vertex[i].x, vertex[i].z, lattice[facility].sections[j].start.x, lattice[facility].sections[j].start.z);
if (minDistance > d.dist) { minDistance = d.dist; dindex = i; p = d;}
}
const i = dindex;
const j = (i+1) % lattice[facility].sections.length;
const alpha = 180/Math.PI*Math.atan2(lattice[facility].sections[j].start.z-lattice[facility].sections[i].start.z, lattice[facility].sections[j].start.x-lattice[facility].sections[i].start.x);
// console.log(dindex, p.dist, p.x, p.y, alpha);
$('#rulerg').attr('transform', 'translate('+ (p.x)+' '+(p.y)+'),rotate('+alpha+')');
}
function rulerInit() {
const cx=0, cy=0;
appendSvg("g", {id: 'rulerg'}, false, false, 'rulerclass');
appendSvg("line", {id: 'ruler1', x1: cx-10050, y1: cy, x2: cx+10050, y2: cy, style:"display: block", stroke:"yellow", "stroke-width":100}, false, false, 'rulerclass', '#rulerg');
for (let i=-10; i<=10; i++) {
const xt = (cx+i*1000);
appendSvg("line", {id: 'tick1'+(100-i), x1: xt, y1: cy, x2: xt, y2: cy+300, style:"display: block", stroke:"yellow","stroke-width":100}, false, false, 'rulerclass', '#rulerg');
appendSvg("text", {id: 'label'+(100-i), x: xt-300, y: cy+600, fill:"yellow", stroke:"black","stroke-width":1, "font-family":"Arial", "font-size":300, "font-weight":"bold", "text-anchor": "start"}, false, false, 'rulerclass', '#rulerg');
if (i) $('#label'+(100-i)).html(Math.abs(i)+' m');
}
appendSvg("line", {id: 'redruler1', x1: cx, y1: cy, x2: cx, y2: cy+10050, style:"display: block", stroke:"red", "stroke-width":100}, false, false, 'rulerclass', '#rulerg');
for (let i=0; i<=10; i++) {
const yt = (cy+i*1000);
appendSvg("line", {id: 'redtick1'+(100-i), x1: cx, y1: yt, x2: cx+300, y2: yt, style:"display: block", stroke:"red","stroke-width":100}, false, false, 'rulerclass', '#rulerg');
appendSvg("text", {id: 'redlabel'+(100-i), x: cx+400, y: yt, fill:"red", stroke:"black","stroke-width":1, "font-family":"Arial", "font-size":300, "font-weight":"bold", "text-anchor": "start"}, false, false, 'rulerclass', '#rulerg');
}
appendSvg("line", {id: 'greenruler1', x1: cx, y1: cy, x2: cx, y2: cy-10050, style:"display: block", stroke:"green", "stroke-width":100}, false, false, 'rulerclass', '#rulerg');
for (let i=0; i<=10; i++) {
const yt = (cy-i*1000);
appendSvg("line", {id: 'greentick1'+(100-i), x1: cx, y1: yt, x2: cx+300, y2: yt, style:"display: block", stroke:"green","stroke-width":100}, false, false, 'rulerclass', '#rulerg');
appendSvg("text", {id: 'greenlabel'+(100-i), x: cx+400, y: yt, fill:"green", stroke:"black","stroke-width":1, "font-family":"Arial", "font-size":300, "font-weight":"bold", "text-anchor": "start"}, false, false, 'rulerclass', '#rulerg');
}
}
function trajectoryWidthSet(a) {
console.log(a, zoom);
trajectoryWidth = a;
$('.trajectory').css('stroke-width', 75*trajectoryWidth/zoom);
}
function rulerSwitch() {
$('#rulerg').toggle();
}
if (scaleprefix != '' && $('#scaleh')[0].style.display != 'none') return;
const units = [' m', '00 mm', '0 mm', ' mm', '00 μ', '0 μ', 'μ', '00 nm', '0 nm', ' nm'];
const scaleh = ($('#'+scaleprefix+'scaleh').children().eq(1).children()[1].value-0)*cfactor;
const scalehunit = Math.ceil(Math.log10(scaleh));
const scalehfactor = scaleh/Math.pow(10, scalehunit);
const scalev = ($('#'+scaleprefix+'scalev').children().eq(1).children()[1].value-0)*cfactor;
const scalevunit = Math.ceil(Math.log10(scalev));
const scalevfactor = scalev/Math.pow(10, scalevunit);
const hfactor = scalehfactor<0.2? 5: (scalehfactor<0.5? 2: 1);
const vfactor = scalevfactor<0.2? 5: (scalevfactor<0.5? 2: 1);
console.log('scaleh', scaleh, 'scalehunit', scalehunit, 'scalehfactor', scalehfactor);
$('#redruler1').attr('y2', -10100*scalehfactor*hfactor);
$('#greenruler1').attr('y2', 10100*scalevfactor*vfactor);
$('#redtick1'+(100-i)).attr('y1', yh);
$('#redtick1'+(100-i)).attr('y2', yh);
$('#redlabel'+(100-i)).attr('y', yh);
$('#redlabel'+(100-i)).html(i*hfactor+units[scalehunit]);
const yv = (-i*vfactor*1000*scalevfactor);
$('#greentick1'+(100-i)).attr('y1', -yv);
$('#greentick1'+(100-i)).attr('y2', -yv);
$('#greenlabel'+(100-i)).attr('y', -yv);
$('#greenlabel'+(100-i)).html(i*vfactor+units[scalevunit]);
function setTick(x, y, cx, cy, dist, distPixel, n, pow10=1000) {
const tx1 = cx + (x - cx) / dist * pow10 * n;
const ty1 = cy + (y - cy) / dist * pow10 * n;
const tx2 = tx1 - (y - cy) / distPixel * 10;
const ty2 = ty1 + (x - cx) / distPixel * 10;
$('#tick'+n).attr('x1', tx1);
$('#tick'+n).attr('y1', ty1);
$('#tick'+n).attr('x2', tx2);
$('#tick'+n).attr('y2', ty2);
$('#tickLabel'+n).attr('x', 2*tx2-tx1);
$('#tickLabel'+n).attr('y', 2*ty2-ty1);
$('#tickLabel'+n).html(x==cx || distPixel<220? '': pow10 * n / 1000);
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
}
// 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;
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 (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));
const pow10 = Math.pow(10, Math.round(Math.log10(dist))-1);
$('#measurementLine').attr('x2', x);
$('#measurementLine').attr('y2', y);
$('#measurementLineStroke').attr('x2', x);
$('#measurementLineStroke').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 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[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[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[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[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[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)+' ';
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);
$('#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 clearmeasurement() {
$('#measurementLine').attr('x1', cx);
$('#measurementLine').attr('y1', cy);
$('#measurementLine').attr('x2', cx);
$('#measurementLine').attr('y2', cy);
$('#measurementLineStroke').attr('x1', cx);
$('#measurementLineStroke').attr('y1', cy);
$('#measurementLineStroke').attr('x2', cx);
$('#measurementLineStroke').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);
for (let i=1; i<32; i++) {setTick(cx, cy, cx, cy, 1, 1, i);}
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 (!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: 'measurementLineStroke', x1: cx, y1: cy, x2: cx, y2: cy, style:"display: block", fill:"yellow", stroke:"black","stroke-width":4});
appendSvg("line", {id: 'measurementLine', x1: cx, y1: cy, x2: cx, y2: cy, style:"display: block", fill:"yellow", stroke:"yellow","stroke-width":2});
appendSvg("path", {d: '', fill: "none", stroke: "limegreen", "stroke-width": 3, id:"beam"});
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});
appendSvg("line", {id: 'tick'+i, x1: cx, y1: cy, x2: cx, y2: cy, style:"display: block", fill:"yellow", stroke:"black","stroke-width":1});
appendSvg("text", {id: 'tickLabel'+i, x: cx, y: cy, fill:"white", stroke:"black","stroke-width":1, "font-family":"Arial", "font-size":20, "font-weight":"bold", "text-anchor": "start"});
// $('#measurementStart').attr('cx', cx); $('#measurementStart').attr('cy', cy);
$('#measurementLine').attr('x1', cx);
$('#measurementLine').attr('y1', cy);
$('#measurementLineStroke').attr('x1', cx);
$('#measurementLineStroke').attr('y1', cy);
}
main.addEventListener('mousemove', function(e) {
getCursorPosition(main, e);
});
}
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();
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
if (machine.indexOf('fermi')>-1) {
fetch(conf.rchan+'srv-tango-srf-01:20000/f/access_control/safety/Undulator_access_state').then((response) => {return response.json();}).then((fel) => {
fel1 = fel[5] == 1;
fel2 = fel[6] == 1;
});
}
function resizeIframe(obj) {
obj.style.height = obj.contentWindow.document.documentElement.scrollHeight + 'px';
}
let latticeFile = document.location.href.split('?')[0].split('/').slice(0,-1).join('/')+'/'+machine+'_lattice.json';
if (machine.indexOf('simulator_')>-1) {latticeFile = document.location.href.split('?')[0].split('/').slice(0,-1).join('/')+'/'+'simulator.php?lattice&machine='+machine.split('simulator_')[1];}
const menuParams = {machine: machineCaseSensitive.toLowerCase(), search: '', backgroundColor: backgroundColor};
gui.title('PAnTHer - controls');
// if (navigator.userAgent.indexOf('Firefox/63')>-1) {$( "body" ).append('<button id="starter" style="align: center;height: 500px; width: 95%;background-color: #449944; font-size: 100px;" onClick="mystart()">START</button>');}
function mystart() {
panZoomPanther = svgPanZoom('#panther', {beforeZoom: myZoom, fit: false, contain: false});
$("#sname").on("keydown", searchText);
$('#starter').hide();
}
// Polyfill replaceAll()
if (typeof String.prototype.replaceAll !== 'function') {
String.prototype.replaceAll = function(search, replacement) {
var target = this;
return target.split(search).join(replacement);
};
// Polyfill for parentNode.replaceChildren()
if (typeof Element.prototype.replaceChildren !== 'function') {
Object.defineProperty(Element.prototype, 'replaceChildren', {
configurable: true,
writable: true,
value: function replaceChildren(...nodes) {
// Remove all existing child nodes
while (this.firstChild) {
this.removeChild(this.firstChild);
}
// Append new DOM objects
this.append(...nodes);
}
});
}
function toggleMachine(machine) {
document.location = document.location.href.split('?')[0] + '?machine='+machine;
/*if (document.location.search.indexOf('machine=')==-1) document.location = document.location.href + (document.location.href.indexOf('?')==-1? '?': '&') + 'machine='+machine;
let search = document.location.search.split('machine=')[1].split('&')[0];
document.location = document.location.href.replace('machine='+search, 'machine='+machine);*/
}
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) {
console.log('searchText()', e, e.keyCode || e.which, $("#sname").val().toUpperCase().replace('.','_'));
if (e.keyCode == 13) findComponent($("#sname").val().toUpperCase());
function shrinkName(name) {
return name.replaceAll('FEL0', 'FEL').replaceAll('PS_', 'PS').replaceAll('SIP_', 'SIP').replaceAll('KG0', 'KG').replaceAll('BC0', 'BC').replaceAll('_L0', 'L').replaceAll('_F0', 'F').replaceAll('_0', '').replaceAll('_', '');
}
function guiconf(gui, id) {
const i = gui.children.length - 1;
gui.children[i].domElement.style.display = 'none';
gui.children[i].domElement.setAttribute('id', id);
}
// if (navigator.userAgent.indexOf('Firefox/63')==-1) {gui.add(menuParams, 'machine', conf.machineList).onChange(function() {toggleMachine(menuParams.machine);});}
gui.add(menuParams, 'machine', conf.machineList).onChange(function() {toggleMachine(menuParams.machine);});
gui.add(menuParams, 'search');
$('.controller.string:last').parent().append('<iframe id="talk" style="height: 30px;" src="./speech/talk.php?background=black&token='+speechToken+'" frameborder="0" scrolling="no" onload="resizeIframe(this)"></iframe>');
gui.addColor(menuParams, 'backgroundColor').onChange(function() {toggleParam('backgroundColor');});
menuParams.vlv = document.location.search.indexOf('vlv')>-1;
gui.add(menuParams, 'vlv').name('vlv & bst').onChange(function() {toggleParam('vlv');});
menuParams.ps = document.location.search.indexOf('ps')>-1;
gui.add(menuParams, 'ps').onChange(function() {toggleParam('ps');});
const sstring = $('.controller.string').children().eq(1).children().eq(0);
sstring.attr('id', 'sname');
sstring.attr('name', 'sname');
sstring.addClass("form-control sname");
function findComponent(name) {
// https://stackoverflow.com/questions/5497318/replace-last-occurrence-of-character-in-string
if (name.indexOf('.')==-1 && name.indexOf('_')>-1) name = name.replace(/_([^_]*)$/, '.' + '$1');
if (document.location.search.indexOf('debugfind')>-1) {console.log('findComponent('+name+')'); return 'OK';}
let servicearea = false;
if (lattice.servicearea) for (let i in lattice.servicearea.sections) {
for (let j in lattice.servicearea.sections[i].components) {
if (name.replace('.', '_')==lattice.servicearea.sections[i].components[j].name.replace('.', '_')) {servicearea = true;}
for (let k in lattice.servicearea.sections[i].components[j].embedded) {
if (name==lattice.servicearea.sections[i].components[j].embedded[k]) {servicearea = true;}
}
}
}
console.trace(name, servicearea, document.location.search.indexOf('servicearea'), document.location.search.indexOf('search='+name)); // return;
if ((servicearea != document.location.search.indexOf('servicearea')>-1) && document.location.search.indexOf('search='+name)==-1) {
document.location = './panther2d.php?machine='+machine+'&search='+name+(servicearea? '&servicearea': '');
}
if (name==null) name = document.getElementById('sname').value;
for (let i=0; i<alias.length; i++) if (alias[i][1]==name) name = alias[i][0];
console.log(name, typeof $('#'+name)[0], shrinkName(name), shrinkedNames.indexOf(shrinkName(name)));
if (typeof $('#'+id)[0] == 'undefined') {
const sindex = shrinkedNames.indexOf(shrinkName(id));
if (sindex>-1) id = names[sindex]; else return name+' Not found';
if (document.location.search.indexOf('servicearea')>-1) facilityStatus.servicearea = true;
console.log(name, window.innerWidth/2, $('#'+id)[0].getCTM().e, $('#'+id)[0].getCTM().f);
// panZoomPanther.zoomAtPoint(10, {x: window.innerWidth/2 - $('#'+name)[0].getCTM().e, y: window.innerHeight/2 - $('#'+name)[0].getCTM().f})
panZoomPanther.zoom(10);
// leave a delay between zoom and pan
}
function mypan(name) {
$('.label').show();
const x = window.innerWidth/2 - $('#'+name)[0].getCTM().e + panZoomPanther.getPan().x;
const y = window.innerHeight/2 - $('#'+name)[0].getCTM().f + panZoomPanther.getPan().y;
const m = $("svg")[0].getTransformToElement($('#'+name)[0]);
panZoomPanther.pan({x: x, y: y});
if (!facilityStatus.servicearea) $('.servicearea').hide();
setTimeout(pinhide, 100, name, $('#'+name).eq(0).attr('transform'));
}
foundAnimate *= foundScale;
if (foundAnimate>1.5) foundScale = 0.95;
if (foundAnimate<1) {foundScale = 1.05; foundAnimate = 1;} else setTimeout(pinhide, 100, name, transform);
$('#'+name).eq(0).attr('transform',transform+',scale('+foundAnimate+')');
}
// $(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', menuParams.backgroundColor); return;}
const urlparam = {};
let search = document.location.search.replace('?', '').split('&');
if (search[0]=='') search.splice(0,1);
const i=search.indexOf(name);
if (i==-1) search.push(name); else search.splice(i,1);
const res = search.join('&');
document.location = document.location.href.split('?')[0]+(res.length? '?'+res: '');
}
async function subscribeSpeech() {
mylog('subscribeSpeech()', 1, 2);
let response = await fetch("./speech/talk.php?read&token="+speechToken);
} else if (response.status != 200) {
// An error - let's show it
mylog('subscribeSpeech() ERROR ', response.statusText);
// Reconnect in one second
await new Promise(resolve => setTimeout(resolve, 1000));
} else {
// Get and show the message
let message = await response.text();
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);
// return feedback
fetch("./speech/talk.php?readresult="+msg+"&token="+speechToken);
}
// Call subscribeSpeech() again to get the next message
await subscribeSpeech();
if (document.location.search.indexOf('debug')>-1) $('#debug').val($('#debug').val()+JSON.stringify(args)+'\n');
console.trace.apply(null);
console.log(args, JSON.stringify(args), $('#debug').val());
}
function initIndex(lattice) {
const index = [];
for (let l in lattice.conf.index) {
if (l=='start') continue;
const cmd = "findComponent('"+lattice.conf.index[l].replace('.','_')+"')";
index.push('<button onclick="'+cmd+'">'+l+'</button>');
}
$('body').append('<div style="position: absolute; left: 5px; bottom: 5px;">'+index.join(' ')+'</div>');
}
function toggleFacility(value) {
console.log('toggleFacility', value, this);
if (value) $('.'+this.property).show(); else $('.'+this.property).hide();
}
function initShortcut(lattice) {
const index = [];
for (let l in lattice.conf.shortcut['2d']) {
const cmd = "document.location = document.location.pathname + '?"+lattice.conf.shortcut['2d'][l]+"';";
index.push('<button onclick="'+cmd+'" id="'+l.toLowerCase().split(' ').join('')+'">'+l+'</button>');
}
$('body').append('<div style="position: absolute; left: 5px; bottom: 5px;">'+index.join(' ')+'</div>');
}
function init() {
fetch(latticeFile).then((response) => {return response.json();}).then((flattice) => {
lattice = flattice;
if (Object.keys(lattice).length>0) {
const machineFolder = gui.addFolder('toggle facility');
for (let i in lattice) {if (i!='conf') facilities.push(i); facilityStatus[i] = i!='servicearea';}
if (document.location.search.indexOf('+servicearea')>-1) {
facilityStatus.servicearea = true;
}
menuParams[' '] = false; machineFolder.add(menuParams, ' ').onChange(toggleFacility);
// for (let i=0; i<facilities.length; i++) if (facilities[i]!='') {menuParams[facilities[i]] = true;}
menuParams[i] = document.location.search.indexOf(i+'=hide')==-1;
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);
// menuParams[i] = true;
}
else {
initLattice(lattice[i].sections, i);
console.log('.', i, menuParams[i]);
if (document.location.search.indexOf('+servicearea')==-1) {
for (let i=0; i<facilities.length; i++) if (facilities[i]!='') {machineFolder.add(menuParams, facilities[i]).onChange(toggleFacility);}
menuParams.measurement = document.location.search.indexOf('measurement')>-1;
gui.add(menuParams, 'measurement').onChange(function() {toggleParam('measurement');});
menuParams['measurement button'] = 'right';
gui.add(menuParams, 'measurement button', {Left: 'left', Right: 'right'}).onChange(measurementFacility);
menuParams['measurement device'] = '';
gui.add(menuParams, 'measurement device', measurementDevice).onChange(measurementFacility);
if (document.location.search.indexOf('measurement')==-1) measurementToggle(false);
if (document.location.search.indexOf('servicearea')>-1) initSearch(lattice.servicearea.sections, 'servicearea');
if (typeof blm != 'undefined') blmMenu(lattice, facilities, menuParams);
menuParams.trajectoryWidth = trajectoryWidth;
gui.add(menuParams, 'trajectoryWidth', 1, 10, 0.2).onChange(function(e) {trajectoryWidthSet(e);});
guiconf(gui, 'trajectoryWidth');
menuParams.ruler = ruler;
gui.add(menuParams, 'ruler').onChange(function() {rulerSwitch();});
guiconf(gui, 'ruler');
rulerInit();
main.addEventListener('mousemove', function(e) {getRulerPosition(main, e, facilities.indexOf('sr')>-1? 'sr': 'fel1');});
if (ruler) {
main.style.cursor = 'crosshair';
}
else {
$('#rulerg').hide();
$('#trajectoryWidth').hide();
}
if (typeof bpmData != 'undefined') bpmMenu(lattice, facilities, menuParams);
if (lattice.conf && lattice.conf.shortcut && lattice.conf.shortcut["2d"]) initShortcut(lattice);
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
if (lattice.conf && lattice.conf.index) initIndex(lattice);
}
$('.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');}
// panZoomPanther = svgPanZoom('#panther', {beforeZoom: myZoom, fit: false, contain: false}); // https://github.com/bastienmoulia/svg-pan-zoom-rotate
// if( /Android|webOS|iPhone|iPad|Mac|Macintosh|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ) {
if( /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ) {
panZoomPanther = svgPanZoom('#panther', {
zoomEnabled: true,
controlIconsEnabled: false,
fit: 0,
center: 1,
maxZoom: maxZoom*2,
customEventsHandler: eventsHandler,
//beforeZoom: myZoom,
});
}
else {
panZoomPanther = svgPanZoom('#panther', {
zoomEnabled: true,
zoomScaleSensitivity: 0.3,
controlIconsEnabled: false,
fit: false,
center: false,
minZoom: 0.2,
maxZoom: maxZoom,
beforePan: myPan,
beforeZoom: myZoom,
});
}
if (document.location.search.indexOf('debug')>-1) {
$('#tooltip').show();
$('#tooltip').css('width', '100%');
$('#tooltip').html('<textarea id="debug" style="height: 100px; width:100%;"></textarea>');
}
let pan = [window.innerWidth/2, window.innerHeight/2];
if (document.location.search.indexOf('pan=')>-1) pan = document.location.search.split('pan=')[1].split('&')[0].split(',');
if (document.location.search.indexOf('search=')>-1) findComponent(document.location.search.split('search=')[1].split('&')[0]);
else {
const default_zoom = typeof conf.default_zoom[machine.split('_')[0]]=='undefined'? conf.default_zoom.default: conf.default_zoom[machine.split('_')[0]];
const zoom = document.location.search.indexOf('zoom=')>-1? document.location.search.split('zoom=')[1].split('&')[0]-0: default_zoom;
panZoomPanther.zoom(zoom);
setTimeout(panZoomPanther.pan, 600, {x: pan[0], y: pan[1]});
}
if (state) {
fetch(conf.stateSrcUrl, {cache: "no-store"}).then((response) => {return response.text();}).then((data) => {
const statSrc = data.toUpperCase().split('.').join('_').split(',');
for (let j=0; j<statSrc.length; j++) {
// if (statSrc[j].split('/')[2]=='POWER_SUPPLY' || statSrc[j].split('/')[2]=='INJECTION' || statSrc[j].split('/')[2]=='EXTRACTION')
statSrc[j] = statSrc[j].split('/')[3].replace('PS', '');
}
for (let i=0; i<status.length; i++) {
if (status[i].name.indexOf('KICK')>-1) console.log('KICK state', i, status[i].name, statSrc);
for (let j=0; j<statSrc.length; j++) {
if (status[i].name.indexOf(statSrc[j])>-1) {status[i].statsrc = state; status[i].statindex = j;}
}
}
// console.log('statSrc', data, statSrc, status);
});
setInterval(updateStatus, 1000);
}
if (vlv) {
for (let i in conf.bstmap) { if (i.indexOf('.')>-1) conf.bstmap[i.replace('.','_')] = conf.bstmap[i];}
fetch(conf.vlvSrcUrl, {cache: "no-store"}).then((response) => {return response.text();}).then((data) => {
const vlvSrc = data.toUpperCase().substring(14).split(',');
for (let i=0; i<vlvs.length; i++) {
for (let j=0; j<vlvSrc.length; j++) {
const vlva = vlvSrc[j].split('/');
if (vlva.length < 4) continue;
const name = vlva[3].replace('.','_');
if (vlvs[i].name.replace('.','_').indexOf(name)>-1) {vlvs[i].vlvsrc = state; vlvs[i].vlvindex = j; vlvs[i].type = 'vlv';}
if (vlvSrc[j].split('/')[2].indexOf(conf.bstmap.base)>-1) {
if (conf.bstmap[vlvs[i].name] && conf.bstmap[vlvs[i].name].indexOf(vlvSrc[j].split('/')[4])>-1) {
vlvs[i].vlvsrc = 'bst'; vlvs[i].vlvindex = j; vlvs[i].type = 'bst';
}
}
}
}
//console.log('vlvSrc', data, vlvSrc, vlvs);
});
setInterval(updateVlv, 1000);
}
$("#sname").on("keydown", searchText);
window[lattice.conf.modules[i]+'2d'](lattice, menuParams, compData);
menuParams.gotoAdmin = function() {document.location = './admin.php';};
gui.add(menuParams, 'gotoAdmin').name('Admin');
menuParams.goto3D = function() {document.location = './panther.php?machine='+menuParams.machine;};
gui.add(menuParams, 'goto3D').name('3D');
// if (document.location.search.indexOf('expandbl')>-1) $('#blBtn').click();
});
}
function showStatus(i, stat) {
if (stat == 0 || stat == 'null' || stat == '' || stat == 'ON' || stat == 'RUNNING' || (!fel1 && $('#'+status[i].name)[0].classList[0]=='fel1') || (!fel2 && $('#'+status[i].name)[0].classList[0]=='fel2')) {$('#'+status[i].name).hide();}
else if (stat == 'ON' || stat == 'RUNNING') {$('#'+status[i].name).show();document.getElementById(status[i].name).style.fill = conf.stateLabelColor[stat];$('#'+status[i].name).addClass('noblink');}
else {$('#'+status[i].name).show(); document.getElementById(status[i].name).style.fill = conf.stateLabelColor[stat];$('#'+status[i].name).removeClass('noblink');}
// console.log(i, status[i], stat);
}
function clearStatus() {
}
function updateStatus() {
fetch(conf.stateUrl, {cache: "no-store"}).then((response) => {return response.text();}).then((data) => {
const statVal = data.split(';');
// console.log(conf.stateUrl, statVal, status);
for (let i=0; i<status.length; i++) {
if (status[i].statsrc==state) {
if (status[i].statindex) showStatus(i, statVal[status[i].statindex]);
// console.log(statVal, status, status[i].name, i, status[i].statindex, statVal[status[i].statindex]);
}
}
setTimeout(clearStatus, 600);
});
}
function updateVlv() {
fetch(conf.vlvUrl, {cache: "no-store"}).then((response) => {return response.text();}).then((data) => {
const vlvVal = data.split(':')[1].split(';');
// console.log('updateVlv()', conf.vlvUrl, vlvVal, vlvs);
for (let i=0; i<vlvs.length; i++) {
if (vlvs[i].type=='vlv') $('#'+vlvs[i].name).css('fill', vlvVal[vlvs[i].vlvindex]=='CLOSED'? 'red': (vlvVal[vlvs[i].vlvindex]=='OPENED'? 'limegreen': 'grey'));
if (vlvs[i].type=='bst') {
if (typeof vlvVal[vlvs[i].vlvindex] != 'string') continue;
const val = vlvVal[vlvs[i].vlvindex].split(',');
$('#'+vlvs[i].name).css('fill', val[0]=='true'? 'limegreen': (val[1]=='true'? 'red': 'grey'));
}
}
});
}
function rescale(x) {return x;}
String.prototype.replaceAt = function(index, replacement) {
return this.substring(0, index) + replacement + this.substring(index + replacement.length);
};
function evalLeft(x) {
if (innerWidth-x > 490) return 30 + (x-0);
return innerWidth - 510;
};
function evalId(base) {
if (base.indexOf('.')>-1) return base;
return base.replaceAt(base.lastIndexOf('_'), '.').replace('RTBPM','BPM');
}
function openTooltip(event) {
if (typeof event == 'string' && event.indexOf('trajectory')>-1) {
const eventData = event.split(' ');
console.log(event);
$('#tooltip').css('left', evalLeft(eventData[2]));
console.log('left', $('#tooltip').css('left'));
$('#tooltip').css('top', 30 + (eventData[3]-0));
$('#tooltip').show();
$('#tooltipFrame').attr('src', conf.tooltipApp+'?s=trajectory¶m='+event.split(' ')[1]);
console.log(document.getElementById('tooltip').style.display);
pinTooltip = true;
if (hideTimeout!==false) clearTimeout(hideTimeout);
hideTimeout = setTimeout(hideTooltip, 120000);
console.log(document.getElementById('tooltip').style.display);
// return;
}
else 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': '???');
console.log('openTooltip()',type, this.id, '-'+this.dataset.embedded+'-', this, event, event.clientY);
const embedded = (typeof this.dataset.embedded == 'undefined' || this.dataset.embedded == 'undefined' || this.id[0]=='R')? '': ','+this.dataset.embedded;
document.getElementById('tooltipFrame').src = conf.tooltipApp+'?s='+type.replace('fast', '')+'¶m='+this.id + embedded.replace(',undefined','');
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);
const id = evalId(this.id);
let buttons = '<button onClick="compLink(\''+conf.compdb + id+'\')">'+id+'</button> ';
if (typeof this.dataset.embedded != 'undefined' && 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> ';
}
}
else {
for (let i=0; i<lattice.servicearea.sections.length; i++) {
if (lattice.servicearea.sections[i].components) for (let j=0; j<lattice.servicearea.sections[i].components.length; j++) {
if (lattice.servicearea.sections[i].components[j].embedded && lattice.servicearea.sections[i].components[j].embedded.indexOf('PS'+id)>-1) rack = 'rack <button onClick="compLink(\'https://puma-01.elettra.eu/spa/index.html?s='+lattice.servicearea.sections[i].components[j].name.split('_')[0].toLowerCase()+'¶m='+lattice.servicearea.sections[i].components[j].name+'\')">'+lattice.servicearea.sections[i].components[j].name+'</button> ';
}
}
}
buttons = buttons + rack;
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);
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"/>';
}
else if (machine=='elettra') document.getElementById('compdb').setAttribute("disabled", true);
event.stopPropagation();
}
else {
for (let l in lattice) {
if (l=='confg') continue;
let servicearea = false;
for (let i in lattice[l].sections) {
for (let j in lattice[l].sections[i].components) {
if (this.id==lattice[l].sections[i].components[j].name.replace('.', '_')) {mylog('openTooltip()', lattice[l].sections[i].components[j], lattice[l].sections[i].components[j].position-document.location.search.split('offset=')[1].split('&')[0]);}
}
}
}
}
}
function hideTooltip() {
if (hideTimeout!==false) clearTimeout(hideTimeout);
hideTimeout = false;
if (document.location.search.indexOf('debug')==-1) {
document.getElementById('tooltipFrame').src = '';
document.getElementById('tooltip').style.display = 'none';
}
}
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? -350: 350)+" "+(labelReverse? 100: 200)+")";
function appendSvg(tagName, attrib, onClickCall=false, text=false, myclass=false, appendTo="svg") {
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);
// const textNode = document.createTextNode(text); elem.appendChild(textNode);
elem.innerHTML = text;
}
const jelem = $(elem);
if (myclass) {/*mylog(elem, jelem, myclass);*/ elem.classList.add(myclass);}
for (let i in attrib) {
// if (tagName=='line') console.log('line', i, attrib[i]);
jelem.attr(i, ''+attrib[i]);
const hook = appendTo.indexOf('.')==0? appendTo.replace(' ','_'): appendTo.replace('.','_').replace(' ','_');
$(hook).append(jelem);
}
function appendSearch(component, facility) {
// mylog('appendSearch()',component, facility);
if (component) {
const comp = component.type.replace('booster', '');
if (comp && comp!=' ' && $('#'+comp)[0]) {
const id = extractId(component.name);
names.push(id[0]);
if (facility=='servicearea') serviceareanames.push(id[0]);
for (let j=0; j<component.embedded.length; j++) {
names.push(component.embedded[j]);
shrinkedNames.push(shrinkName(component.embedded[j]));
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]]);
}
}
function appendLabel(id, labelclass, display, x, y, beta, labelReverse, suffix='label', fontSize=1, appendTo="svg") {
if ((beta+3600)%360 <180 && typeof labelReverse != 'object') labelReverse = [-90, -250, -100];
const anchorEnd = (typeof labelReverse == 'object' && labelReverse.length>3)? labelReverse[3]-0: 1;
appendSvg("text", {
id: (id+suffix).replace(' ','_'),
x:0, y:0, style:"display: "+display, fill:"white", stroke:"#101020","stroke-width":0, "font-family":"Arial", "font-size":100*fontSize, "font-weight":"700",
"text-anchor": ((labelReverse && anchorEnd)? "end": "start"),
}
function appendLabel2(param, labelclass, display, x, y, beta, labelReverse, suffix='label') {
const id = param.name;
const fontsize = labelclass.indexOf('bl')>-1? 800: 500;
// console.log("appendLabel2()",param, labelclass, display, x, y, beta, labelReverse);
if (labelclass.indexOf('bl')>-1 && typeof labelReverse != 'object') {
labelReverse = [180, 17000, param.type=='beamlineUp'? -500: +800];
if ((beta+3690)%360 < 180) labelReverse = [0, -14000, param.type=='beamlineUp'? 1000: -300];
}
else if ((beta+3600)%360 < 180 && typeof labelReverse != 'object') labelReverse = [-90, -250, -100];
appendSvg("text", {
x:0, y:0, style:"display: block", fill:"red", stroke:"pink","stroke-width":5, "font-family":"Arial", "font-size":fontsize, "font-weight":"700",
"text-anchor": (labelReverse? "end": "start"),
transform: transformLabel(x, y, beta, labelReverse)
}, false, id);
}
function appendComponent(components, x0, y0, x1, y1, facility) {
const dx = x1 - x0;
const dy = y1 - y0;
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', '');
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];}
if (typeof blm != 'undefined' && comp=='blm') {
const name = components[i].name.replace('BPM','BLM');
// mylog('appendComponent(), ', name, blm.obj);
blm.obj.push(name);
blm.dir.push(beta);
appendSvg("rect", {id:name, name:name, x:0, y:0, width:40, height:40, rx:20, ry:20, transform:"translate("+rescale(x)+" "+rescale(y)+") rotate("+(name.indexOf('_L')>-1? beta + 180: beta)+")"}, openTooltip, false, "blm");
}
if (typeof bpmData != 'undefined' && comp=='bpm') {
// mylog('appendComponent()',components[i], x0, y0, x1, y1, beta, facility, 180*Math.atan2(y0-y1, x0-x1)/Math.PI);
bpmData[facility].obj.push(components[i].name);
bpmData[facility].dir.push(beta);
bpmData[facility].pos.push([rescale(x), rescale(y)]);
}
if (typeof bpmData != 'undefined' && comp=='corrector') {
corr[facility].obj.push(components[i].name);
corr[facility].dir.push(beta);
corr[facility].pos.push([x, y]);
}
if ($('#'+comp)[0]) {
// mylog('components['+i+']',components[i]);
const id = extractId(components[i].name);
const section = components[i].name.indexOf('_')>-1? components[i].name.split('_')[1].split('.')[0]+' ': '';
const offset = components[i].type == 'beamlineUp'? "-2100 -3500": (typeof components[i].reverse2d == 'undefined'? "0 -200": "-500 -1400");
const transform = "translate("+rescale(x)+" "+rescale(y)+") rotate("+(beta+(typeof components[i].reverse2d == 'undefined'? 180: 0))+") translate("+offset+")";
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: [];
const compClass = typeof components[i].class == 'undefined'? '': ' '+components[i].class;
const attr = {href:"#"+compid, id: id[0], name:components[i].name, "data-embedded":components[i].embedded, "data-aka": aka, class: comp+' '+section+facility+compClass, style:"cursor: pointer", transform:transform};
if (hidecomponents && (hidecomponents.indexOf(comp)>-1 || hidecomponents[0]=='*')) attr.visibility = 'hidden';
appendSvg("use", attr, 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+compClass, 'none', x, y, beta, components[i].labelReverse);
if (id[0].indexOf('<')==-1) {
appendSvg("g", {"id": id[0]+'_g'});
appendLabel(components[i].name, comp+' value '+section+facility, 'none', x+600, y+400, 90, true, 'value', 0.7, '#'+id[0]+'_g');