otsdaq_utilities  v2_04_01
ViewerRoot.js
1 //=====================================================================================
2 //
3 // Created Aug, 2013
4 // by Ryan Rivera ((rrivera at fnal.gov))
5 //
6 // ViewerRoot.js
7 //
8 // requires an omni div, that will be made full window size (window.innerWidth and
9 // window.innerHeight) at position 0,0.
10 //
11 // Note: there are some variables declared outside of the namespace ViewerRoot
12 // so take care to avoid naming collisions with:
13 // - gFile
14 // - source_dir
15 // - obj_list
16 // - ViewerRoot.objIndex
17 // - last_index
18 // - function_list
19 // - func_list
20 // - frame_id
21 // - random_id
22 //
23 // public function list:
24 // ViewerRoot.launch()
25 //
26 // from web: http://root.cern.ch/js/
27 // http://root.cern.ch/drupal/content/trevolutionjs
28 // currently using v3.5: https://root.cern.ch/js/3.5/demo/demo.htm
29 // -- to change versions, hopefully just replace folder here:
30 // -- WebGUI/js/visualizers_lib/ViewerRoot_lib/JsRoot/... tar.gz file unzipped inside JsRoot
31 //=====================================================================================
32 
33 
34 var ViewerRoot = ViewerRoot || {}; //define namespace
35 
37 //public function definitions
38 
39 //ViewerRoot ~~
40 //called to start Root viewer
41 ViewerRoot.launch = function() {
42 
43  Debug.log("ViewerRoot.launch");
44 
45  document.getElementById("omni").innerHTML = "<div id='omniHistogramViewer'></div>";
46  ViewerRoot.omni = document.getElementById("omniHistogramViewer");
47 
48  //initialize with loading message in center
49  var w = ViewerRoot.w = window.innerWidth;
50  var h = ViewerRoot.h = window.innerHeight;
51 
52  ViewerRoot.omni.style.position = "absolute";
53  ViewerRoot.omni.style.left = 0 + "px";
54  ViewerRoot.omni.style.top = 0 + "px";
55  ViewerRoot.omni.style.width = w + "px";
56  ViewerRoot.omni.style.height = h + "px";
57  ViewerRoot.omni.style.backgroundColor = "rgb(30,30,30)";
58 
59  ViewerRoot.omni.innerHTML = "<center><div id='loaderStatus' style='margin-top:" + (h/2-8) + "px'>Loading Root Viewer...</div></center>";
60 
61  //load directories of histograms
62  //and display selected histogram
63  //allow window splitting and comparing and contrasting with transparent histos
65 
66  loadScript(source_dir+'ViewerRootHud.js',function(){
67  loadScript(source_dir+'JsRoot/scripts/JSRootCore.js',function(){
68  JSROOT.AssertPrerequisites('2d;io;3d;',ViewerRoot.init);
69  }); });
70 
72  // - if rootCanvas not created, clear omni and create, full window
73  // - since root js library knows to draw in div with id='report'
74  // each root object goes in its own div, which at time of creation is given
75  // id='report'. Maintain array of references to divs holding root object
76  // that does not depend on id. And use for removal and movement and sizing?
77  // - first histo always goes full screen within rootCanvas
78  // - next histo based on RADIO: Tile, Replace, Superimpose
79  // - if TILE, tile it within rootCanvas
80  // - if REPLACE, replace previous object
81  // - if SUPERIMPOSE, place over previous object with alpha 0
82  //
83  // - implementation
84  // - keep array of all root elements drawn
85  // - keep array of their corresponding locations
86  // - keep number of locations used in tile
87 
88 
89 }
90 
91 //end public function definitions
93 
94 
95 var source_dir = "/WebPath/js/visualizers_lib/ViewerRoot_lib/";
96 //var gFile;
97 //var obj_list;
98 //var last_index;
99 //var function_list;
100 //var func_list;
101 //var frame_id;
102 //var random_id;
103 
104 ViewerRoot.STREAMER_INFO_FILE_PATH = "/WebPath/js/visualizers_lib/ViewerRoot_lib/streamerInfo.root";
105 
106 ViewerRoot.LOAD_STREAMER_INFO_CHECK_PERIOD = 100; //ms
107 ViewerRoot.DISPLAY_MIN_WIDTH = 450; //dont allow w or h to go less than this
108 ViewerRoot.DISPLAY_MIN_HEIGHT = 300; //dont allow w or h to go less than this
109 ViewerRoot.HUD_WIDTH = 300;
110 ViewerRoot.HUD_MARGIN_RIGHT = 0;
111 ViewerRoot.HUD_DROP_DOWN_SPEED = 40;
112 ViewerRoot.ROOT_CONTAINER_OFFY = 20;
113 ViewerRoot.ROOT_HEADER_HEIGHT = 20;
114 
115 ViewerRoot.TILE_MODE = 0;
116 ViewerRoot.REPLACE_MODE = 1;
117 ViewerRoot.SUPERIMPOSE_MODE = 2;
118 
119 ViewerRoot.ADMIN_PERMISSIONS_THRESHOLD = 1;
120 ViewerRoot.userPermissions = 0; //0 is no access, 1 is access
121 
122 ViewerRoot.omni;
123 ViewerRoot.rootContainer;
124 
125 ViewerRoot.objIndex;
126 
127 ViewerRoot.rootElArr;
128 ViewerRoot.rootPosArr;
129 ViewerRoot.rootObjArr;
130 ViewerRoot.rootObjIndexArr;
131 ViewerRoot.rootHeaderElArr;
132 ViewerRoot.rootObjNameArr;
133 ViewerRoot.rootIsTransparentArr;
134 ViewerRoot.rootIsAutoRefreshArr;
135 
136 ViewerRoot.numPositionsTiled;
137 ViewerRoot.rootTargetIndex; //targeted object for replace or superimpose
138 ViewerRoot.w;
139 ViewerRoot.h;
140 ViewerRoot.sFile;
141 
142 ViewerRoot.hudAutoHide = false;
143 ViewerRoot.nextObjectMode = 1;
144 ViewerRoot.clearEachRequest = true;
145 ViewerRoot.autoRefreshDefault = false;
146 ViewerRoot.autoRefreshPeriod = 1000;
147 ViewerRoot.pauseRefresh = false;
148 ViewerRoot.hardRefresh = true;
149 
150 ViewerRoot.autoRefreshTimer = 0;
151 
152 
153 ViewerRoot.iterLoading = false;
154 ViewerRoot.iterNumberRemaining;
155 ViewerRoot.iterNumPositionsTiled;
156 ViewerRoot.iterRunWildcard;
157 ViewerRoot.iterRootObjNameArr;
158 ViewerRoot.iterRootPosArr;
159 ViewerRoot.iterRootIsTransparentArr;
160 ViewerRoot.iterRootIsAutoRefreshArr;
161 ViewerRoot.iterSaveNextObjectMode;
162 ViewerRoot.iterSaveAutoRefreshDefault;
163 
164 
165 
166 //"private" function list
167 //ViewerRoot.init
168 //ViewerRoot.autoRefreshTick
169 //ViewerRoot.prepareNextLocation
170 //ViewerRoot.removeAllAtPosition
171 //ViewerRoot.manageRootHeaders
172 //ViewerRoot.toggleAllAtPositionAutoRefresh
173 //ViewerRoot.handleRootPositionSelect
174 //ViewerRoot.clearAll
175 //ViewerRoot.handleWindowResize
176 //ViewerRoot.resizeRootObjects
177 //ViewerRoot.refreshTransparency
178 //ViewerRoot.checkStreamerInfoLoaded
179 //ViewerRoot.getDirectoryContents
180 //ViewerRoot.getDirContentsHandler
181 //ViewerRoot.rootReq
182 //ViewerRoot.rootConfigReq
183 //ViewerRoot.getRootConfigHandler
184 //ViewerRoot.iterativeConfigLoader
185 //ViewerRoot.getRootDataHandler
186 //ViewerRoot.interpretObjectBuffer
187 
188 ViewerRoot.init = function() {
189  Debug.log("ViewerRoot.init");
190  //JSROOT.redraw('object_draw', histo, "colz");
191 
192 
193  ViewerRoot.rootElArr = [];
194  ViewerRoot.rootPosArr = [];
195  ViewerRoot.rootObjArr = [];
196  ViewerRoot.rootObjIndexArr = [];
197  ViewerRoot.rootObjNameArr = [];
198  ViewerRoot.rootObjTitleArr = [];
199  ViewerRoot.rootHeaderElArr = [];
200  ViewerRoot.rootIsTransparentArr = [];
201  ViewerRoot.rootIsAutoRefreshArr = [];
202 
203  ViewerRoot.numPositionsTiled = 0;
204  ViewerRoot.rootTargetIndex = -1;
205 
206  obj_list = new Array();
207  ViewerRoot.objIndex = 0;
208  last_index = 0;
209  function_list = new Array();
210  func_list = new Array();
211  frame_id = 0;
212  random_id = 0;
213 
214  //create and add report container
215  ViewerRoot.rootContainer = document.createElement('div');
216  ViewerRoot.rootContainer.setAttribute("id","reportContainer");
217  ViewerRoot.rootContainer.onmouseup = function(){
218  Debug.log("Deselect all root containers");
219  ViewerRoot.rootTargetIndex = -1;
220  ViewerRoot.resizeRootObjects();
221  };
222  ViewerRoot.omni.appendChild(ViewerRoot.rootContainer);
223 
224  ViewerRoot.hud = new ViewerRoot.createHud();
225  window.onresize = ViewerRoot.handleWindowResize;
226  ViewerRoot.handleWindowResize();
227 
228  ViewerRoot.autoRefreshTimer = window.setInterval(ViewerRoot.autoRefreshTick,
229  ViewerRoot.autoRefreshPeriod);
230 
231  document.getElementById("loaderStatus").innerHTML = "Root Viewer Loaded.<br>Use drop-down to make selections.";
232  ViewerRoot.getDirectoryContents("/");
233 }
234 
235 ViewerRoot.autoRefreshMatchArr = []; //use array to match request returns to index
236 
237 // ViewerRoot.autoRefreshTick ~~
238 // handle autorefreshes
239 // Strategy:
240 // For each root object that is in refresh mode, push index,path to an array
241 // and send req. When req returns match path to array and remove entry.
242 // When array is empty auto refresh complete.
243 ViewerRoot.autoRefreshTick = function() {
244 
245  //Debug.log("ViewerRoot autoRefreshTick pause=" + ViewerRoot.pauseRefresh);
246  if(ViewerRoot.pauseRefresh) return;
247 
248  if(ViewerRoot.autoRefreshMatchArr.length) //not done yet with previous refresh!
249  {
250  Debug.log("ViewerRoot autoRefreshTick not done yet! Refresh period too short.");
251  return;
252  }
253 
254  ViewerRoot.autoRefreshMatchArr = []; //insert [<index>, <path>] tuples
255  for(var j=0;j<ViewerRoot.rootPosArr.length;++j)
256  if(ViewerRoot.rootIsAutoRefreshArr[j])
257  {
258  //Debug.log("ViewerRoot autoRefreshTick " + j + " " + ViewerRoot.rootObjNameArr[j]);
259  ViewerRoot.autoRefreshMatchArr.push([j, ViewerRoot.rootObjNameArr[j]]);
260  ViewerRoot.rootReq(ViewerRoot.rootObjNameArr[j]);
261  }
262 }
263 
264 // ViewerRoot.() ~~
265 // Prepares next div location for root js library drawing
266 // based on RADIO: Tile, Replace, Superimpose. The div id
267 // will be "histogram"+ViewerRoot.objIndex.. this is the div
268 // the root js library will draw to.
269  ViewerRoot.prepareNextLocation = function(objName, objTitle) {
270  Debug.log("ViewerRoot prepareNextLocation for ViewerRoot.objIndex " + "mode " + ViewerRoot.nextObjectMode +
271  ": " + ViewerRoot.objIndex + ": " + objName);
272 
273  //fix target just in case foul play occured
274  if(ViewerRoot.rootTargetIndex > ViewerRoot.numPositionsTiled) ViewerRoot.rootTargetIndex = -1;
275 
276  //create and add new div
277  var ri = ViewerRoot.rootElArr.length;
278  ViewerRoot.rootElArr.push(document.createElement('div')); //make container
279  ViewerRoot.rootElArr[ri].setAttribute("class","rootObjectContainer"); //set new report target
280 
281  var tmpdiv = document.createElement('div'); //make target div
282  tmpdiv.setAttribute("id","histogram"+ViewerRoot.objIndex); //set new target for root object
283  tmpdiv.setAttribute("class","rootObjectContainerTarget");
284  ViewerRoot.rootElArr[ri].appendChild(tmpdiv);
285 
286  //add report to report container
287  ViewerRoot.rootContainer.appendChild(ViewerRoot.rootElArr[ri]);
288 
289  var drawTransparently = false;
290  if(!ViewerRoot.numPositionsTiled || ViewerRoot.nextObjectMode == ViewerRoot.TILE_MODE)
291  {
292  //next tile position (or first tile)
293  ViewerRoot.rootPosArr.push(ViewerRoot.numPositionsTiled++);
294  }
295  else if(ViewerRoot.nextObjectMode == ViewerRoot.REPLACE_MODE)
296  {
297  //replace tile(s) at position ViewerRoot.rootTargetIndex, if -1 then replace last tile(s)
298  var repi = ViewerRoot.rootTargetIndex == -1? ViewerRoot.numPositionsTiled-1:ViewerRoot.rootTargetIndex;
299  ViewerRoot.removeAllAtPosition(repi); //remove all tiles that match repi
300 
301  ViewerRoot.rootPosArr.push(repi); //assign new report to position
302  }
303  else if(ViewerRoot.nextObjectMode == ViewerRoot.SUPERIMPOSE_MODE)
304  {
305  //add tile at position ViewerRoot.rootTargetIndex, if -1 then at last tile(s)
306  var supi = ViewerRoot.rootTargetIndex == -1? ViewerRoot.numPositionsTiled-1:ViewerRoot.rootTargetIndex;
307 
308  ViewerRoot.rootPosArr.push(supi); //assign new report to position
309  drawTransparently = true;
310  }
311 
312  ViewerRoot.rootIsTransparentArr.push(drawTransparently); //keep for transparent drawing
313  ViewerRoot.rootIsAutoRefreshArr.push(ViewerRoot.autoRefreshDefault);
314  ViewerRoot.rootObjNameArr.push(objName); //assign new report to position
315  ViewerRoot.rootObjTitleArr.push(objTitle);
316 
317  ViewerRoot.manageRootHeaders(); //manage headers for all positions
318  ViewerRoot.resizeRootObjects(true); //resize all root objects as a result of new element
319 }
320 
321 // ViewerRoot.removeAllAtPosition ~~
322 // Remove all histogram div elements and associated root object data structures
323 // for the given position i.
324 // If isClosingPosition then redraw after and update tiled positions and renumber all above
325 // position i.
326 ViewerRoot.removeAllAtPosition = function(posi, isClosingPosition) {
327  Debug.log("ViewerRoot removeAllAtPosition " + posi);
328 
329  for(var i=0;i<ViewerRoot.rootPosArr.length;++i)
330  if(ViewerRoot.rootPosArr[i] == posi) //remove element
331  {
332  ViewerRoot.rootElArr[i].parentNode.removeChild(ViewerRoot.rootElArr[i]);
333  ViewerRoot.rootElArr.splice(i,1);
334  ViewerRoot.rootPosArr.splice(i,1);
335  delete ViewerRoot.rootObjArr[i]; ViewerRoot.rootObjArr[i] = null;
336  ViewerRoot.rootObjArr.splice(i,1);
337  ViewerRoot.rootObjIndexArr.splice(i,1);
338  ViewerRoot.rootObjNameArr.splice(i,1);
339  ViewerRoot.rootObjTitleArr.splice(i,1);
340  ViewerRoot.rootIsTransparentArr.splice(i,1);
341  ViewerRoot.rootIsAutoRefreshArr.splice(i,1);
342 
343  --i; //rewind
344  }
345  else if(isClosingPosition && ViewerRoot.rootPosArr[i] > posi) //renumber position
346  --ViewerRoot.rootPosArr[i];
347 
348  if(isClosingPosition)
349  {
350  --ViewerRoot.numPositionsTiled;
351  ViewerRoot.manageRootHeaders();
352  if(ViewerRoot.rootTargetIndex > posi) --ViewerRoot.rootTargetIndex;
353  else if(ViewerRoot.rootTargetIndex >= ViewerRoot.numPositionsTiled) ViewerRoot.rootTargetIndex = -1;
354  ViewerRoot.resizeRootObjects(true); //resize all root objects as a result of new element
355  }
356 }
357 
358 // ViewerRoot.manageRootHeaders ~~
359 // handle adding/removing/drawing of root object headers
360 ViewerRoot.manageRootHeaders = function() {
361  Debug.log("ViewerRoot manageRootHeaders");
362 
363  var tmpdiv;
364  while(ViewerRoot.numPositionsTiled > ViewerRoot.rootHeaderElArr.length) //add header elements
365  {
366  tmpdiv = document.createElement('div'); //make target div
367  tmpdiv.setAttribute("id","rootContainerHeader-"+ViewerRoot.rootHeaderElArr.length);
368  tmpdiv.setAttribute("class","rootContainerHeader");
369  tmpdiv.onmouseup = ViewerRoot.handleRootPositionSelect;
370  ViewerRoot.rootContainer.appendChild(tmpdiv);
371  ViewerRoot.rootHeaderElArr.push(tmpdiv);
372  }
373 
374  while(ViewerRoot.numPositionsTiled < ViewerRoot.rootHeaderElArr.length) //remove header elements
375  {
376  tmpdiv = ViewerRoot.rootHeaderElArr[ViewerRoot.rootHeaderElArr.length-1];
377  tmpdiv.parentNode.removeChild(tmpdiv);
378  ViewerRoot.rootHeaderElArr.splice(ViewerRoot.rootHeaderElArr.length-1,1);
379  }
380 
381  //give name to headers by position
382  var found;
383  var name, fullPath;
384  var str;
385  var isAtLeastOneRefreshing;
386  for(var i=0;i<ViewerRoot.rootHeaderElArr.length;++i)
387  {
388  found = 0;
389  isAtLeastOneRefreshing = false;
390  for(var j=0;j<ViewerRoot.rootPosArr.length;++j)
391  if(ViewerRoot.rootPosArr[j] == i) { ++found; fullPath = ViewerRoot.rootObjNameArr[j];
392  //name = (fullPath.length > 20)?("..." + fullPath.substr(fullPath.length-18)):fullPath;
393  name=ViewerRoot.rootObjTitleArr[j];
394  if(ViewerRoot.rootIsAutoRefreshArr[j]) isAtLeastOneRefreshing = true; //this root object is set to autorefresh
395  }
396 
397  str = "";
398 
399  //add title
400  str += "<div title='" + fullPath + "' class='rootContainerHeader-name'>" + (found == 1?name:"Multiple Files...") + "</div>";
401 
402  //add close button
403  str += "<a title='Close' href='Javascript:ViewerRoot.removeAllAtPosition("+i+",true);' onmouseup='event.cancelBubble=true;' " +
404  "class='rootContainerHeader-closeBtn'>X</a>";
405 
406  //add auto refresh icon
407  //if at least one root object is refreshing show icon as on
408 
409  //Below is original
410  str += "<a title='Close' href='Javascript:ViewerRoot.toggleAllAtPositionAutoRefresh(" + i +
411  ");' onmouseup='event.cancelBubble=true;' " +
412  "class='rootContainerHeader-refreshBtn'><img id='rootContainerHeaderRefreshImg" + i +
413  "'src='/WebPath/images/iconImages/icon-rootAutoRefresh" + (isAtLeastOneRefreshing?"On":"Off") + ".png'></a>";
414 
415 
416  //Making the refresh button do the same thing as respective histograph name
417 // str += "<a title='Refresh' href='Javascript:ViewerRoot.rootReq(\"" + fullPath +
418 // "\");' onmouseup='event.cancelBubble=true;' " +
419 // "class='rootContainerHeader-refreshBtn'><img id='rootContainerHeaderRefreshImg" + i +
420 // "'src='/WebPath/images/iconImages/icon-rootAutoRefresh" + (isAtLeastOneRefreshing?"On":"Off") + ".png'></a>";
421 //
422  ViewerRoot.rootHeaderElArr[i].innerHTML = str;
423  }
424 }
425 
426 // ViewerRoot.toggleAllAtPositionAutoRefresh ~~
427 // toggle auto refresh for position i
428 // Superimposed position is a special case
429 // if any of superimposed are true, then all should go false
430 // else all go true
431 ViewerRoot.toggleAllAtPositionAutoRefresh = function(i)
432 {
433  Debug.log("ViewerRoot toggleAllAtPositionAutoRefresh " + i);
434  var found = 0;
435  var v = true, lastv;
436  var doover = false;
437  do
438  {
439  for(var j=0;j<ViewerRoot.rootPosArr.length;++j)
440  if(ViewerRoot.rootPosArr[j] == i)
441  {
442  if(!doover && ViewerRoot.rootIsAutoRefreshArr[j]) v = false;
443  ViewerRoot.rootIsAutoRefreshArr[j] = v; //---------------------------------------->This is all this function does!
444 
445  Debug.log("ViewerRoot toggleAllAtPositionAutoRefresh rootObj " + j + " to " + v);
446 
447  var tmp = document.getElementById("rootContainerHeaderRefreshImg" + i );
448  tmp.src = "/WebPath/images/iconImages/icon-rootAutoRefresh" + (v?"On":"Off") + ".png";
449  if(lastv != v ){++found; lastv = v;}
450  }
451  if(!doover && found>1) doover = true;
452  else doover = false;
453  } while(doover) //may need to do it over again, because values of superimposed root objects could be wrong
454 
455 }
456 
457 // ViewerRoot.handleRootPositionSelect ~~
458 ViewerRoot.handleRootPositionSelect = function(event) {
459  event.cancelBubble = true;
460  var i = parseInt(this.id.substr(this.id.indexOf("-")+1))
461  Debug.log("ViewerRoot handleRootPositionSelect " + i);
462  ViewerRoot.rootTargetIndex = i;
463  ViewerRoot.resizeRootObjects();
464 }
465 
466 // ViewerRoot.clearAll ~~
467 // remove all root objects
468 ViewerRoot.clearAll = function() {
469  Debug.log("ViewerRoot clearAll");
470 
471  ViewerRoot.rootTargetIndex = -1;
472  //ViewerRoot.numPositionsTiled will be 0 at end
473  for(ViewerRoot.numPositionsTiled; ViewerRoot.numPositionsTiled>0; --ViewerRoot.numPositionsTiled)
474  ViewerRoot.removeAllAtPosition(ViewerRoot.numPositionsTiled-1);
475  ViewerRoot.manageRootHeaders();
476  ViewerRoot.resizeRootObjects();
477 }
478 
479 // ViewerRoot.handleWindowResize ~~
480 ViewerRoot.handleWindowResize = function() {
481 
482  var w = ViewerRoot.w = window.innerWidth < ViewerRoot.DISPLAY_MIN_WIDTH? ViewerRoot.DISPLAY_MIN_WIDTH:window.innerWidth;
483  var h = ViewerRoot.h = window.innerHeight < ViewerRoot.DISPLAY_MIN_HEIGHT? ViewerRoot.DISPLAY_MIN_HEIGHT:window.innerHeight;
484 
485  if(!ViewerRoot.hudAutoHide) //force w smaller
486  ViewerRoot.w = w -= ViewerRoot.HUD_WIDTH + ViewerRoot.HUD_MARGIN_RIGHT + (5*2); //5 is padding of mouseover region in css
487 
488  Debug.log("ViewerRoot handleWindowResize " + w + "-" + h);
489 
490  ViewerRoot.omni.style.width = w + "px";
491  ViewerRoot.omni.style.height = h + "px";
492 
493  ViewerRoot.hud.handleWindowResize();
494  ViewerRoot.resizeRootObjects(true);
495 }
496 
497 // ViewerRoot.resizeRootObjects ~~
498 // Resize all root objects based on positions and tile arrangement
499 // if isForNewObject = true, then redraw all reports except last(new) report
500 // OLD: do not need to redraw for normal window resize, because obj's handler handles
501 // NEW: now on window resize the object is not redrawn.. the <svg class=root_canvas> size
502 // does not get updated.. So just redraw for normal window resize case.
503 ViewerRoot.resizeRootObjects = function(needToRedraw) {
504 
505  ViewerRoot.rootContainer.style.width = ViewerRoot.w + "px";
506  ViewerRoot.rootContainer.style.height = ViewerRoot.h + "px";
507 
508  if(ViewerRoot.numPositionsTiled < 1)
509  { //if no rootObjects, invisible container
510  ViewerRoot.rootContainer.style.backgroundColor = "rgba(0,0,0,0)";
511  return;
512  }
513  ViewerRoot.rootContainer.style.backgroundColor = "white";
514 
515 
516  var w = ViewerRoot.w;
517  var h = ViewerRoot.h - ViewerRoot.ROOT_CONTAINER_OFFY;
518 
519  var aspect = 3/4; //3/4, 9/16 , 1
520  var r = Math.round(Math.sqrt(h*ViewerRoot.numPositionsTiled/aspect/w)); //Math.ceil(Math.sqrt(ViewerRoot.numPositionsTiled));
521  if(r<1) r = 1;
522  var c = Math.ceil(ViewerRoot.numPositionsTiled/r);
523 
524  Debug.log("ViewerRoot resizeRootObjects " + r + "-" + c + " for " + ViewerRoot.numPositionsTiled);
525 
526  //calc individual position size
527  w = Math.floor(w/c);
528  h = Math.floor(h/r);
529 
530  Debug.log("ViewerRoot resizeRootObjects size " + w + "-" + h );
531 
532  //re-calc root object width based on aspect
533  var rootAspect = 3/4;
534  var rootw = h/w < rootAspect?h/rootAspect:w;
535 
536  //position all reports properly
537  for(var i=0;i<ViewerRoot.rootElArr.length;++i)
538  {
539  ViewerRoot.rootElArr[i].style.width = rootw + "px";
540  ViewerRoot.rootElArr[i].style.height = (h - ViewerRoot.ROOT_HEADER_HEIGHT) + "px";
541  ViewerRoot.rootElArr[i].style.left = w*(ViewerRoot.rootPosArr[i]%c) + (w-rootw)/2 + "px";
542  ViewerRoot.rootElArr[i].style.top = ViewerRoot.ROOT_CONTAINER_OFFY + ViewerRoot.ROOT_HEADER_HEIGHT +
543  h*Math.floor(ViewerRoot.rootPosArr[i]/c) + "px";
544 
545  // Debug.log("ViewerRoot resizeRootObjects x y " + i + " at pos " + ViewerRoot.rootPosArr[i] +
546  // ":" + ViewerRoot.rootElArr[i].style.left + "-" + ViewerRoot.rootElArr[i].style.top );
547 
548  if(needToRedraw && ViewerRoot.rootObjArr[i]) //redraw for new size, when new added rootobj not defined at this point
549  {
550  //Debug.log("ViewerRoot resizeRootObjects redraw " + i + "-" + ViewerRoot.rootObjIndexArr[i] );
551  //JSROOTPainter.drawObject(ViewerRoot.rootObjArr[i], ViewerRoot.rootObjIndexArr[i]);
552  JSROOT.redraw('histogram'+
553  ViewerRoot.rootObjIndexArr[i],
554  ViewerRoot.rootObjArr[i], "colz"); //last arg, root draw option
555  ViewerRoot.refreshTransparency(i);
556  }
557  }
558 
559  //position headers
560  for(var i=0;i<ViewerRoot.rootHeaderElArr.length;++i)
561  {
562  ViewerRoot.rootHeaderElArr[i].style.width = w-2 + "px";
563  ViewerRoot.rootHeaderElArr[i].style.height = ViewerRoot.ROOT_HEADER_HEIGHT + "px";
564  ViewerRoot.rootHeaderElArr[i].style.left = w*(i%c) + "px";
565  ViewerRoot.rootHeaderElArr[i].style.top = ViewerRoot.ROOT_CONTAINER_OFFY + h*Math.floor(i/c) + "px";
566 
567  ViewerRoot.rootHeaderElArr[i].style.borderColor =
568  ViewerRoot.rootTargetIndex==i?'rgb(68,156,44)':'black';
569  ViewerRoot.rootHeaderElArr[i].style.backgroundColor =
570  ViewerRoot.rootTargetIndex==i?'rgb(178,222,166)':'rgba(0,0,0,0)';
571  }
572 }
573 
574 // ViewerRoot.refreshTransparency ~~
575 // refresh the transparency state of histogram i and svg components
576 ViewerRoot.refreshTransparency = function(i) {
577  //if need be, make transparent
578  if(ViewerRoot.rootIsTransparentArr[i])
579  {
580  //Debug.log("superimpose draw " + i);
581  //histogram div bgColor
582  ViewerRoot.rootElArr[i].children[0].style.backgroundColor = "rgba(0,0,0,0)";
583  //svg bgColor
584  var svg = ViewerRoot.rootElArr[i].children[0].getElementsByTagName('svg')[0];
585  svg.style.backgroundColor = "rgba(0,0,0,0)";
586  //rect fill
587  if(svg.getElementsByTagName('rect')[0])
588  svg.getElementsByTagName('rect')[0].style.fill = "rgba(0,0,0,0)";
589 
590  //structure:
591  //<div id='histogram#'><svg><g>
592  //<rect x="0" y="0" width="461.48" height="281.70663849600004" fill="rgba(0,0,0,0)" style="stroke: #000000; stroke-width: 1px;"></rect>
593  //<svg>..root drawing..</svg>
594  //</g>
595  //</svg>
596  }
597 }
598 
599 // ViewerRoot.checkStreamerInfoLoaded ~~
600 // periodically check to usee if the streamer info, giving information on root types has completely loaded
601 // this is a critical step before attempting to draw any root objects
602 ViewerRoot.checkStreamerInfoLoaded = function() {
603  if(ViewerRoot.sFile &&
604  ViewerRoot.sFile.fStreamerInfo &&
605  gFile.fStreamerInfo.fClassMap &&
606  gFile.fStreamerInfo.fClassMap.length > 0) //done
607  {
608  document.getElementById("loaderStatus").innerHTML = "Root Viewer Loaded.<br>Use drop-down to make selections.";
609  ViewerRoot.getDirectoryContents("/");
610  }
611  else //not done, wait longer
612  window.setTimeout(ViewerRoot.checkStreamerInfoLoaded,ViewerRoot.LOAD_STREAMER_INFO_CHECK_PERIOD);
613 }
614 
615 // ViewerRoot.getDirectoryContents ~~
616 // request directory contents from server for path
617 ViewerRoot.getDirectoryContents = function(path) {
618 
619  Debug.log("ViewerRoot getDirectoryContents " + path);
620 
621  if(path.indexOf(".root/") >=0)
622  DesktopContent.XMLHttpRequest("Request?RequestType=getRoot", "RootPath="+path, ViewerRoot.getDirContentsHandler);
623  else
624  DesktopContent.XMLHttpRequest("Request?RequestType=getDirectoryContents", "Path="+path, ViewerRoot.getDirContentsHandler);
625 }
626 
627 // ViewerRoot.getDirContentsHandler ~~
628 ViewerRoot.getDirContentsHandler = function(req) {
629  Debug.log("ViewerRoot getDirContentsHandler " + req.responseText);
630 
631  var permissions = DesktopContent.getXMLValue(req,'permissions');
632  if(!permissions)
633  Debug.log("ViewerRoot getDirContentsHandler permissions missing");
634  else if(ViewerRoot.userPermissions != permissions)
635  {
636  Debug.log("ViewerRoot getDirContentsHandler user permissions = " + permissions);
637  ViewerRoot.userPermissions = permissions;
638  ViewerRoot.hud.handleWindowResize();
639  }
640 
641  ViewerRoot.hud.handleDirContents(req);
642 }
643 
644 // ViewerRoot.rootReq ~~
645 // if refreshIndex, then request is meant to replace root object at index
646 ViewerRoot.rootReq = function(rootPath) {
647 
648  Debug.log("ViewerRoot.rootReq " + rootPath );
649  DesktopContent.XMLHttpRequest("Request?RequestType=getRoot", "RootPath="+rootPath,
650  //ViewerRoot.tmpRootDataHandler);
651  ViewerRoot.getRootDataHandler);
652 }
653 
654 //ViewerRoot.rootConfigReq ~~
655 ViewerRoot.rootConfigReq = function(rootConfigPath) {
656  //Debug.log("ViewerRoot.rootReq");
657  DesktopContent.XMLHttpRequest("Request?RequestType=getRootConfig", "RootConfigPath="+rootConfigPath,
658  ViewerRoot.getRootConfigHandler);
659 }
660 
661 //ViewerRoot.getRootConfigHandler ~~
662 // receives saved configuration and rebuilds the view based on the configuration
663 ViewerRoot.getRootConfigHandler = function(req) {
664  Debug.log("ViewerRoot getRootConfigHandler " + req.responseText );
665 
666  var status = DesktopContent.getXMLValue(req,"status");
667  if(status != "1")
668  { alert("Loading Root Pre-Made Configuration Failed: " + status); return }
669 
670  ViewerRoot.iterNumPositionsTiled = DesktopContent.getXMLValue(req,"numPositionsTiled");
671  ViewerRoot.iterRunWildcard = DesktopContent.getXMLValue(req,"runNumWildcard"); //TODO replace obj names with current run number!
672 
673  //copy NodeList to just normal arrays
674 
675  var tmp = req.responseXML.getElementsByTagName("rootObjName");
676  ViewerRoot.iterRootObjNameArr = [];
677  for(var i=0;i<tmp.length;++i) ViewerRoot.iterRootObjNameArr[i] = tmp[i].getAttribute("value");
678 
679  tmp = req.responseXML.getElementsByTagName("rootPos");
680  ViewerRoot.iterRootPosArr = [];
681  for(var i=0;i<tmp.length;++i) ViewerRoot.iterRootPosArr[i] = tmp[i].getAttribute("value") | 0; //parse as int
682 
683  tmp = req.responseXML.getElementsByTagName("rootIsTransparent");
684  ViewerRoot.iterRootIsTransparentArr = [];
685  for(var i=0;i<tmp.length;++i) ViewerRoot.iterRootIsTransparentArr[i] = tmp[i].getAttribute("value") | 0; //parse as int
686 
687  tmp = req.responseXML.getElementsByTagName("rootIsAutoRefresh");
688  ViewerRoot.iterRootIsAutoRefreshArr = [];
689  for(var i=0;i<tmp.length;++i) ViewerRoot.iterRootIsAutoRefreshArr[i] = tmp[i].getAttribute("value") | 0; //parse as int
690 
691  ViewerRoot.clearAll();
692 
693  ViewerRoot.iterLoading = true;
694  ViewerRoot.iterNumberRemaining = ViewerRoot.iterRootObjNameArr.length;
695  ViewerRoot.iterSaveNextObjectMode = ViewerRoot.nextObjectMode;
696  ViewerRoot.iterSaveAutoRefreshDefault = ViewerRoot.autoRefreshDefault;
697 
698  ViewerRoot.iterativeConfigLoader();
699 }
700 
701 //ViewerRoot.iterativeConfigLoader ~~
702 // goes through every iterRootObj and loads sequentially to display
703 ViewerRoot.iterativeConfigLoader = function() {
704  //Debug.log("ViewerRoot iterativeConfigLoader " + ViewerRoot.iterNumberRemaining);
705  if(!ViewerRoot.iterNumberRemaining) //done
706  {
707  ViewerRoot.autoRefreshDefault = ViewerRoot.iterSaveAutoRefreshDefault;
708  ViewerRoot.nextObjectMode = ViewerRoot.iterSaveNextObjectMode;
709  ViewerRoot.iterLoading = false;
710  return;
711  }
712 
713  --ViewerRoot.iterNumberRemaining;
714 
715  //next is always the lowest position left
716  var min = -1;
717  for(var i=0;i<ViewerRoot.iterRootPosArr.length;++i)
718  if(min == -1 || ViewerRoot.iterRootPosArr[i] < ViewerRoot.iterRootPosArr[min]) min = i;
719 
720  ViewerRoot.nextObjectMode = ViewerRoot.iterRootIsTransparentArr[min]?ViewerRoot.SUPERIMPOSE_MODE:ViewerRoot.TILE_MODE;
721  ViewerRoot.autoRefreshDefault = ViewerRoot.iterRootIsAutoRefreshArr[min];
722 
723  ViewerRoot.rootReq(ViewerRoot.iterRootObjNameArr[min]);
724 
725  //remove from iter array
726  ViewerRoot.iterRootObjNameArr.splice(min,1);
727  ViewerRoot.iterRootPosArr.splice(min,1);
728  ViewerRoot.iterRootIsTransparentArr.splice(min,1);
729  ViewerRoot.iterRootIsAutoRefreshArr.splice(min,1);
730 
731 }
732 
733 
734 // ViewerRoot.getRootDataHandler ~~
735 // receives streamed root object from server and prepares it for js structures
736 ViewerRoot.getRootDataHandler = function(req) {
737 
738  //Debug.log("ViewerRoot getRootDataHandler " + req.responseText );
739 
740  var rootType = DesktopContent.getXMLValue(req,"rootType");
741  var rootStr = DesktopContent.getXMLValue(req,"rootData");
742  var rootName = DesktopContent.getXMLValue(req,"path");//
743  //"my" + rootType + ViewerRoot.objIndex;// DesktopContent.getXMLValue(req,"path");// + ViewerRoot.objIndex;
744  //if(rootName.length > 20) rootName = "..." + rootName.substr(rootName.length-18);
745 
746  var rootJSON = DesktopContent.getXMLValue(req,"rootJSON");
747 
748  //Debug.log("ViewerRoot tmpRootDataHandler JSON \n\n" + rootJSON );
749 
750  var ojbect = JSROOT.parse(rootJSON);
751  var rootTitle = ojbect.fTitle;
752 
753  if(!ojbect || !rootType || !rootName)
754  {
755  Debug.log("Pausing auto-refresh! \n\nPlease resolve the erros before resuming refreshes.", Debug.HIGH_PRIORITY);
756 
757  var chk = document.getElementById("hudCheckbox" + 2); //pause refresh checkbox
758  chk.checked = true;
759  ViewerRoot.pauseRefresh = true;
760 
761  Debug.log("Error reading Root object from server - Name: " + rootName, Debug.HIGH_PRIORITY);
762  ViewerRoot.autoRefreshMatchArr = []; //clearing the array so that future refreshes work
763  return;
764  }
765 
766 
767  var refreshIndex = -1; //default to -1 if no auto refresh needed
768  if(ViewerRoot.autoRefreshMatchArr.length) //check if request matches auto refresh entry
769  {
770  for(var i=0;i<ViewerRoot.autoRefreshMatchArr.length;++i)
771  {
772  if(rootName == ViewerRoot.autoRefreshMatchArr[i][1])
773  {
774  refreshIndex = ViewerRoot.autoRefreshMatchArr[i][0];
775 
776  //remove from auto refresh array
777  ViewerRoot.autoRefreshMatchArr[i] = 0;
778  ViewerRoot.autoRefreshMatchArr.splice(i,1);
779 
780  //if name in js structures has changed,
781  // assume it is users fault and throw out this refreshed object
782  if(refreshIndex >= ViewerRoot.rootObjNameArr.length ||
783  ViewerRoot.rootObjNameArr[refreshIndex] != rootName)
784  {
785  Debug.log("ViewerRoot getRootDataHandler weird unmatch!?#$@%");
786  return; //throw out object, since incomplete match
787  }
788  break;
789  }
790  }
791  //if not found, assume it is a new object
792  }
793 
794  console.log("refreshIndex=" + refreshIndex + " ViewerRoot.rootTargetIndex=" + ViewerRoot.rootTargetIndex);
795 
796  if(refreshIndex < 0) ViewerRoot.prepareNextLocation(rootName, rootTitle);
797  else
798  {
799  //refreshIndex is the location to target
800  //prepare a new location as though it is replace with auto-refresh on
801  //
802  // e.g.
803  // globalset = replace/on
804  // ViewerRoot.prepareNextLocation(rootName);
805  // globalset = gui settings
806 
807  // tmpHLI = HIGHLIGHT_INDEX;
808  // HIGHLIGHT_INDEX = refreshIndex
809  //refreshIndex = -1;
810  // do it
811  // HIGHLIGHT_INDEX = tmpHLI;
812 
813 
814 
815 // var tmpRootTargetIndex = ViewerRoot.rootTargetIndex;
816 // ViewerRoot.rootTargetIndex = refreshIndex;
817 //
818 // var tmpRefreshIndex = refreshIndex;
819 // refreshIndex = -1;
820 //
821 // var tmpNextObjectMode = ViewerRoot.nextObjectMode;
822 // var tmpAutoRefreshDefault = ViewerRoot.autoRefreshDefault;
823 //
824 // ViewerRoot.nextObjectMode = ViewerRoot.REPLACE_MODE;
825 // ViewerRoot.autoRefreshDefault = true;
826 //
827 //
828 // ViewerRoot.prepareNextLocation(rootName);
829 //
830 //
831 // ViewerRoot.rootTargetIndex = tmpRootTargetIndex;
832 // ViewerRoot.nextObjectMode = tmpNextObjectMode;
833 // ViewerRoot.autoRefreshDefault = tmpAutoRefreshDefault;
834  }
835 
836  ViewerRoot.interpretObjectJSON(ojbect,rootType,rootName,refreshIndex);
837  if(ViewerRoot.iterLoading) ViewerRoot.iterativeConfigLoader();
838 }
839 
840 
841 // ViewerRoot.interpretObjectJSON ~~
842 // interpret and draw
843 ViewerRoot.interpretObjectJSON = function(object,rootType,objName,refreshIndex) {
844 
845  if(refreshIndex == undefined) refreshIndex = -1;
846 
847 
848  if(ViewerRoot.hardRefresh) //"Hard" refresh, reloads axes for example
849  {
850  if(refreshIndex < 0)
851  {
852  ViewerRoot.rootObjArr.push(object);
853  ViewerRoot.rootObjIndexArr.push(ViewerRoot.objIndex);
854  }
855  else //use refresh index
856  {
857  delete ViewerRoot.rootObjArr[refreshIndex]; ViewerRoot.rootObjArr[refreshIndex] = null;
858  ViewerRoot.rootObjArr[refreshIndex] = object;
859  ViewerRoot.rootObjTitleArr[refreshIndex] = object.fTitle;
860  ViewerRoot.rootObjIndexArr[refreshIndex] = ViewerRoot.objIndex;
861 
862 
863  ViewerRoot.rootElArr[refreshIndex].innerHTML = ""; //cleare rootObjectContainer
864  var tmpdiv = document.createElement('div'); //make target div
865  tmpdiv.setAttribute("id","histogram"+ViewerRoot.objIndex); //set new target for root object
866  tmpdiv.setAttribute("class","rootObjectContainerTarget");
867  ViewerRoot.rootElArr[refreshIndex].appendChild(tmpdiv);
868  }
869 
870  //draw based on refresh index
871  JSROOT.redraw('histogram'+
872  (ViewerRoot.objIndex),
873  object, "colz"); //last arg, root draw option
874 
875  ViewerRoot.objIndex++;
876  }
877  else //"Soft" refresh, doesn't reload axes for example
878  {
879  //draw based on refresh index
880  JSROOT.draw('histogram'+
881  (refreshIndex<0?ViewerRoot.objIndex:
882  ViewerRoot.rootObjIndexArr[refreshIndex]),
883  object, "colz"); //last arg, root draw option
884 
885  if(refreshIndex < 0)
886  {
887  ViewerRoot.rootObjArr.push(object);
888  ViewerRoot.rootObjIndexArr.push(ViewerRoot.objIndex);
889  ViewerRoot.objIndex++;
890  }
891  else //use refresh index
892  {
893  delete ViewerRoot.rootObjArr[refreshIndex]; ViewerRoot.rootObjArr[refreshIndex] = null;
894  ViewerRoot.rootObjArr[refreshIndex] = object;
895  ViewerRoot.rootObjTitleArr[refreshIndex] = object.fTitle;
896  }
897  }
898 
899  ViewerRoot.refreshTransparency(refreshIndex<0?(ViewerRoot.rootObjArr.length-1):refreshIndex);
900  ViewerRoot.manageRootHeaders(); //manage headers for all positions
901 
902 }
903 
904 
905 function loadScript(url, callback) {
906  // dynamic script loader using callback
907  // (as loading scripts may be asynchronous)
908  var script = document.createElement("script")
909  script.type = "text/javascript";
910  if (script.readyState) { // Internet Explorer specific
911  script.onreadystatechange = function() {
912  if (script.readyState == "loaded" ||
913  script.readyState == "complete") {
914  script.onreadystatechange = null;
915  callback();
916  }
917  };
918  } else { // Other browsers
919  script.onload = function(){
920  callback();
921  };
922  }
923  var rnd = Math.floor(Math.random()*80000);
924  script.src = url;//+ "?r=" + rnd;
925  document.getElementsByTagName("head")[0].appendChild(script);
926 };